[haiku-commits] r42749 - haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom

  • From: zharik@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 12 Sep 2011 21:42:53 +0200 (CEST)

Author: siarzhuk
Date: 2011-09-12 21:42:52 +0200 (Mon, 12 Sep 2011)
New Revision: 42749
Changeset: https://dev.haiku-os.org/changeset/42749

Modified:
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/Driver.cpp
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/Driver.h
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/Settings.cpp
   haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/Settings.h
   
haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/usb_davicom.settings
Log:
Bringing usb_davicom to life: part 3 of 3:

* Lot of code refactoring and code style fixes;
* Promiscuous mode implemented;
* Multicasting support implemented;
* Binary-search devices table lookup procedure used
  instead of switch one.



Modified: 
haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp
===================================================================
--- 
haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp    
    2011-09-12 19:35:28 UTC (rev 42748)
+++ 
haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp    
    2011-09-12 19:42:52 UTC (rev 42749)
@@ -1,302 +1,123 @@
 /*
  *     Davicom DM9601 USB 1.1 Ethernet Driver.
+ *     Copyright (c) 2008, 2011 Siarzhuk Zharski <imker@xxxxxx>
  *     Copyright (c) 2009 Adrien Destugues <pulkomandy@xxxxxxxxx>
- *     Copyright (c) 2008, 2011 Siarzhuk Zharski <imker@xxxxxx>
  *     Distributed under the terms of the MIT license.
  *
- *     Heavily based on code of the 
+ *     Heavily based on code of the
  *     Driver for USB Ethernet Control Model devices
  *     Copyright (C) 2008 Michael Lotz <mmlr@xxxxxxxx>
  *     Distributed under the terms of the MIT license.
- *
  */
 
 
 #include "DavicomDevice.h"
 
+#include <stdio.h>
+#include <net/if_media.h>
+
 #include "Driver.h"
 #include "Settings.h"
 
 
-// Vendor commands
-#define READ_REGISTER 0
-#define WRITE_REGISTER 1
-#define WRITE1_REGISTER 3
-#define READ_MEMORY 2
-#define WRITE_MEMORY 5
-#define WRITE1_MEMORY 7
+const int kFrameSize = 1522;
 
+enum VendorRequests {
+       ReqReadRegister                 = 0,
+       ReqWriteRegister                = 1,
+       ReqWriteRegisterByte    = 3,
+};
 
-// Registers
-#define NCR 0x00       // Network control
-#define NSR    0x01    // Network status
-#define RCR 0x05       // RX Control
-#define PAR 0x10       // 6 bits - Physical address (MAC)
-#define GPCR 0x1E      // General purpose control
-#define GPR 0x1F       // General purpose
 
-#define NCR_EXT_PHY            0x80    // External PHY
-#define NCR_FDX                        0x08    // Full duplex
-#define NCR_LBK                        0x06    // Loopback mode
+enum DM9601Registers {
+       RegNCR  = 0x00, // Network Control Register
+               NCRExtPHY       = 0x80, // Select External PHY
+               NCRFullDX       = 0x08, // Full duplex
+               NCRLoopback     = 0x06, // Internal PHY analog loopback
 
-#define NSR_SPEED              0x80    // 0 = 100MBps, 1 = 10MBps
-#define NSR_LINKST             0x40    // 1 = link up
-#define NSR_TXFULL             0x10    // TX FIFO full
-#define NSR_RXOV               0x08    // RX Overflow
+       RegNSR  = 0x01, // Network Status Register
+               NSRSpeed10      = 0x80, // 0 = 100MBps, 1 = 10MBps (internal 
PHY)
+               NSRLinkUp       = 0x40, // 1 = link up (internal PHY)
+               NSRTXFull       = 0x10, // TX FIFO full
+               NSRRXOver       = 0x08, // RX FIFO overflow
 
-#define RCR_DIS_LONG   0x20    // Discard long packet
-#define RCR_DIS_CRC            0x10    // Discard CRC error packet
-#define RCR_ALL                        0x08    // Pass all multicast
-#define RCR_PRMSC              0x02    // Promiscuous
-#define RCR_RXEN               0x01    // RX enable
+       RegRCR  = 0x05, // RX Control Register
+               RCRDiscardLong  = 0x20, // Discard long packet (over 1522 bytes)
+               RCRDiscardCRC   = 0x10, // Discard CRC error packet
+               RCRAllMulticast = 0x08, // Pass all multicast
+               RCRPromiscuous  = 0x02, // Promiscuous
+               RCRRXEnable             = 0x01, // RX enable
 
