From 288723f429eaa141c5ddd55dafe252b34be35fc5 Mon Sep 17 00:00:00 2001 From: Siarzhuk Zharski Date: Mon, 12 Sep 2011 19:42:52 +0000 Subject: [PATCH] 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. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42749 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/usb_davicom/DavicomDevice.cpp | 1115 ++++++++++------- .../network/usb_davicom/DavicomDevice.h | 154 ++- .../drivers/network/usb_davicom/Driver.cpp | 130 +- .../drivers/network/usb_davicom/Driver.h | 34 +- .../drivers/network/usb_davicom/Jamfile | 1 + .../drivers/network/usb_davicom/Settings.cpp | 92 +- .../drivers/network/usb_davicom/Settings.h | 48 +- .../network/usb_davicom/usb_davicom.settings | 23 +- 8 files changed, 939 insertions(+), 658 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp index dcb2ed13a9..e816da5b6c 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp +++ b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.cpp @@ -1,301 +1,122 @@ /* * Davicom DM9601 USB 1.1 Ethernet Driver. - * Copyright (c) 2009 Adrien Destugues * Copyright (c) 2008, 2011 Siarzhuk Zharski + * Copyright (c) 2009 Adrien Destugues * 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 * Distributed under the terms of the MIT license. - * */ #include "DavicomDevice.h" +#include +#include + #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 +enum DM9601Registers { + RegNCR = 0x00, // Network Control Register + NCRExtPHY = 0x80, // Select External PHY + NCRFullDX = 0x08, // Full duplex + NCRLoopback = 0x06, // Internal PHY analog loopback -#define NCR_EXT_PHY 0x80 // External PHY -#define NCR_FDX 0x08 // Full duplex -#define NCR_LBK 0x06 // Loopback mode + 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 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 + 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 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 + 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 GPCR_GEP_CNTL0 0x01 // Power Down function + RegEPAR = 0x0c, // EEPROM & PHY Address Register + EPARIntPHY = 0x40, // [7:6] force to 01 if Internal PHY is selected + EPARMask = 0x1f, // mask [0:5] -#define GPR_GEP_GEPIO0 0x01 // Power down + RegEPDRL = 0x0d, // EEPROM & PHY Low Byte Data Register -#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 + RegEPDRH = 0x0e, // 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] - -#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; - } - - // 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; - } + RegBMSR = 0x01, + RegPHYID1 = 0x02, + RegPHYID2 = 0x03, +}; #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), - fInsideNotify(0), - fDevice(device), - fDescription(description), + fHasConnection(false), + fTXBufferFull(false), fNonBlocking(false), + fInsideNotify(0), 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); - - if (deviceDescriptor == NULL) { - TRACE_ALWAYS("Error of getting USB device descriptor.\n"); - return; - } - - fVendorID = deviceDescriptor->vendor_id; - fProductID = deviceDescriptor->product_id; + fDeviceInfo = deviceInfo; fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); if (fNotifyReadSem < B_OK) { @@ -311,8 +132,8 @@ DavicomDevice::DavicomDevice(usb_device device, const char *description) 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 @@ DavicomDevice::DavicomDevice(usb_device device, const char *description) _InitMII(); fStatus = B_OK; + TRACE("Created!\n"); } @@ -334,11 +156,11 @@ DavicomDevice::~DavicomDevice() 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 @@ DavicomDevice::Open(uint32 flags) 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,8 +201,8 @@ DavicomDevice::Close() fOpen = false; return B_OK; } - - _EnableInterrupts(false); + + _EnableInterrupts(false); // wait until possible notification handling finished... while (atomic_add(&fInsideNotify, 0) != 0) @@ -390,13 +213,16 @@ DavicomDevice::Close() 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 @@ DavicomDevice::Read(uint8 *buffer, size_t *numBytes) return B_DEVICE_NOT_FOUND; } -// TRACE_RX("Request %d bytes.\n", numBytesToRead); + TRACE_RX("Request %d bytes.\n", numBytesToRead); + + 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 }; - uint8 header[kRXHeaderSize]; iovec rxData[] = { - { header, kRXHeaderSize }, + { &header, sizeof(header) }, { buffer, numBytesToRead } }; @@ -440,33 +282,28 @@ DavicomDevice::Read(uint8 *buffer, size_t *numBytes) 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: ??? - } - */ - - *numBytes = header[1] | ( header[2] << 8 ); - - if (header[0] & 0xBF ) { - TRACE_ALWAYS("RX error %d occured !\n", header[0]); + if (header.Errors() != 0) { + TRACE_ALWAYS("RX header errors %#04x detected!\n", header.Errors()); } - if(fActualLengthRead - kRXHeaderSize > *numBytes) { + 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); + + *numBytes = header.countLow | ( header.countHigh << 8 ); + + 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 @@ DavicomDevice::Write(const uint8 *buffer, size_t *numBytes) } 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 @@ DavicomDevice::Write(const uint8 *buffer, size_t *numBytes) 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 @@ DavicomDevice::Write(const uint8 *buffer, size_t *numBytes) return fStatusWrite; } - *numBytes = fActualLengthWrite - kTXHeaderSize;; + *numBytes = fActualLengthWrite - sizeof(_TXHeader); TRACE_TX("Written %d bytes.\n", *numBytes); return B_OK; @@ -551,7 +396,7 @@ DavicomDevice::Control(uint32 op, void *buffer, size_t length) return B_OK; case ETHER_GETFRAMESIZE: - *(uint32 *)buffer = 1518 /* fFrameSize */; + *(uint32 *)buffer = kFrameSize; return B_OK; case ETHER_NONBLOCK: @@ -561,24 +406,22 @@ DavicomDevice::Control(uint32 op, void *buffer, size_t length) 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 @@ status_t 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 @@ DavicomDevice::SetupDevice(bool deviceReplugged) 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 @@ DavicomDevice::CompareAndReattach(usb_device device) 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 @@ DavicomDevice::_SetupEndpoints() 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 @@ DavicomDevice::_SetupEndpoints() 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 @@ DavicomDevice::ReadMACAddress(ether_address_t *address) status_t -DavicomDevice::StopDevice() +DavicomDevice::_StartDevice() { uint8 control = 0; - // disable RX - status_t result = _ReadRegister(RCR, 1, &control); + // 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 &= ~RCR_RXEN; - result = _Write1Register(RCR, control); + 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(RegRCR, 1, &control); + if (result != B_OK) { + TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); + return result; + } + + 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 @@ DavicomDevice::StopDevice() 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; } -status_t -DavicomDevice::ModifyMulticastTable(bool add, uint8 address) +uint32 +DavicomDevice::_EthernetCRC32(const uint8* buffer, size_t length) { - //TODO: !!! - TRACE_ALWAYS("Call for (%d, %#02x) is not implemented\n", add, address); - return B_OK; + 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 join, ether_address_t *group) +{ + 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 @@ void 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::_WriteCallback(void *cookie, int32 status, void *data, DavicomDevice *device = (DavicomDevice *)cookie; device->fActualLengthWrite = actualLength; device->fStatusWrite = status; + device->fStats.writeCount++; release_sem_etc(device->fNotifyWriteSem, 1, B_DO_NOT_RESCHEDULE); } @@ -863,113 +854,30 @@ DavicomDevice::_NotifyCallback(void *cookie, int32 status, void *data, return; } - if (status != B_OK) { - TRACE_ALWAYS("Device status error:%#010x\n", status); - /* - status_t result = gUSBModule->clear_feature(device->fNotifyEndpoint, - USB_FEATURE_ENDPOINT_HALT); - if(result != B_OK) - TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); - */ - } - - // parse data in overriden class - device->OnNotify(actualLength); + if (status == B_OK) + device->_OnNotify(actualLength); + else + TRACE_ALWAYS("Status error:%#010x; length:%d\n", status, actualLength); // schedule next notification buffer - gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyBuffer, - kNotifyBufferSize, _NotifyCallback, device); + gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyData, + sizeof(DM9601NotifyData), _NotifyCallback, device); atomic_add(&device->fInsideNotify, -1); } status_t -DavicomDevice::StartDevice() +DavicomDevice::_OnNotify(uint32 actualLength) { - uint8 control = 0; - - // disable loopback - status_t result = _ReadRegister(NCR, 1, &control); - if (result != B_OK) { - TRACE_ALWAYS("Error reading NCR: %#010x.\n", result); - return result; - } - - if (control & NCR_EXT_PHY) - TRACE_ALWAYS("Device uses external PHY\n"); - - control &= ~NCR_LBK; - result = _Write1Register(NCR, 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(RCR, 1, &control); - if (result != B_OK) { - TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); - return result; - } - - // TODO: do not forget handle promiscous mode correctly in the future!!! - control |= RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN | RCR_ALL; - result = _Write1Register(RCR, 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(GPCR, 1, &control); - if (result != B_OK) { - TRACE_ALWAYS("Error reading GPCR: %#010x.\n", result); - return result; - } - - control |= GPCR_GEP_CNTL0; - result = _Write1Register(GPCR, control); - if (result != B_OK) { - TRACE_ALWAYS("Error writing %#02X to GPCR: %#010x.\n", control, result); - return result; - } - - result = _ReadRegister(GPR, 1, &control); - if (result != B_OK) { - TRACE_ALWAYS("Error reading GPR: %#010x.\n", result); - return result; - } - - control &= ~GPR_GEP_GEPIO0; - result = _Write1Register(GPR, control); - if (result != B_OK) { - TRACE_ALWAYS("Error writing %#02X to GPR: %#010x.\n", control, result); - return result; - } - - return B_OK; -} - - -status_t -DavicomDevice::OnNotify(uint32 actualLength) -{ - if (actualLength != kNotifyBufferSize) { - TRACE_ALWAYS("Data underrun error. %d of 8 bytes received\n", - actualLength); + if (actualLength != sizeof(DM9601NotifyData)) { + TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n", + actualLength, sizeof(DM9601NotifyData)); return B_BAD_DATA; } - // 3 = RX status - // 4 = Receive overflow counter - // 5 = Received packet counter - // 6 = Transmit packet counter - // 7 = GPR - - // 0 = Network status (NSR) - bool linkIsUp = (fNotifyBuffer[0] & NSR_LINKST) != 0; - fTXBufferFull = (fNotifyBuffer[0] & NSR_TXFULL) != 0; - bool rxOverflow = (fNotifyBuffer[0] & NSR_RXOV) != 0; + bool linkIsUp = fNotifyData->LINKST != 0; + fTXBufferFull = fNotifyData->TXFULL != 0; + bool rxOverflow = fNotifyData->RXOV != 0; bool linkStateChange = (linkIsUp != fHasConnection); fHasConnection = linkIsUp; @@ -977,19 +885,72 @@ DavicomDevice::OnNotify(uint32 actualLength) if (linkStateChange) { if (fHasConnection) { TRACE("Link is now up at %s Mb/s\n", - (fNotifyBuffer[0] & NSR_SPEED) ? "10" : "100"); + fNotifyData->SPEED ? "10" : "100"); } else TRACE("Link is now down"); } - if (rxOverflow) - TRACE("RX buffer overflow occured %d times\n", fNotifyBuffer[4]); +#ifdef UDAV_TRACE + if (gTraceStats) { + if (fNotifyData->TXFULL) + fStats.txFull++; + if (fNotifyData->RXOV) + fStats.rxOverflow++; - // 1,2 = TX status - if (fNotifyBuffer[1]) - TRACE("Error %x occured on transmitting packet 1\n", fNotifyBuffer[1]); - if (fNotifyBuffer[2]) - TRACE("Error %x occured on transmitting packet 2\n", fNotifyBuffer[2]); + if (fNotifyData->ROC) + fStats.rxOvCount += fNotifyData->ROC; + + if (fNotifyData->RT) + fStats.runtFrames++; + if (fNotifyData->LCS) + fStats.lateRXCollisions++; + if (fNotifyData->RWTO) + fStats.rwTOs++; + if (fNotifyData->PLE) + fStats.physLayerErros++; + if (fNotifyData->AE) + fStats.alignmentErros++; + if (fNotifyData->CE) + fStats.crcErrors++; + if (fNotifyData->FOE) + fStats.overErrors++; + + if (fNotifyData->TSR1.LC) + fStats.lateTXCollisions++; + if (fNotifyData->TSR1.LCR) + fStats.lostOfCarrier++; + if (fNotifyData->TSR1.NC) + fStats.noCarrier++; + if (fNotifyData->TSR1.COL) + fStats.txCollisions++; + if (fNotifyData->TSR1.EC) + fStats.excCollisions++; + + if (fNotifyData->TSR2.LC) + fStats.lateTXCollisions++; + if (fNotifyData->TSR2.LCR) + fStats.lostOfCarrier++; + if (fNotifyData->TSR2.NC) + fStats.noCarrier++; + if (fNotifyData->TSR2.COL) + fStats.txCollisions++; + if (fNotifyData->TSR2.EC) + fStats.excCollisions++; + + fStats.notifyCount++; + } +#endif + + if (rxOverflow) + TRACE("RX buffer overflow. %d packets dropped\n", fNotifyData->ROC); + + uint8 tsr = 0xfc & *(uint8*)&fNotifyData->TSR1; + if (tsr != 0) + TRACE("TX packet 1: Status %#04x is not OK.\n", tsr); + + tsr = 0xfc & *(uint8*)&fNotifyData->TSR2; + if (tsr != 0) + TRACE("TX packet 2: Status %#04x is not OK.\n", tsr); if (linkStateChange && fLinkStateChangeSem >= B_OK) release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); @@ -998,16 +959,16 @@ DavicomDevice::OnNotify(uint32 actualLength) status_t -DavicomDevice::GetLinkState(ether_link_state *linkState) +DavicomDevice::_GetLinkState(ether_link_state *linkState) { uint8 registerValue = 0; - status_t result = _ReadRegister(NSR, 1, ®isterValue); + status_t result = _ReadRegister(RegNSR, 1, ®isterValue); if (result != B_OK) { - TRACE_ALWAYS("Error reading NSR register! %x\n",result); + TRACE_ALWAYS("Error reading NSR register! %x\n", result); return result; } - if (registerValue & NSR_SPEED) + if (registerValue & NSRSpeed10) linkState->speed = 10000000; else linkState->speed = 100000000; @@ -1017,26 +978,236 @@ DavicomDevice::GetLinkState(ether_link_state *linkState) linkState->media = IFM_ETHER | IFM_100_TX; if (fHasConnection) { linkState->media |= IFM_ACTIVE; - result = _ReadRegister(NCR, 1, ®isterValue); + result = _ReadRegister(RegNCR, 1, ®isterValue); if (result != B_OK) { - TRACE_ALWAYS("Error reading NCR register! %x\n",result); + TRACE_ALWAYS("Error reading NCR register! %x\n", result); return result; } - if (registerValue & NCR_FDX) + if (registerValue & NCRFullDX) linkState->media |= IFM_FULL_DUPLEX; else linkState->media |= IFM_HALF_DUPLEX; - if (registerValue & NCR_LBK) + if (registerValue & NCRLoopback) linkState->media |= IFM_LOOP; } -/* + TRACE_STATE("Medium state: %s, %lld MBit/s, %s duplex.\n", (linkState->media & IFM_ACTIVE) ? "active" : "inactive", linkState->speed / 1000000, (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); -*/ + + TRACE_STATS("tx:%d rx:%d rxCn:%d rtF:%d lRxC:%d rwTO:%d PLE:%d AE:%d CE:%d " + "oE:%d ltxC:%d lCR:%d nC:%d txC:%d exC:%d r:%d w:%d n:%d\n", + fStats.txFull, fStats.rxOverflow, fStats.rxOvCount, + fStats.runtFrames, fStats.lateRXCollisions, fStats.rwTOs, + fStats.physLayerErros, fStats.alignmentErros, + fStats.crcErrors, fStats.overErrors, + fStats.lateTXCollisions, fStats.lostOfCarrier, + fStats.noCarrier, fStats.txCollisions, fStats.excCollisions, + fStats.readCount, fStats.writeCount, fStats.notifyCount); return B_OK; } + +status_t +DavicomDevice::_ReadRegister(uint8 reg, size_t size, uint8* buffer) +{ + if (size > 255) + return B_BAD_VALUE; + + size_t actualLength = 0; + status_t result = gUSBModule->send_request(fDevice, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, + ReqReadRegister, 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 = 0; + + status_t result = gUSBModule->send_request(fDevice, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + ReqWriteRegister, 0, reg, size, buffer, &actualLength); + + return result; +} + + +status_t +DavicomDevice::_Write1Register(uint8 reg, uint8 value) +{ + size_t actualLength = 0; + + status_t result = gUSBModule->send_request(fDevice, + USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, + ReqWriteRegisterByte, 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(RegEPAR, EPARIntPHY | (reg & EPARMask)); + if (result != B_OK) { + TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result); + return result; + } + + // select PHY operation and initiate reading + result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegRead); + if (result != B_OK) { + TRACE_ALWAYS("Failed to starting MII reading. Error:%#x\n", result); + return result; + } + + // finalize writing + uint8 control = 0; + result = _ReadRegister(RegEPCR, 1, &control); + if (result != B_OK) { + TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result); + return result; + } + + result = _Write1Register(RegEPCR, control & ~EPCRRegRead); + if (result != B_OK) { + TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result); + return result; + } + + // retrieve the result from data registers + uint8 values[2] = { 0 }; + result = _ReadRegister(RegEPDRL, 2, values); + if (result != B_OK) { + TRACE_ALWAYS("Failed to retrieve data %#x. Error:%#x\n", data, result); + return result; + } + + *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(RegEPAR, EPARIntPHY | (reg & EPARMask)); + if (result != B_OK) { + TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result); + return result; + } + + // put the value to data register + uint8 values[] = { data & 0xff, ( data >> 8 ) & 0xff }; + result = _WriteRegister(RegEPDRL, sizeof(uint16), values); + if (result != B_OK) { + TRACE_ALWAYS("Failed to put data %#x. Error:%#x\n", data, result); + return result; + } + + // select PHY operation and initiate writing + result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegWrite); + if (result != B_OK) { + TRACE_ALWAYS("Failed to starting MII wrintig. Error:%#x\n", result); + return result; + } + + // finalize writing + uint8 control = 0; + result = _ReadRegister(RegEPCR, 1, &control); + if (result != B_OK) { + TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result); + return result; + } + + result = _Write1Register(RegEPCR, control & ~EPCRRegWrite); + 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(RegBMCR, &control); + if (result != B_OK) { + TRACE_ALWAYS("Failed to read MII BMCR register. Error:%#x\n", result); + return result; + } + + result = _WriteMII(RegBMCR, control & ~BMCRIsolate); + if (result != B_OK) { + TRACE_ALWAYS("Failed to clear isolate PHY. Error:%#x\n", result); + return result; + } + + result = _WriteMII(0, BMCRReset); + if (result != B_OK) { + TRACE_ALWAYS("Failed to reset BMCR register. Error:%#x\n", result); + return result; + } + + uint16 id01 = 0, id02 = 0; + result = _ReadMII(RegPHYID1, &id01); + if (result != B_OK) { + TRACE_ALWAYS("Failed to read PHY ID 0. Error:%#x\n", result); + return result; + } + + result = _ReadMII(RegPHYID2, &id02); + if (result != B_OK) { + TRACE_ALWAYS("Failed to read PHY ID 1. Error:%#x\n", result); + return result; + } + + 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(RegUSBC, 1, &control); + if (result != B_OK) { + TRACE_ALWAYS("Error of reading USB control register:%#010x\n", result); + return result; + } + + if (enable) { + control |= USBCIntAck; + control &= ~USBCIntNAck; + } else { + control &= ~USBCIntAck; + } + + result = _Write1Register(RegUSBC, control); + if (result != B_OK) + TRACE_ALWAYS("Error of setting USB control register:%#010x\n", result); + + return result; +} + diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h index 11da5f6566..d8441bd11e 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h +++ b/src/add-ons/kernel/drivers/network/usb_davicom/DavicomDevice.h @@ -1,28 +1,109 @@ /* * Davicom DM9601 USB 1.1 Ethernet Driver. + * Copyright (c) 2008, 2011 Siarzhuk Zharski * Copyright (c) 2009 Adrien Destugues - * Copyright (c) 2008, 2011 S.Zharski * 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 * Distributed under the terms of the MIT license. - * */ -#ifndef _USB_Davicom_DEVICE_H_ -#define _USB_Davicom_DEVICE_H_ +#ifndef _USB_DAVICOM_DEVICE_H_ +#define _USB_DAVICOM_DEVICE_H_ -#include +#include +#include #include "Driver.h" +struct DM9601NotifyData { + // Network Status Register + uint RXRDY :1; + uint RXOV :1; + uint TX1END :1; + uint TX2END :1; + uint TXFULL :1; + uint WAKEST :1; + uint LINKST :1; + uint SPEED :1; + + struct { + uint :2; + uint EC :1; + uint COL :1; + uint LC :1; + uint NC :1; + uint LCR :1; + uint :1; + } __attribute__((__packed__)) TSR1, TSR2; + + // RX Status Register + uint FOE :1; + uint CE :1; + uint AE :1; + uint PLE :1; + uint RWTO :1; + uint LCS :1; + uint MF :1; + uint RT :1; + + // RX Overflows Count + uint RXFU :1; + uint ROC :7; + + uint RXC :8; + uint TXC :8; + uint GPR :8; + + DM9601NotifyData() { memset(this, 0, sizeof(DM9601NotifyData)); } +} __attribute__((__packed__)); + + +struct DeviceInfo { + union Id { + uint16 fIds[2]; + uint32 fKey; + } fId; + const char* fName; + inline uint16 VendorId() { return fId.fIds[0]; } + inline uint16 ProductId() { return fId.fIds[1]; } + inline uint32 Key() { return fId.fKey; } +}; + class DavicomDevice { + + struct _Statistics { + // NSR + int txFull; + int rxOverflow; + int rxOvCount; + // RSR + int runtFrames; + int lateRXCollisions; + int rwTOs; + int physLayerErros; + int alignmentErros; + int crcErrors; + int overErrors; + // TSR 1/2 + int lateTXCollisions; + int lostOfCarrier; + int noCarrier; + int txCollisions; + int excCollisions; + + int notifyCount; + int readCount; + int writeCount; + _Statistics() { memset(this, 0, sizeof(_Statistics)); } + }; + public: - DavicomDevice(usb_device device, const char *description); - virtual ~DavicomDevice(); + DavicomDevice(usb_device device, DeviceInfo& Info); + ~DavicomDevice(); status_t InitCheck() { return fStatus; }; @@ -40,8 +121,8 @@ public: bool IsRemoved() { return fRemoved; }; status_t CompareAndReattach(usb_device device); -virtual status_t SetupDevice(bool deviceReplugged); - + status_t SetupDevice(bool deviceReplugged); + private: static void _ReadCallback(void *cookie, int32 status, void *data, uint32 actualLength); @@ -52,6 +133,16 @@ static void _NotifyCallback(void *cookie, int32 status, status_t _SetupEndpoints(); + status_t _StartDevice(); + status_t _StopDevice(); + status_t _OnNotify(uint32 actualLength); + status_t _GetLinkState(ether_link_state *state); + status_t _SetPromiscuousMode(bool bOn); + uint32 _EthernetCRC32(const uint8* buffer, size_t length); + status_t _ModifyMulticastTable(bool join, + ether_address_t *group); + status_t _ReadMACAddress(ether_address_t *address); + status_t _ReadRegister(uint8 reg, size_t size, uint8* buffer); status_t _WriteRegister(uint8 reg, size_t size, uint8* buffer); status_t _Write1Register(uint8 reg, uint8 buffer); @@ -60,32 +151,22 @@ static void _NotifyCallback(void *cookie, int32 status, status_t _InitMII(); status_t _EnableInterrupts(bool enable); -static const int kFrameSize = 1518; -static const size_t kRXHeaderSize = 3; -static const size_t kTXHeaderSize = 2; -protected: - /* overrides */ -virtual status_t StartDevice() ; -virtual status_t StopDevice(); -virtual status_t OnNotify(uint32 actualLength) ; -virtual status_t GetLinkState(ether_link_state *state) ; -virtual status_t SetPromiscuousMode(bool bOn); -virtual status_t ModifyMulticastTable(bool add, uint8 address); - status_t ReadMACAddress(ether_address_t *address); - + // device info + usb_device fDevice; + DeviceInfo fDeviceInfo; + ether_address_t fMACAddress; + // state tracking status_t fStatus; bool fOpen; bool fRemoved; - vint32 fInsideNotify; - usb_device fDevice; - uint16 fVendorID; - uint16 fProductID; -const char * fDescription; + bool fHasConnection; + bool fTXBufferFull; bool fNonBlocking; + vint32 fInsideNotify; - // pipes for notifications and data io + // pipes for notifications, data io and tx packet size usb_pipe fNotifyEndpoint; usb_pipe fReadEndpoint; usb_pipe fWriteEndpoint; @@ -98,15 +179,12 @@ const char * fDescription; int32 fStatusWrite; sem_id fNotifyReadSem; sem_id fNotifyWriteSem; - - uint8 * fNotifyBuffer; -static const size_t kNotifyBufferSize = 8; - - // connection data sem_id fLinkStateChangeSem; - ether_address_t fMACAddress; - bool fHasConnection; - bool fTXBufferFull; + + DM9601NotifyData* fNotifyData; + _Statistics fStats; + Vector fMulticastHashes; }; -#endif //_USB_Davicom_DEVICE_H_ +#endif // _USB_DAVICOM_DEVICE_H_ + diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/Driver.cpp b/src/add-ons/kernel/drivers/network/usb_davicom/Driver.cpp index 06a0ca299a..bdb2caede4 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/Driver.cpp +++ b/src/add-ons/kernel/drivers/network/usb_davicom/Driver.cpp @@ -1,60 +1,53 @@ /* - * Davicom 9601 USB 1.1 Ethernet Driver. - * Copyright 2009 Adrien Destugues + * Davicom DM9601 USB 1.1 Ethernet Driver. + * Copyright (c) 2008, 2011 Siarzhuk Zharski + * Copyright (c) 2009 Adrien Destugues * Distributed under the terms of the MIT license. * - * Heavily based on code of - * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. - * Copyright (c) 2008 S.Zharski - * Distributed under the terms of the MIT license. - * + * Heavily based on code of the * Driver for USB Ethernet Control Model devices * Copyright (C) 2008 Michael Lotz * Distributed under the terms of the MIT license. - * */ -#include -#include -#include -#ifdef HAIKU_TARGET_PLATFORM_HAIKU -#include // for mutex -#else -#include "BeOSCompatibility.h" // for pseudo mutex -#endif +#include "Driver.h" + +#include + +#include +#include #include "DavicomDevice.h" -#include "Driver.h" #include "Settings.h" + int32 api_version = B_CUR_DRIVER_API_VERSION; static const char *sDeviceBaseName = "net/usb_davicom/"; DavicomDevice *gDavicomDevices[MAX_DEVICES]; char *gDeviceNames[MAX_DEVICES + 1]; usb_module_info *gUSBModule = NULL; - -usb_support_descriptor gSupportedDevices[] = { - { 0, 0, 0, 0x0fe6, 0x8101}, // "Sunrising JP108" - { 0, 0, 0, 0x07aa, 0x9601}, // "Corega FEther USB-TXC" - { 0, 0, 0, 0x0a46, 0x9601}, // "Davicom USB-100" - { 0, 0, 0, 0x0a46, 0x6688}, // "ZT6688 USB NIC" - { 0, 0, 0, 0x0a46, 0x0268}, // "ShanTou ST268 USB NIC" - { 0, 0, 0, 0x0a46, 0x8515}, // "ADMtek ADM8515 USB NIC" - { 0, 0, 0, 0x0a47, 0x9601}, // "Hirose USB-100" - { 0, 0, 0, 0x0a46, 0x9000} // "DM9000E" -}; - mutex gDriverLock; -// auto-release helper class -class DriverSmartLock { -public: - DriverSmartLock() { mutex_lock(&gDriverLock); } - ~DriverSmartLock() { mutex_unlock(&gDriverLock); } + + +// IMPORTANT: keep entries sorted by ids to let the +// binary search lookup procedure work correctly !!! +DeviceInfo gSupportedDevices[] = { + { { { 0x01e1, 0x9601 } }, "Noname DM9601" }, + { { { 0x07aa, 0x9601 } }, "Corega FEther USB-TXC" }, + { { { 0x0a46, 0x0268 } }, "ShanTou ST268 USB NIC" }, + { { { 0x0a46, 0x6688 } }, "ZT6688 USB NIC" }, + { { { 0x0a46, 0x8515 } }, "ADMtek ADM8515 USB NIC" }, + { { { 0x0a46, 0x9000 } }, "DM9000E" }, + { { { 0x0a46, 0x9601 } }, "Davicom DM9601" }, + { { { 0x0a47, 0x9601 } }, "Hirose USB-100" }, + { { { 0x0fe6, 0x8101 } }, "Sunrising SR9600" }, + { { { 0x0fe6, 0x9700 } }, "Kontron DM9601" } }; + DavicomDevice * -create_davicom_device(usb_device device) +lookup_and_create_device(usb_device device) { const usb_device_descriptor *deviceDescriptor = gUSBModule->get_device_descriptor(device); @@ -64,18 +57,22 @@ create_davicom_device(usb_device device) return NULL; } -#define IDS(__vendor, __product) (((__vendor) << 16) | (__product)) + TRACE("trying %#06x:%#06x.\n", + deviceDescriptor->vendor_id, deviceDescriptor->product_id); - switch(IDS(deviceDescriptor->vendor_id, deviceDescriptor->product_id)) { - case IDS(0x0fe6, 0x8101): return new DavicomDevice(device, "Sunrising JP108"); - case IDS(0x07aa, 0x9601): return new DavicomDevice(device, "Corega FEther USB-TXC"); - case IDS(0x0a46, 0x9601): return new DavicomDevice(device, "Davicom USB-100"); - case IDS(0x0a46, 0x6688): return new DavicomDevice(device, "ZT6688 USB NIC"); - case IDS(0x0a46, 0x0268): return new DavicomDevice(device, "ShanTou ST268 USB NIC"); - case IDS(0x0a46, 0x8515): return new DavicomDevice(device, "ADMtek ADM8515 USB NIC"); - case IDS(0x0a47, 0x9601): return new DavicomDevice(device, "Hirose USB-100"); - case IDS(0x0a46, 0x9000): return new DavicomDevice(device, "DM9000E"); + // use binary search to lookup device in table + DeviceInfo::Id id = { { deviceDescriptor->vendor_id, + 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; } + + if(gSupportedDevices[right].Key() == id.fKey) + return new DavicomDevice(device, gSupportedDevices[right]); + return NULL; } @@ -85,7 +82,7 @@ usb_davicom_device_added(usb_device device, void **cookie) { *cookie = NULL; - DriverSmartLock driverLock; // released on exit + MutexLocker lock(gDriverLock); // released on exit // check if this is a replug of an existing device first for (int32 i = 0; i < MAX_DEVICES; i++) { @@ -101,7 +98,7 @@ usb_davicom_device_added(usb_device device, void **cookie) } // no such device yet, create a new one - DavicomDevice *davicomDevice = create_davicom_device(device); + DavicomDevice *davicomDevice = lookup_and_create_device(device); if (davicomDevice == 0) { return ENODEV; } @@ -140,7 +137,7 @@ usb_davicom_device_added(usb_device device, void **cookie) status_t usb_davicom_device_removed(void *cookie) { - DriverSmartLock driverLock; // released on exit + MutexLocker lock(gDriverLock); // released on exit DavicomDevice *device = (DavicomDevice *)cookie; for (int32 i = 0; i < MAX_DEVICES; i++) { @@ -161,7 +158,7 @@ usb_davicom_device_removed(void *cookie) } -//#pragma mark - +// #pragma mark - status_t @@ -180,9 +177,9 @@ init_driver() return status; load_settings(); - + TRACE_ALWAYS("%s\n", kVersion); - + for (int32 i = 0; i < MAX_DEVICES; i++) gDavicomDevices[i] = NULL; @@ -194,8 +191,15 @@ init_driver() &usb_davicom_device_removed }; - gUSBModule->register_driver(DRIVER_NAME, gSupportedDevices, - sizeof(gSupportedDevices) / sizeof(usb_support_descriptor), NULL); + const size_t count = _countof(gSupportedDevices); + static usb_support_descriptor sDescriptors[count] = {{ 0 }}; + + for(size_t i = 0; i < count; i++) { + sDescriptors[i].vendor = gSupportedDevices[i].VendorId(); + sDescriptors[i].product = gSupportedDevices[i].ProductId(); + } + + gUSBModule->register_driver(DRIVER_NAME, sDescriptors, count, NULL); gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); return B_OK; } @@ -221,7 +225,7 @@ uninit_driver() mutex_destroy(&gDriverLock); put_module(B_USB_MODULE_NAME); - + release_settings(); } @@ -229,7 +233,7 @@ uninit_driver() static status_t usb_davicom_open(const char *name, uint32 flags, void **cookie) { - DriverSmartLock driverLock; // released on exit + MutexLocker lock(gDriverLock); // released on exit *cookie = NULL; status_t status = ENODEV; @@ -280,9 +284,9 @@ static status_t usb_davicom_free(void *cookie) { DavicomDevice *device = (DavicomDevice *)cookie; - - DriverSmartLock driverLock; // released on exit - + + MutexLocker lock(gDriverLock); // released on exit + status_t status = device->Free(); for (int32 i = 0; i < MAX_DEVICES; i++) { if (gDavicomDevices[i] == device) { @@ -307,8 +311,8 @@ publish_devices() gDeviceNames[i] = NULL; } - DriverSmartLock driverLock; // released on exit - + MutexLocker lock(gDriverLock); // released on exit + int32 deviceCount = 0; for (int32 i = 0; i < MAX_DEVICES; i++) { if (gDavicomDevices[i] == NULL) @@ -320,7 +324,7 @@ publish_devices() TRACE("publishing %s\n", gDeviceNames[deviceCount]); deviceCount++; } else - TRACE_ALWAYS("Error: out of memory during allocating device name.\n"); + TRACE_ALWAYS("Error: out of memory during allocating dev.name.\n"); } gDeviceNames[deviceCount] = NULL; @@ -338,8 +342,8 @@ find_device(const char *name) usb_davicom_control, usb_davicom_read, usb_davicom_write, - NULL, /* select */ - NULL /* deselect */ + NULL, // select + NULL // deselect }; return &deviceHooks; diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/Driver.h b/src/add-ons/kernel/drivers/network/usb_davicom/Driver.h index 2a7bb3cfa1..0b4be0213e 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/Driver.h +++ b/src/add-ons/kernel/drivers/network/usb_davicom/Driver.h @@ -1,44 +1,35 @@ /* - * Davicom 9601 USB 1.1 Ethernet Driver. - * Copyright 2009 Adrien Destugues + * Davicom DM9601 USB 1.1 Ethernet Driver. + * Copyright (c) 2008, 2011 Siarzhuk Zharski + * Copyright (c) 2009 Adrien Destugues * Distributed under the terms of the MIT license. * - * Heavily based on code of : - * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. - * Copyright (c) 2008 S.Zharski - * Distributed under the terms of the MIT license. - * + * Heavily based on code of the * Driver for USB Ethernet Control Model devices * Copyright (C) 2008 Michael Lotz * Distributed under the terms of the MIT license. - * */ - #ifndef _USB_DAVICOM_DRIVER_H_ #define _USB_DAVICOM_DRIVER_H_ -#include -#include + #include #include -#include -#include -#include -#include -#include -#include + +// extra tracing in debug mode +//#define UDAV_TRACE #define DRIVER_NAME "usb_davicom" #define MAX_DEVICES 8 -const uint8 kInvalidRequest = 0xff; - -const char* const kVersion = "ver.0.8.3"; +const char* const kVersion = "ver.0.9.4"; extern usb_module_info *gUSBModule; + extern "C" { + status_t usb_davicom_device_added(usb_device device, void **cookie); status_t usb_davicom_device_removed(void *cookie); @@ -47,8 +38,9 @@ void uninit_driver(); const char **publish_devices(); device_hooks *find_device(const char *name); + } -#endif //_USB_DAVICOM_DRIVER_H_ +#endif // _USB_DAVICOM_DRIVER_H_ diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/Jamfile b/src/add-ons/kernel/drivers/network/usb_davicom/Jamfile index 8f06287b7d..486a067296 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/Jamfile +++ b/src/add-ons/kernel/drivers/network/usb_davicom/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers network usb_davicom ; SetSubDirSupportedPlatformsBeOSCompatible ; UsePrivateHeaders kernel net ; +UsePrivateKernelHeaders ; KernelAddon usb_davicom : Driver.cpp diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/Settings.cpp b/src/add-ons/kernel/drivers/network/usb_davicom/Settings.cpp index 311653d86a..028843f1cc 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/Settings.cpp +++ b/src/add-ons/kernel/drivers/network/usb_davicom/Settings.cpp @@ -1,32 +1,38 @@ /* - * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. - * Copyright (c) 2008 S.Zharski + * Davicom DM9601 USB 1.1 Ethernet Driver. + * Copyright (c) 2008, 2011 Siarzhuk Zharski * Distributed under the terms of the MIT license. - * - * Heavily based on code of the - * Driver for USB Ethernet Control Model devices - * Copyright (C) 2008 Michael Lotz - * Distributed under the terms of the MIT license. - * */ -#include // for mutex #include "Settings.h" +#include +#include +#include + +#include +#include + +#include "Driver.h" + + +mutex gLogLock; +static char *gLogFilePath = NULL; + bool gTraceOn = false; bool gTruncateLogFile = false; bool gAddTimeStamp = true; bool gTraceState = false; bool gTraceRX = false; bool gTraceTX = false; -static char *gLogFilePath = NULL; -mutex gLogLock; +bool gTraceStats = false; -static + +static void create_log() { - if(gLogFilePath == NULL) + if (gLogFilePath == NULL) return; int flags = O_WRONLY | O_CREAT | ((gTruncateLogFile) ? O_TRUNC : 0); @@ -35,23 +41,28 @@ void create_log() mutex_init(&gLogLock, DRIVER_NAME"-logging"); } -void load_settings() + +void +load_settings() { void *handle = load_driver_settings(DRIVER_NAME); - if(handle == 0) + if (handle == 0) return; gTraceOn = get_driver_boolean_parameter(handle, "trace", gTraceOn, true); - gTraceState = get_driver_boolean_parameter(handle, "trace_state", gTraceState, true); + gTraceState = get_driver_boolean_parameter(handle, + "trace_state", gTraceState, true); gTraceRX = get_driver_boolean_parameter(handle, "trace_rx", gTraceRX, true); gTraceTX = get_driver_boolean_parameter(handle, "trace_tx", gTraceTX, true); - gTruncateLogFile = get_driver_boolean_parameter(handle, "truncate_logfile", - gTruncateLogFile, true); - gAddTimeStamp = get_driver_boolean_parameter(handle, "add_timestamp", - gAddTimeStamp, true); - const char * logFilePath = get_driver_parameter(handle, "logfile", - NULL, "/var/log/"DRIVER_NAME".log"); - if(logFilePath != NULL) { + gTraceStats = get_driver_boolean_parameter(handle, + "trace_stats", gTraceStats, true); + gTruncateLogFile = get_driver_boolean_parameter(handle, + "reset_logfile", gTruncateLogFile, true); + gAddTimeStamp = get_driver_boolean_parameter(handle, + "add_timestamp", gAddTimeStamp, true); + const char * logFilePath = get_driver_parameter(handle, + "logfile", NULL, "/var/log/"DRIVER_NAME".log"); + if (logFilePath != NULL) { gLogFilePath = strdup(logFilePath); } @@ -60,39 +71,42 @@ void load_settings() create_log(); } -void release_settings() + +void +release_settings() { - if(gLogFilePath != NULL) { + if (gLogFilePath != NULL) { mutex_destroy(&gLogLock); free(gLogFilePath); } } + void usb_davicom_trace(bool force, const char* func, const char *fmt, ...) { - if(!(force || gTraceOn)) { -// return; + if (!(force || gTraceOn)) { + return; } va_list arg_list; static const char *prefix = "\33[33m"DRIVER_NAME":\33[0m"; static char buffer[1024]; char *buf_ptr = buffer; - if(gLogFilePath == NULL){ + if (gLogFilePath == NULL) { strcpy(buffer, prefix); buf_ptr += strlen(prefix); } - - if(gAddTimeStamp) { - bigtime_t time = system_time(); - uint32 msec = time / 1000; - uint32 sec = msec / 1000; - sprintf(buf_ptr, "%02ld.%02ld.%03ld:", - sec / 60, sec % 60, msec % 1000); - buf_ptr += strlen(buf_ptr); - } - if(func != NULL) { + if (gAddTimeStamp) { + bigtime_t time = system_time(); + uint32 msec = time / 1000; + uint32 sec = msec / 1000; + sprintf(buf_ptr, "%02ld.%02ld.%03ld:", + sec / 60, sec % 60, msec % 1000); + buf_ptr += strlen(buf_ptr); + } + + if (func != NULL) { sprintf(buf_ptr, "%s::", func); buf_ptr += strlen(buf_ptr); } @@ -101,7 +115,7 @@ void usb_davicom_trace(bool force, const char* func, const char *fmt, ...) vsprintf(buf_ptr, fmt, arg_list); va_end(arg_list); - if(gLogFilePath == NULL) { + if (gLogFilePath == NULL) { dprintf(buffer); return; } diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/Settings.h b/src/add-ons/kernel/drivers/network/usb_davicom/Settings.h index a4a456d258..b3e2531b7c 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/Settings.h +++ b/src/add-ons/kernel/drivers/network/usb_davicom/Settings.h @@ -1,40 +1,48 @@ /* - * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. - * Copyright (c) 2008 S.Zharski + * Davicom DM9601 USB 1.1 Ethernet Driver. + * Copyright (c) 2008, 2011 Siarzhuk Zharski * Distributed under the terms of the MIT license. - * - * Heavily based on code of the - * Driver for USB Ethernet Control Model devices - * Copyright (C) 2008 Michael Lotz - * Distributed under the terms of the MIT license. - * */ +#ifndef _USB_DAVICOM_SETTINGS_H_ +#define _USB_DAVICOM_SETTINGS_H_ -#ifndef _USB_DAVICOM_SETTINGS_H_ - #define _USB_DAVICOM_SETTINGS_H_ -#include +#ifdef _countof +#warning "_countof(...) WAS ALREADY DEFINED!!! Remove local definition!" +#undef _countof +#endif +#define _countof(array)(sizeof(array) / sizeof(array[0])) -#include "Driver.h" void load_settings(); void release_settings(); - void usb_davicom_trace(bool force, const char *func, const char *fmt, ...); + #define TRACE(x...) usb_davicom_trace(false, __func__, x) #define TRACE_ALWAYS(x...) usb_davicom_trace(true, __func__, x) + +#ifdef UDAV_TRACE + extern bool gTraceState; -#define TRACE_STATE(x...) usb_davicom_trace(gTraceState, NULL, x) - extern bool gTraceRX; -#define TRACE_RX(x...) usb_davicom_trace(gTraceRX, NULL, x) - extern bool gTraceTX; +extern bool gTraceStats; +#define TRACE_STATE(x...) usb_davicom_trace(gTraceState, NULL, x) +#define TRACE_STATS(x...) usb_davicom_trace(gTraceStats, NULL, x) +#define TRACE_RX(x...) usb_davicom_trace(gTraceRX, NULL, x) #define TRACE_TX(x...) usb_davicom_trace(gTraceTX, NULL, x) -#define TRACE_RET(result) usb_davicom_trace(false, __func__, \ - "Returns:%#010x\n", result); +#else + +#define TRACE_STATE(x...) +#define TRACE_STATS(x...) +#define TRACE_RX(x...) +#define TRACE_TX(x...) + +#endif + + +#endif // _USB_DAVICOM_SETTINGS_H_ -#endif /*_USB_DAVICOM_SETTINGS_H_*/ diff --git a/src/add-ons/kernel/drivers/network/usb_davicom/usb_davicom.settings b/src/add-ons/kernel/drivers/network/usb_davicom/usb_davicom.settings index 9399a7af5d..8953617ec7 100644 --- a/src/add-ons/kernel/drivers/network/usb_davicom/usb_davicom.settings +++ b/src/add-ons/kernel/drivers/network/usb_davicom/usb_davicom.settings @@ -1,25 +1,25 @@ ## -## ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. -## Copyright (c) 2008 S.Zharski +## Davicom DM9601 USB 1.1 Ethernet Driver. +## Copyright (c) 2008, 2011 Siarzhuk Zharski ## Distributed under the terms of the MIT license. ## ## trace [on|off] - activate additional tracing. ## default value: off -trace on +# trace on ## logfile [full path to private log file] ## default path value: /var/log/usb_davicom.log ## if disabled - all output goes to syslog -logfile /var/log/usb_davicom.log +# logfile /var/log/usb_davicom.log ## reset_logfile [on|off] - truncate private log file on driver/system restart ## default value: off ## -reset_logfile on +# reset_logfile on ## add_timestamp [on|off] - add time of writing the string in private log file. @@ -28,6 +28,12 @@ reset_logfile on # add_timestamp off +########################################################################### +## +## Following settings are usable only with special version of the driver +## compiled with UDAV_TRACE defined. Look into Driver.h for details. +## + ## trace_state [on|off] - activate state tracing. Statistic about of ## media state. ## default value: off @@ -45,3 +51,10 @@ reset_logfile on ## default value: off # trace_tx on + +## trace_stats [on|off] - activate tx/rx error counters tracing. +## +## default value: off + +# trace_stats on +