-#define GPCR_GEP_CNTL0 0x01    // Power Down function
+       RegEPCR = 0x0b, // EEPROM & PHY Control Register
+               EPCROpSelect    = 0x08, // EEPROM or PHY Operation Select
+               EPCRRegRead             = 0x04, // EEPROM or PHY Register Read 
Command
+               EPCRRegWrite    = 0x02, // EEPROM or PHY Register Write Command
 
-#define GPR_GEP_GEPIO0 0x01    // Power down
+       RegEPAR = 0x0c, // EEPROM & PHY Address Register
+               EPARIntPHY              = 0x40, // [7:6] force to 01 if 
Internal PHY is selected
+               EPARMask                = 0x1f, // mask [0:5]
 
-#define EPCR           0x0b    // EEPROM/PHY Control Register
-#define EPCR_EPOS      0x08    // EEPROM/PHY Operation Select
-#define EPCR_ERPRR     0x04    // EEPROM/PHY Register Read Command
-#define EPCR_ERPRW     0x02    // EEPROM/PHY Register Write Command
+       RegEPDRL = 0x0d, // EEPROM & PHY Low Byte Data Register
 
-#define EPAR           0x0c    // EEPROM/PHY Control Register
-#define EPAR_ADDR0     0x40    // EEPROM/PHY Address 
-#define EPAR_MASK      0x1f    // mask [0:5]
+       RegEPDRH = 0x0e, // EEPROM & PHY Low Byte Data Register
 
-#define EPDRL          0x0d    // EEPROM/PHY Data Register
-
-#define USBCR          0xf4    // USB Control Register
-#define EP3ACK         0x20    // ACK with 8-byte data on interrupt EP
-#define EP3NACK                0x10    // Supress ACK on interrupt EP
-
-//TODO: multicast support
-//TODO: set media state support
-
-
-status_t
-DavicomDevice::_ReadRegister(uint8 reg, size_t size, uint8* buffer)
-{
-       if (size > 255) return B_BAD_VALUE;
-       size_t actualLength;
-       status_t result = gUSBModule->send_request(fDevice,
-               USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
-               READ_REGISTER, 0, reg, size, buffer, &actualLength);
-       if (size != actualLength) {
-               TRACE_ALWAYS("Size mismatch reading register ! asked %d got %d",
-                       size, actualLength);
-       }
-       return result;
-}
-
-
-status_t
-DavicomDevice::_WriteRegister(uint8 reg, size_t size, uint8* buffer)
-{
-       if (size > 255) return B_BAD_VALUE;
-       size_t actualLength;
-       status_t result = gUSBModule->send_request(fDevice,
-               USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
-               WRITE_REGISTER, 0, reg, size, buffer, &actualLength);
-       return result;
-}
-
-
-status_t
-DavicomDevice::_Write1Register(uint8 reg, uint8 value)
-{
-       size_t actualLength;
-       status_t result = gUSBModule->send_request(fDevice,
-               USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
-               WRITE1_REGISTER, value, reg, 0, NULL, &actualLength);
-       return result;
-}
-
-
-status_t
-DavicomDevice::_ReadMII(uint8 reg, uint16* data)
-{
-       // select PHY and set PHY register address
-       status_t result = _Write1Register(EPAR, EPAR_ADDR0 | (reg & EPAR_MASK));
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, 
result);
-               return result;
-       }
+       RegPAR  = 0x10, // [0x10 - 0x15] Physical Address Register
        
-       // select PHY operation and initiate reading
-       result = _Write1Register(EPCR, EPCR_EPOS | EPCR_ERPRR);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to starting MII reading. Error:%#x\n", 
result);
-               return result;
-       }
+       RegMAR  = 0x16, // [0x16 - 0x1d] Multicast Address Register
 
-       // finalize writing
-       uint8 control = 0;
-       result = _ReadRegister(EPCR, 1, &control);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", 
result);
-               return result;
-       }
+       RegGPCR = 0x1E, // General Purpose Control Register
+               GPCRPowerDown   = 0x01, // [0:6] Define in/out direction of GPCR
+                                                               // GPIO0 - is 
output for Power Down function
 
-       result = _Write1Register(EPCR, control & ~EPCR_ERPRR);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", 
result);
-               return result;
-       }
+       RegGPR  = 0x1F, // General Purpose Register
+               GPRPowerDownInPHY = 0x01,       // Power down Internal PHY
 
-       // retrieve the result from data registers
-       uint8 values[2] = { 0 };
-       result = _ReadRegister(EPDRL, 2, values);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to retrieve data %#x. Error:%#x\n", data, 
result);
-               return result;
-       }
+       RegUSBC = 0xf4, // USB Control Register
+               USBCIntAck              = 0x20, // ACK with 8-bytes of data on 
interrupt EP
+               USBCIntNAck             = 0x10, // Supress ACK on interrupt EP
 
-       *data = values[0] | values[1] << 8;  
-       return result;
-}
+};
 
 
-status_t
-DavicomDevice::_WriteMII(uint8 reg, uint16 data)
-{
-       // select PHY and set PHY register address
-       status_t result = _Write1Register(EPAR, EPAR_ADDR0 | (reg & EPAR_MASK));
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, 
result);
-               return result;
-       }
+enum MIIRegisters {
+       RegBMCR = 0x00,
+               BMCRIsolate     = 0x0400,
+               BMCRReset       = 0x8000,
 
-       // put the value to data register
-       uint8 values[] = { data & 0xff, ( data >> 8 ) & 0xff };
-       result = _WriteRegister(EPDRL, sizeof(uint16), values);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to put data %#x. Error:%#x\n", data, 
result);
-               return result;
-       }
+       RegBMSR = 0x01,
+       RegPHYID1       = 0x02,
+       RegPHYID2       = 0x03,
+};
 
-       // select PHY operation and initiate writing
-       result = _Write1Register(EPCR, EPCR_EPOS | EPCR_ERPRW);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to starting MII wrintig. Error:%#x\n", 
result);
-               return result;
-       }
-
-       // finalize writing
-       uint8 control = 0;
-       result = _ReadRegister(EPCR, 1, &control);
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", 
result);
-               return result;
-       }
-
-       result = _Write1Register(EPCR, control & ~EPCR_ERPRW);
-       if (result != B_OK)
-               TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", 
result);
-       
-       return result;
-}
-
-
-status_t
-DavicomDevice::_InitMII()
-{
-       uint16 control = 0;
-       status_t result = _ReadMII(0, &control); // read BMCR
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to read BMCR register. Error:%#x\n", 
result);
-               return result;
-       }
-
-       result = _WriteMII(0, control & ~0x0400); // clear Isolate flag
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to write BMCR register. Error:%#x\n", 
result);
-               return result;
-       }
-
-       result = _WriteMII(0, 0x8000); // write reset to BMCR
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to reset BMCR register. Error:%#x\n", 
result);
-               return result;
-       }
-
-       uint16 id01 = 0, id02 = 0;
-       result = _ReadMII(0x02, &id01); // read PHY_ID 0
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to read PHY ID 0. Error:%#x\n", result);
-               return result;
-       }
-
-       result = _ReadMII(0x03, &id02); // read PHY_ID 1
-       if (result != B_OK) {
-               TRACE_ALWAYS("Failed to read PHY ID 1. Error:%#x\n", result);
-               return result;
-       }
-
 #define MII_OUI(id1, id2)       (((id1) << 6) | ((id2) >> 10))
 #define MII_MODEL(id2)          (((id2) & 0x03f0) >> 4)
 #define MII_REV(id2)             ((id2) & 0x000f)
 
-       TRACE_ALWAYS("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
-                       MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02));
 
-       return result;
-}
-
-
-status_t
-DavicomDevice::_EnableInterrupts(bool enable)
-{
-       uint8 control = 0;
-       status_t result = _ReadRegister(USBCR, 1, &control);
-       if(result != B_OK) {
-               TRACE_ALWAYS("Error of reading USB control register:%#010x\n", 
result);
-               return result;
-       }
-
-       if (enable) {
-               control |= EP3ACK;
-               control &= ~EP3NACK;
-       } else {
-               control &= ~EP3ACK;
-       }
-
-       result = _Write1Register(USBCR, control);
-       if(result != B_OK)
-               TRACE_ALWAYS("Error of setting USB control register:%#010x\n", 
result);
-
-       return result;
-}
-
-
-DavicomDevice::DavicomDevice(usb_device device, const char *description)
-       :       fStatus(B_ERROR),
+DavicomDevice::DavicomDevice(usb_device device, DeviceInfo& deviceInfo)
+       :       fDevice(device),
+               fStatus(B_ERROR),
                fOpen(false),
                fRemoved(false),
+               fHasConnection(false),
+               fTXBufferFull(false),
+               fNonBlocking(false),
                fInsideNotify(0),
-               fDevice(device),
-               fDescription(description),
-               fNonBlocking(false),
                fNotifyEndpoint(0),
                fReadEndpoint(0),
                fWriteEndpoint(0),
                fMaxTXPacketSize(0),
+               fActualLengthRead(0),
+               fActualLengthWrite(0),
+               fStatusRead(0),
+               fStatusWrite(0),
                fNotifyReadSem(-1),
                fNotifyWriteSem(-1),
-               fNotifyBuffer(NULL),
                fLinkStateChangeSem(-1),
-               fHasConnection(false)
+               fNotifyData(NULL)
 {
-       const usb_device_descriptor
-                       *deviceDescriptor = 
gUSBModule->get_device_descriptor(device);
+       fDeviceInfo = deviceInfo;
 
-       if (deviceDescriptor == NULL) {
-               TRACE_ALWAYS("Error of getting USB device descriptor.\n");
-               return;
-       }
-
-       fVendorID = deviceDescriptor->vendor_id;
-       fProductID = deviceDescriptor->product_id;
-
        fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
        if (fNotifyReadSem < B_OK) {
                TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n",
@@ -311,8 +132,8 @@
                return;
        }
 
-       fNotifyBuffer = (uint8*)malloc(kNotifyBufferSize);
-       if (fNotifyBuffer == NULL) {
+       fNotifyData = new DM9601NotifyData();
+       if (fNotifyData == NULL) {
                TRACE_ALWAYS("Error allocating notify buffer\n");
                return;
        }
@@ -324,6 +145,7 @@
        _InitMII();
 
        fStatus = B_OK;
+       TRACE("Created!\n");
 }
 
 
@@ -334,11 +156,11 @@
        if (fNotifyWriteSem >= B_OK)
                delete_sem(fNotifyWriteSem);
 
-       if (!fRemoved) //???
+       if (!fRemoved) // ???
                gUSBModule->cancel_queued_transfers(fNotifyEndpoint);
 
-       if(fNotifyBuffer)
-               free(fNotifyBuffer);
+       delete fNotifyData;
+       TRACE("Deleted!\n");
 }
 
 
@@ -350,23 +172,24 @@
        if (fRemoved)
                return B_ERROR;
 
-       status_t result = StartDevice();
+       status_t result = _StartDevice();
        if (result != B_OK) {
                return result;
        }
 
        // setup state notifications
-       result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyBuffer,
-               kNotifyBufferSize, _NotifyCallback, this);
-       if(result != B_OK) {
+       result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyData,
+               sizeof(DM9601NotifyData), _NotifyCallback, this);
+       if (result != B_OK) {
                TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", 
result);
                return result;
        }
 
-       result = _EnableInterrupts(true); 
+       result = _EnableInterrupts(true);
 
        fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
        fOpen = true;
+       TRACE("Opened: %#010x!\n", result);
        return result;
 }
 
@@ -378,9 +201,9 @@
                fOpen = false;
                return B_OK;
        }
-       
-       _EnableInterrupts(false); 
 
+       _EnableInterrupts(false);
+
        // wait until possible notification handling finished...
        while (atomic_add(&fInsideNotify, 0) != 0)
                snooze(100);
@@ -390,13 +213,16 @@
 
        fOpen = false;
 
-       return StopDevice();
+       status_t result = _StopDevice();
+       TRACE("Closed: %#010x!\n", result);
+       return result;
 }
 
 
 status_t
 DavicomDevice::Free()
 {
+       TRACE("Freed!\n");
        return B_OK;
 }
 
@@ -413,11 +239,27 @@
                return B_DEVICE_NOT_FOUND;
        }
 
-//     TRACE_RX("Request %d bytes.\n", numBytesToRead);
+       TRACE_RX("Request %d bytes.\n", numBytesToRead);
 
-       uint8 header[kRXHeaderSize];
+       struct _RXHeader {
+               uint    FOE     :1;
+               uint    CE      :1;
+               uint    LE      :1;
+               uint    PLE     :1;
+               uint    RWTO:1;
+               uint    LCS     :1;
+               uint    MF      :1;
+               uint    RF      :1;
+               uint    countLow        :8;
+               uint    countHigh       :8;
+
+               uint8   Errors() { return 0xbf & *(uint8*)this; }
+       } __attribute__((__packed__));
+
+       _RXHeader header = { 0 };
+
        iovec rxData[] = {
-               { header, kRXHeaderSize },
+               { &header, sizeof(header) },
                { buffer,  numBytesToRead }
        };
 
@@ -440,33 +282,28 @@
                return fStatusRead;
        }
 
-       if(fActualLengthRead < kRXHeaderSize) {
-               TRACE_ALWAYS("Error: no place for TRXHeader:only %d of %d 
bytes.\n",
-                       fActualLengthRead, kRXHeaderSize);
-               return B_ERROR; //TODO: ???
+       if (fActualLengthRead < sizeof(_RXHeader)) {
+               TRACE_ALWAYS("Error: no place for RXHeader: only %d of %d 
bytes.\n",
+                       fActualLengthRead, sizeof(_RXHeader));
+               return B_ERROR;
        }
 
-       /*
-        * TODO :see what the first byte holds ?
-       if(!header.IsValid()) {
-               TRACE_ALWAYS("Error:TRX Header is invalid: len:%#04x; 
ilen:%#04x\n",
-                       header.fLength, header.fInvertedLength);
-               return B_ERROR; //TODO: ???
+       if (header.Errors() != 0) {
+               TRACE_ALWAYS("RX header errors %#04x detected!\n", 
header.Errors());
        }
-       */
 
-       *numBytes = header[1] | ( header[2] << 8 );
+       TRACE_STATS("FOE:%d CE:%d LE:%d PLE:%d rwTO:%d LCS:%d MF:%d RF:%d\n",
+                       header.FOE, header.CE, header.LE, header.PLE,
+                       header.RWTO, header.LCS, header.MF, header.RF);
 
-       if (header[0] & 0xBF ) {
-               TRACE_ALWAYS("RX error %d occured !\n", header[0]);
-       }
+       *numBytes = header.countLow | ( header.countHigh << 8 );
 
-       if(fActualLengthRead - kRXHeaderSize > *numBytes) {
+       if (fActualLengthRead - sizeof(_RXHeader) > *numBytes) {
                TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; 
received:%d\n",
-                       *numBytes, fActualLengthRead - kRXHeaderSize);
+                       *numBytes, fActualLengthRead - sizeof(_RXHeader));
        }
 
-//     TRACE_RX("Read %d bytes.\n", *numBytes);
+       TRACE_RX("Read %d bytes.\n", *numBytes);
        return B_OK;
 }
 
@@ -490,13 +327,15 @@
        }
 
        if (fTXBufferFull) {
-               TRACE_ALWAYS("Error of writing %d bytes to device while TX 
buffer full.\n",
+               TRACE_ALWAYS("Error of writing %d bytes to device: TX buffer 
full.\n",
                        numBytesToWrite);
                return B_ERROR;
        }
 
        TRACE_TX("Write %d bytes.\n", numBytesToWrite);
 
+       // additional padding byte must be transmitted in case data size
+       // to be send is multiple of pipe's max packet size
        uint16 length = numBytesToWrite;
        size_t count = 2;
        if (((numBytesToWrite + 2) % fMaxTXPacketSize) == 0) {
@@ -504,17 +343,23 @@
                count++;
        }
 
-       uint8 header[kTXHeaderSize] = { length & 0xFF, length >> 8 };
+       struct _TXHeader {
+               uint    countLow        :8;
+               uint    countHigh       :8;
+       } __attribute__((__packed__));
+
+       _TXHeader header = { length & 0xff, length >> 8 & 0xff };
+
        uint8 padding = 0;
 
        iovec txData[] = {
-               { header, kTXHeaderSize },
+               { &header, sizeof(_TXHeader) },
                { (uint8*)buffer, numBytesToWrite },
                { &padding, 1 }
        };
 
        status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint,
-               txData, count/*2*/, _WriteCallback, this);
+               txData, count, _WriteCallback, this);
        if (result != B_OK) {
                TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result);
                return result;
@@ -532,7 +377,7 @@
                return fStatusWrite;
        }
 
-       *numBytes = fActualLengthWrite - kTXHeaderSize;;
+       *numBytes = fActualLengthWrite - sizeof(_TXHeader);
 
        TRACE_TX("Written %d bytes.\n", *numBytes);
        return B_OK;
@@ -551,7 +396,7 @@
                        return B_OK;
 
                case ETHER_GETFRAMESIZE:
-                       *(uint32 *)buffer = 1518 /* fFrameSize */;
+                       *(uint32 *)buffer = kFrameSize;
                        return B_OK;
 
                case ETHER_NONBLOCK:
@@ -561,24 +406,22 @@
 
                case ETHER_SETPROMISC:
                        TRACE("ETHER_SETPROMISC\n");
-                       return SetPromiscuousMode(*((uint8*)buffer));
+                       return _SetPromiscuousMode(*((uint8*)buffer));
 
                case ETHER_ADDMULTI:
                        TRACE("ETHER_ADDMULTI\n");
-                       return ModifyMulticastTable(true, *((uint8*)buffer));
+                       return _ModifyMulticastTable(true, 
(ether_address_t*)buffer);
 
                case ETHER_REMMULTI:
                        TRACE("ETHER_REMMULTI\n");
-                       return ModifyMulticastTable(false, *((uint8*)buffer));
+                       return _ModifyMulticastTable(false, 
(ether_address_t*)buffer);
 
-#if HAIKU_TARGET_PLATFORM_HAIKU
                case ETHER_SET_LINK_STATE_SEM:
                        fLinkStateChangeSem = *(sem_id *)buffer;
                        return B_OK;
 
                case ETHER_GET_LINK_STATE:
-                       return GetLinkState((ether_link_state *)buffer);
-#endif
+                       return _GetLinkState((ether_link_state *)buffer);
 
                default:
                        TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op);
@@ -616,8 +459,8 @@
 DavicomDevice::SetupDevice(bool deviceReplugged)
 {
        ether_address address;
-       status_t result = ReadMACAddress(&address);
-       if(result != B_OK) {
+       status_t result = _ReadMACAddress(&address);
+       if (result != B_OK) {
                TRACE_ALWAYS("Error reading MAC address:%#010x\n", result);
                return result;
        }
@@ -626,14 +469,15 @@
                                address.ebyte[0], address.ebyte[1], 
address.ebyte[2],
                                address.ebyte[3], address.ebyte[4], 
address.ebyte[5]);
 
-       if(deviceReplugged) {
-               // this might be the same device that was replugged - read the 
MAC address
-               // (which should be at the same index) to make sure
-               if(memcmp(&address, &fMACAddress, sizeof(address)) != 0) {
+       if (deviceReplugged) {
+               // this might be the same device that was replugged - read the 
MAC
+               // address (which should be at the same index) to make sure
+               if (memcmp(&address, &fMACAddress, sizeof(address)) != 0) {
                        TRACE_ALWAYS("Cannot replace device with MAC address:"
-                                                                               
                "%02x:%02x:%02x:%02x:%02x:%02x\n",
-                               fMACAddress.ebyte[0], fMACAddress.ebyte[1], 
fMACAddress.ebyte[2],
-                               fMACAddress.ebyte[3], fMACAddress.ebyte[4], 
fMACAddress.ebyte[5]);
+                               "%02x:%02x:%02x:%02x:%02x:%02x\n",
+                               fMACAddress.ebyte[0], fMACAddress.ebyte[1],
+                               fMACAddress.ebyte[2], fMACAddress.ebyte[3],
+                               fMACAddress.ebyte[4], fMACAddress.ebyte[5]);
                        return B_BAD_VALUE; // is not the same
                }
        } else
@@ -654,8 +498,8 @@
                return B_ERROR;
        }
 
-       if (deviceDescriptor->vendor_id != fVendorID
-               && deviceDescriptor->product_id != fProductID) {
+       if (deviceDescriptor->vendor_id != fDeviceInfo.VendorId()
+               && deviceDescriptor->product_id != fDeviceInfo.ProductId()) {
                // this certainly isn't the same device
                return B_BAD_VALUE;
        }
@@ -713,35 +557,41 @@
        int readEndpoint   = -1;
        int writeEndpoint  = -1;
 
-       for(size_t ep = 0; ep < interface->endpoint_count; ep++) {
-         usb_endpoint_descriptor *epd = interface->endpoint[ep].descr;
-         if((epd->attributes & USB_ENDPOINT_ATTR_MASK) == 
USB_ENDPOINT_ATTR_INTERRUPT) {
-           notifyEndpoint = ep;
-           continue;
-         }
+       for (size_t ep = 0; ep < interface->endpoint_count; ep++) {
+               usb_endpoint_descriptor *epd = interface->endpoint[ep].descr;
+               if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
+                               == USB_ENDPOINT_ATTR_INTERRUPT)
+               {
+                       notifyEndpoint = ep;
+                       continue;
+               }
 
-         if((epd->attributes & USB_ENDPOINT_ATTR_MASK) != 
USB_ENDPOINT_ATTR_BULK) {
-           TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n", 
epd->attributes);
-           continue;
-         }
+               if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
+                               != USB_ENDPOINT_ATTR_BULK)
+               {
+                       TRACE_ALWAYS("Error: USB endpoint type %#04x is 
unknown.\n",
+                                       epd->attributes);
+                       continue;
+               }
 
-         if((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
-                                                                               
                        == USB_ENDPOINT_ADDR_DIR_IN) {
-           readEndpoint = ep;
-               continue;
-         }
+               if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
+                               == USB_ENDPOINT_ADDR_DIR_IN)
+               {
+                       readEndpoint = ep;
+                       continue;
+               }
 
-         if((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT)
-                                                                               
                        == USB_ENDPOINT_ADDR_DIR_OUT) {
-           writeEndpoint = ep;
-               continue;
-         }
+               if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT)
+                               == USB_ENDPOINT_ADDR_DIR_OUT)
+               {
+                       writeEndpoint = ep;
+                       continue;
+               }
        }
 
        if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) {
-               TRACE_ALWAYS("Error: not all USB endpoints were found: "
-                                                                               
"notify:%d; read:%d; write:%d\n",
-                                                                               
        notifyEndpoint, readEndpoint, writeEndpoint);
+               TRACE_ALWAYS("Error: not all USB endpoints were found: 
notify:%d; "
+                       "read:%d; write:%d\n", notifyEndpoint, readEndpoint, 
writeEndpoint);
                return B_ERROR;
        }
 
@@ -757,10 +607,11 @@
 
 
 status_t
-DavicomDevice::ReadMACAddress(ether_address_t *address)
+DavicomDevice::_ReadMACAddress(ether_address_t *address)
 {
-       status_t result = _ReadRegister(PAR, sizeof(ether_address), 
(uint8*)address);
-       if(result != B_OK) {
+       status_t result = _ReadRegister(RegPAR,
+                                                       sizeof(ether_address), 
(uint8*)address);
+       if (result != B_OK) {
                TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result);
                return result;
        }
@@ -770,19 +621,87 @@
 
 
 status_t
-DavicomDevice::StopDevice()
+DavicomDevice::_StartDevice()
 {
        uint8 control = 0;
 
+       // disable loopback
+       status_t result = _ReadRegister(RegNCR, 1, &control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error reading NCR: %#010x.\n", result);
+               return result;
+       }
+
+       if (control & NCRExtPHY)
+               TRACE_ALWAYS("Device uses external PHY\n");
+
+       control &= ~NCRLoopback;
+       result = _Write1Register(RegNCR, control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error writing %#02X to NCR: %#010x.\n", control, 
result);
+               return result;
+       }
+
+       // Initialize RX control register, enable RX and activate multicast
+       result = _ReadRegister(RegRCR, 1, &control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
+               return result;
+       }
+
+       control &= ~RCRPromiscuous;
+       control |= RCRDiscardLong | RCRDiscardCRC | RCRRXEnable | 
RCRAllMulticast;
+       result = _Write1Register(RegRCR, control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, 
result);
+               return result;
+       }
+
+       // clear POWER_DOWN state of internal PHY
+       result = _ReadRegister(RegGPCR, 1, &control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error reading GPCR: %#010x.\n", result);
+               return result;
+       }
+
+       control |= GPCRPowerDown;
+       result = _Write1Register(RegGPCR, control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error writing %#02X to GPCR: %#010x.\n", control, 
result);
+               return result;
+       }
+
+       result = _ReadRegister(RegGPR, 1, &control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error reading GPR: %#010x.\n", result);
+               return result;
+       }
+
+       control &= ~GPRPowerDownInPHY;
+       result = _Write1Register(RegGPR, control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error writing %#02X to GPR: %#010x.\n", control, 
result);
+               return result;
+       }
+
+       return B_OK;
+}
+
+
+status_t
+DavicomDevice::_StopDevice()
+{
+       uint8 control = 0;
+
        // disable RX
-       status_t result = _ReadRegister(RCR, 1, &control);
+       status_t result = _ReadRegister(RegRCR, 1, &control);
        if (result != B_OK) {
                TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
                return result;
        }
 
-       control &= ~RCR_RXEN;
-       result = _Write1Register(RCR, control);
+       control &= ~RCRRXEnable;
+       result = _Write1Register(RegRCR, control);
        if (result != B_OK)
                TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, 
result);
 
@@ -791,40 +710,110 @@
 
 
 status_t
-DavicomDevice::SetPromiscuousMode(bool on)
+DavicomDevice::_SetPromiscuousMode(bool on)
 {
+       uint8 control = 0;
 
-       /* load multicast filter and update promiscious mode bit */
-       uint8_t rxmode;
-
-       status_t result = _ReadRegister(RCR, 1, &rxmode);
+       status_t result = _ReadRegister(RegRCR, 1, &control);
        if (result != B_OK) {
-               TRACE_ALWAYS("Error reading RX Control:%#010x\n", result);
+               TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
                return result;
        }
-       rxmode &= ~(RCR_ALL | RCR_PRMSC);
 
        if (on)
-               rxmode |= RCR_ALL | RCR_PRMSC;
-/*     else if (ifp->if_flags & IFF_ALLMULTI)
-               rxmode |= RCR_ALL; */
+               control |= RCRPromiscuous;
+       else
+               control &= ~RCRPromiscuous;
 
-       /* write new mode bits */
-       result = _Write1Register(RCR, rxmode);
-       if(result != B_OK) {
-               TRACE_ALWAYS("Error writing %#04x to RX Control:%#010x\n", 
rxmode, result);
-       }
+       result = _Write1Register(RegRCR, control);
+       if (result != B_OK)
+               TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, 
result);
 
        return result;
 }
 
 
+uint32
+DavicomDevice::_EthernetCRC32(const uint8* buffer, size_t length)
+{
+       uint32 result = 0xffffffff;
+       for (size_t i = 0; i < length; i++) {
+               uint8 data = *buffer++;
+               for (int bit = 0; bit < 8; bit++, data >>= 1) {
+                       uint32 carry = ((result & 0x80000000) ? 1 : 0) ^ (data 
& 0x01);
+                       result <<= 1;
+                       if (carry != 0)
+                               result = (result ^ 0x04c11db6) | carry;
+               }
+       }
+       return result;
+}
+
+
 status_t
-DavicomDevice::ModifyMulticastTable(bool add, uint8 address)
+DavicomDevice::_ModifyMulticastTable(bool join, ether_address_t *group)
 {
-               //TODO: !!!
-       TRACE_ALWAYS("Call for (%d, %#02x) is not implemented\n", add, address);
-       return B_OK;
+       char groupName[6 * 3 + 1] = { 0 };
+       sprintf(groupName, "%02x:%02x:%02x:%02x:%02x:%02x",
+               group->ebyte[0], group->ebyte[1], group->ebyte[2],
+               group->ebyte[3], group->ebyte[4], group->ebyte[5]);
+       TRACE("%s multicast group %s\n", join ? "Joining" : "Leaving", 
groupName);
+
+       uint32 hash = _EthernetCRC32(group->ebyte, 6);
+       bool isInTable = fMulticastHashes.Find(hash) != fMulticastHashes.End();
+       
+       if (isInTable && join)
+               return B_OK; // already listed - nothing to do
+
+       if (!isInTable && !join) {
+               TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", 
groupName);
+               return B_ERROR;
+       }
+
+       const size_t hashLength = 8;
+       uint8 hashTable[hashLength] = { 0 };
+       hashTable[hashLength - 1] |= 0x80; // broadcast address
+
+       status_t result = _WriteRegister(RegMAR, hashLength, hashTable);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error initializing MAR: %#010x.\n", result);
+               return result;
+       }
+       
+       if (join)
+               fMulticastHashes.PushBack(hash);
+       else
+               fMulticastHashes.Remove(hash);
+
+       for (int32 i = 0; i < fMulticastHashes.Count(); i++) {
+               uint32 hash = fMulticastHashes[i] >> 26;
+               hashTable[hash / 8] |= 1 << (hash % 8);
+       }
+
+       // clear/set pass all multicast bit as required
+       uint8 control = 0;
+       result = _ReadRegister(RegRCR, 1, &control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
+               return result;
+       }
+
+       if (fMulticastHashes.Count() > 0)
+               control &= ~RCRAllMulticast;
+       else
+               control |= RCRAllMulticast;
+
+       result = _Write1Register(RegRCR, control);
+       if (result != B_OK) {
+               TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, 
result);
+               return result;
+       }
+
+       result = _WriteRegister(RegMAR, hashLength, hashTable);
+       if (result != B_OK)
+               TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", 
result);
+
+       return result;
 }
 
 
@@ -832,10 +821,11 @@
 DavicomDevice::_ReadCallback(void *cookie, int32 status, void *data,
        uint32 actualLength)
 {
-//     TRACE_RX("ReadCB: %d bytes; status:%#010x\n", actualLength, status);
+       TRACE_RX("ReadCB: %d bytes; status:%#010x\n", actualLength, status);
        DavicomDevice *device = (DavicomDevice *)cookie;
        device->fActualLengthRead = actualLength;
        device->fStatusRead = status;
+       device->fStats.readCount++;
        release_sem_etc(device->fNotifyReadSem, 1, B_DO_NOT_RESCHEDULE);
 }
 
@@ -848,6 +838,7 @@
        DavicomDevice *device = (DavicomDevice *)cookie;
        device->fActualLengthWrite = actualLength;

[... truncated: 1326 lines follow ...]

Other related posts:

  • » [haiku-commits] r42749 - haiku/trunk/src/add-ons/kernel/drivers/network/usb_davicom - zharik