[haiku-commits] r34476 - in haiku/branches/developer: . siarzhuk siarzhuk/sis19x

  • From: zharik@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 3 Dec 2009 21:59:10 +0100 (CET)

Author: siarzhuk
Date: 2009-12-03 21:59:10 +0100 (Thu, 03 Dec 2009)
New Revision: 34476
Changeset: http://dev.haiku-os.org/changeset/34476/haiku

Added:
   haiku/branches/developer/siarzhuk/
   haiku/branches/developer/siarzhuk/sis19x/
   haiku/branches/developer/siarzhuk/sis19x/DataRing.cpp
   haiku/branches/developer/siarzhuk/sis19x/DataRing.h
   haiku/branches/developer/siarzhuk/sis19x/Device.cpp
   haiku/branches/developer/siarzhuk/sis19x/Device.h
   haiku/branches/developer/siarzhuk/sis19x/Driver.cpp
   haiku/branches/developer/siarzhuk/sis19x/Driver.h
   haiku/branches/developer/siarzhuk/sis19x/Jamfile
   haiku/branches/developer/siarzhuk/sis19x/MIIBus.cpp
   haiku/branches/developer/siarzhuk/sis19x/MIIBus.h
   haiku/branches/developer/siarzhuk/sis19x/Registers.h
   haiku/branches/developer/siarzhuk/sis19x/Settings.cpp
   haiku/branches/developer/siarzhuk/sis19x/Settings.h
   haiku/branches/developer/siarzhuk/sis7018/
   haiku/branches/developer/siarzhuk/usb_audio/
Log:
- personal branch created;
- usb_audio and sis7018 driver projects are branched for development and 
finishing;
- sis190/191 NIC driver added to personal branch for finishing.


Added: haiku/branches/developer/siarzhuk/sis19x/DataRing.cpp
===================================================================
--- haiku/branches/developer/siarzhuk/sis19x/DataRing.cpp                       
        (rev 0)
+++ haiku/branches/developer/siarzhuk/sis19x/DataRing.cpp       2009-12-03 
20:59:10 UTC (rev 34476)
@@ -0,0 +1,359 @@
+/*
+ *     SiS 190/191 NIC Driver.
+ *     Copyright (c) 2009 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ */
+
+#include "DataRing.h"
+
+#include <net/if_media.h>
+
+#include "Driver.h"
+#include "Settings.h"
+#include "Device.h"
+
+
+//
+//  Tx stuff implementation
+//
+
+template<> 
+void
+DataRing<TxDescriptor, TxDescriptorsCount>::_SetBaseAddress(void* address)
+{
+       fDevice->WritePCI32(TxBase, (uint32)address);
+}
+
+
+template<> 
+status_t
+DataRing<TxDescriptor, TxDescriptorsCount>::Write(const uint8* buffer, 
+                                                                               
                        size_t* numBytes)
+{
+       *numBytes = min_c(*numBytes, MaxFrameSize);
+
+       // wait for available tx descriptor
+       status_t status = acquire_sem_etc(fSemaphore, 1, B_TIMEOUT, 
TransmitTimeout);
+       if(status < B_NO_ERROR) {
+               TRACE_ALWAYS("Cannot acquire sem:%#010x\n", status);
+               return status;
+       }
+
+       cpu_status cpuStatus = disable_interrupts();
+       acquire_spinlock(&fSpinlock);
+
+       uint32 index = fHead % TxDescriptorsCount;
+       volatile TxDescriptor& Descriptor = fDescriptors[index];
+
+       // check if the buffer not owned by hardware
+       uint32 descriptorStatus = Descriptor.fCommandStatus;
+       if((descriptorStatus & TDC_TXOWN) == 0) {
+
+               // copy data into buffer
+               status = user_memcpy((void*)fBuffers[index], buffer, *numBytes);
+
+               // take care about tx descriptor
+               Descriptor.fPacketSize = *numBytes;
+               Descriptor.fEOD |= *numBytes;
+               Descriptor.fCommandStatus = TDC_PADEN | TDC_CRCEN 
+                                                                               
| TDC_DEFEN | TDC_THOL3 | TDC_TXINT;
+               if((fDevice->LinkState().media & IFM_HALF_DUPLEX) != 0) {
+                       Descriptor.fCommandStatus |= TDC_BKFEN | TDC_CRSEN | 
TDC_COLSEN;
+                       if(fDevice->LinkState().speed == 1000000) {
+                               Descriptor.fCommandStatus |= TDC_BSTEN | 
TDC_EXTEN;
+                       }
+               }
+
+               Descriptor.fCommandStatus |= TDC_TXOWN;
+               fHead++;
+       }
+
+       fDevice->WritePCI32(TxControl, fDevice->ReadPCI32(TxControl) | 
TxControlPoll);
+
+       release_spinlock(&fSpinlock);
+       restore_interrupts(cpuStatus);
+
+       // if buffer was owned by hardware - notify about it
+       if((descriptorStatus & TDC_TXOWN) != 0) {
+               release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
+               TRACE_ALWAYS("Buffer is still owned by the card.\n");
+               status = B_BUSY;
+       }
+
+       //      TRACE_ALWAYS("Write:%d bytes:%#010x!\n", *numBytes, status);
+
+       return status;
+}
+
+
+template<>
+int32
+DataRing<TxDescriptor, TxDescriptorsCount>::InterruptHandler()
+{
+       uint32 releasedFrames = 0;
+
+       acquire_spinlock(&fSpinlock);
+
+       while(fTail != fHead) {
+
+               uint32 index = fTail % TxDescriptorsCount;
+               volatile TxDescriptor& Descriptor = fDescriptors[index];
+               uint32 status = Descriptor.fCommandStatus;
+
+#if STATISTICS
+               fDevice->fStatistics.PutTxStatus(status, 
Descriptor.fEOD/*PacketSize*/);
+#endif
+
+               /*if(status & TDC_TXOWN) {
+               //fDevice->WritePCI32(TxControl, fDevice->ReadPCI32(TxControl) 
| TxControlPoll);
+               break; //still owned by hardware - poll again ...
+               }*/
+
+               Descriptor.fPacketSize = 0;
+               Descriptor.fCommandStatus = 0;
+               Descriptor.fEOD &= TxDescriptorEOD;
+
+               releasedFrames++;
+
+               fTail++;
+       }
+
+       release_spinlock(&fSpinlock);
+
+       if(releasedFrames > 0) {
+               release_sem_etc(fSemaphore, releasedFrames, 
B_DO_NOT_RESCHEDULE);
+               return B_INVOKE_SCHEDULER;
+       }
+
+       return B_HANDLED_INTERRUPT;
+}
+
+
+template<>
+void 
+DataRing<TxDescriptor, TxDescriptorsCount>::CleanUp()
+{
+       cpu_status cpuStatus = disable_interrupts();
+       acquire_spinlock(&fSpinlock);
+
+       fDevice->WritePCI32(IntMask, 0 );
+
+       uint32 txControl = fDevice->ReadPCI32(TxControl);
+       txControl &= ~(TxControlPoll | TxControlEnable);
+       fDevice->WritePCI32(TxControl, txControl);
+
+       spin(50);
+
+       uint32 droppedFrames = fHead - fTail;
+       /*
+          for(;fHead != fTail; fHead--, droppedFrames++) {
+          uint32 index = fHead % TxDescriptorsCount;
+          volatile TxDescriptor& Descriptor = fDescriptors[index];
+
+          / *  if(Descriptor.fCommandStatus & TDC_TXOWN) {
+          continue; //still owned by hardware - ignore?
+          }* /
+
+          Descriptor.fPacketSize = 0;
+          Descriptor.fCommandStatus = 0;
+          Descriptor.fEOD &= TxDescriptorEOD;
+          }
+          */
+#if STATISTICS
+       fDevice->fStatistics.fDropped += droppedFrames;
+#endif
+
+       fHead = fTail = 0;
+
+       for(size_t i = 0; i < TxDescriptorsCount; i++) {
+               fDescriptors[i].fPacketSize = 0;
+               fDescriptors[i].fCommandStatus = 0;
+               fDescriptors[i].fEOD &= TxDescriptorEOD;;
+       }
+
+       //      uint32 txBase = fDevice->ReadPCI32(TxBase);
+       //uint32 index = fHead % TxDescriptorsCount;
+       //fDevice->WritePCI32(TxStatus, txBase + 8 /*+ index * 
sizeof(TxDescriptor)*/);
+       //fDevice->WritePCI32(TxBase, txBase);
+
+       if(droppedFrames > 0) {
+               release_sem_etc(fSemaphore, droppedFrames, B_DO_NOT_RESCHEDULE);
+       }
+
+       txControl |= TxControlEnable;
+       fDevice->WritePCI32(TxControl, txControl);
+
+       fDevice->WritePCI32(IntMask, knownInterruptsMask);
+
+       release_spinlock(&fSpinlock);
+       restore_interrupts(cpuStatus);
+}
+
+
+template<>
+void 
+DataRing<TxDescriptor, TxDescriptorsCount>::Dump()
+{
+       int32 count = 0;
+       get_sem_count(fSemaphore, &count);
+       kprintf("Tx:[count:%ld] head:%lu tail:%lu dirty:%lu\n", 
+                       count, fHead, fTail, fHead - fTail);
+
+       kprintf("\tPktSize\t\tCmdStat\t\tBufPtr\t\tEOD\n");
+
+       for(size_t i = 0; i < TxDescriptorsCount; i++) {
+               volatile TxDescriptor& D = fDescriptors[i];
+               char marker = ((fTail % TxDescriptorsCount) == i) ? '=' : ' ';
+               marker = ((fHead % TxDescriptorsCount) == i) ? '>' : marker;
+               kprintf("%02lx %c\t%08lx\t%08lx\t%08lx\t%08lx\n", i, marker,
+                               D.fPacketSize, D.fCommandStatus, 
D.fBufferPointer, D.fEOD);
+       }
+}
+
+
+//
+//  Rx stuff implementation
+//
+
+template<> 
+void
+DataRing<RxDescriptor, RxDescriptorsCount>::_SetBaseAddress(void* address)
+{
+       fDevice->WritePCI32(RxBase, (uint32)address);
+}
+
+
+template<> 
+int32
+DataRing<RxDescriptor, RxDescriptorsCount>::InterruptHandler()
+{
+       uint32 receivedFrames = 0;
+
+       acquire_spinlock(&fSpinlock);
+
+       uint32 index = fHead % RxDescriptorsCount;
+       uint32 status = fDescriptors[index].fStatusSize;
+       uint32 info   = fDescriptors[index].fPacketInfo;
+
+       while(((info & RDI_RXOWN) == 0) && (fHead - fTail) <= 
RxDescriptorsCount) {
+
+#if STATISTICS
+               fDevice->fStatistics.PutRxStatus(status);
+#endif
+               receivedFrames++;
+
+               fHead++;
+
+               index = fHead % RxDescriptorsCount;
+               status = fDescriptors[index].fStatusSize;
+               info = fDescriptors[index].fPacketInfo;
+       }
+
+       release_spinlock(&fSpinlock);
+
+       if(receivedFrames > 0) {
+               release_sem_etc(fSemaphore, receivedFrames, 
B_DO_NOT_RESCHEDULE);
+               return B_INVOKE_SCHEDULER;
+       }
+
+       return B_UNHANDLED_INTERRUPT; //XXX: ????
+}
+
+
+template<> 
+status_t
+DataRing<RxDescriptor, RxDescriptorsCount>::Read(uint8* buffer, size_t* 
numBytes)
+{
+       status_t rstatus = B_ERROR;
+
+       do {
+               // wait for received rx descriptor
+               uint32 flags = B_CAN_INTERRUPT | fDevice->fBlockFlag;
+               status_t acquireStatus = acquire_sem_etc(fSemaphore, 1, flags, 
0);
+               if(acquireStatus != B_NO_ERROR) {
+                       TRACE_ALWAYS("Cannot acquire sem:%#010x\n", 
acquireStatus);
+                       return acquireStatus;
+               }
+
+               cpu_status cpuStatus = disable_interrupts();
+               acquire_spinlock(&fSpinlock);
+
+               uint32 index = fTail % RxDescriptorsCount;  
+               volatile RxDescriptor& Descriptor = fDescriptors[index];
+
+               // check if the buffer owned by hardware - should never occure!
+               uint32 status = Descriptor.fStatusSize;
+               uint32 info = Descriptor.fPacketInfo;
+               uint16 count = (status & 0x7f000000) >> 24;
+               bool isFrameValid = false;
+               //status_t rstatus = B_ERROR;
+
+               if((info & RDI_RXOWN) == 0) {
+                       isFrameValid = (status & rxErrorStatusBits) == 0 && 
(status & RDS_CRCOK) != 0;
+                       if(isFrameValid) {
+                               // frame is OK - copy it into buffer
+                               *numBytes = status & RDS_SIZE;
+                               rstatus = user_memcpy(buffer, 
(void*)fBuffers[index], *numBytes);
+                       } 
+               }
+
+               // take care about rx descriptor
+               Descriptor.fStatusSize = 0;
+               Descriptor.fPacketInfo = RDI_RXOWN | RDI_RXINT;
+
+               fTail++;
+
+               release_spinlock(&fSpinlock);
+               restore_interrupts(cpuStatus);
+
+               if((info & RDI_RXOWN) != 0) {
+                       TRACE_ALWAYS("Buffer is still owned by the card.\n");
+               } else {
+                       if(!isFrameValid) {
+                               TRACE_ALWAYS("Invalid frame received, 
status:%#010x;info:%#010x!\n", status, info);
+                       } /*else {
+                               TRACE_ALWAYS("Read:%d 
bytes;st:%#010x;info:%#010x!\n", *numBytes, status, info);
+                               } */
+                       // we have free rx buffer - reenable potentially idle 
state machine
+                       fDevice->WritePCI32(RxControl, 
fDevice->ReadPCI32(RxControl) | RxControlPoll | RxControlEnable);
+               }
+
+               if(count > 1) {
+                       TRACE_ALWAYS("Warning:Descriptors count is %d!\n", 
count);
+               }
+
+       } while(rstatus != B_OK);
+
+       return rstatus;
+}
+
+
+template<> 
+void 
+DataRing<RxDescriptor, RxDescriptorsCount>::Dump()
+{
+       int32 count = 0;
+       get_sem_count(fSemaphore, &count);
+       kprintf("Rx:[count:%ld] head:%lu tail:%lu dirty:%lu\n", 
+                       count, fHead, fTail, fHead - fTail);
+
+       for(size_t i = 0; i < 2; i++) {
+               kprintf("\tStatSize\tPktInfo\t\tBufPtr\t\tEOD      %c", 
+                               i == 0 ? '|' : '\n');
+       }
+
+       for(size_t i = 0; i < RxDescriptorsCount / 2; i++) {
+               const char* mask = "%02lx %c\t%08lx\t%08lx\t%08lx\t%08lx %c";
+
+               for(size_t ii = 0; ii < 2; ii++) {
+                       size_t index = ii == 0 ? i : (i + RxDescriptorsCount / 
2);
+                       volatile RxDescriptor& D = fDescriptors[index];
+                       char marker = ((fTail % RxDescriptorsCount) == index) ? 
'=' : ' ';
+                       marker = ((fHead % RxDescriptorsCount) == index) ? '>' 
: marker;
+                       kprintf(mask, index, marker, D.fStatusSize, 
D.fPacketInfo, 
+                                       D.fBufferPointer, D.fEOD, ii == 0 ? '|' 
: '\n' );
+               }
+       }
+}
+

Added: haiku/branches/developer/siarzhuk/sis19x/DataRing.h
===================================================================
--- haiku/branches/developer/siarzhuk/sis19x/DataRing.h                         
(rev 0)
+++ haiku/branches/developer/siarzhuk/sis19x/DataRing.h 2009-12-03 20:59:10 UTC 
(rev 34476)
@@ -0,0 +1,174 @@
+/*
+ *     SiS 190/191 NIC Driver.
+ *     Copyright (c) 2009 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ */
+#ifndef _SiS19X_DATARING_H_
+#define _SiS19X_DATARING_H_
+
+
+#include <KernelExport.h>
+
+#include "Driver.h"
+#include "Registers.h"
+#include "Settings.h"
+
+
+class Device;
+
+template<typename __type, uint32 __count>
+class DataRing {
+public:
+                                               DataRing(Device* device, bool 
isTx); 
+                                               ~DataRing();
+
+                       status_t        Open();
+                       void            CleanUp();
+                       status_t        Close();
+
+                       status_t        Read(uint8* buffer, size_t* numBytes);
+                       status_t        Write(const uint8* buffer, size_t* 
numBytes);
+
+                       int32           InterruptHandler();
+
+                       void            Trace();
+                       void            Dump();
+
+private:
+                       status_t        _InitArea();
+                       void            _SetBaseAddress(void* address);
+                       
+                       Device*         fDevice;
+                       bool            fIsTx;
+                       status_t        fStatus;
+                       area_id         fArea;
+                       int32           fSpinlock;
+                       sem_id          fSemaphore;
+                       uint32          fHead;
+                       uint32          fTail;
+                                               
+       volatile __type*        fDescriptors;
+       volatile uint8*         fBuffers[__count];
+};
+
+
+
+template<typename __type, uint32 __count>
+DataRing<__type, __count>::DataRing(Device* device, bool isTx)
+                                                       : 
+                                                       fDevice(device),
+                                                       fIsTx(isTx),
+                                                       fStatus(B_NO_INIT),
+                                                       fArea(-1),
+                                                       fSpinlock(0),
+                                                       fSemaphore(0),
+                                                       fHead(0),
+                                                       fTail(0),
+                                                       fDescriptors(NULL) 
+{
+       memset(fBuffers, 0, sizeof(fBuffers));
+}
+
+
+template<typename __type, uint32 __count>
+DataRing<__type, __count>::~DataRing() 
+{
+       delete_sem(fSemaphore);
+       delete_area(fArea);
+}
+
+
+template<typename __type, uint32 __count>
+status_t 
+DataRing<__type, __count>::_InitArea() 
+{
+       // create area for xfer data descriptors and buffers...
+       // 
+       // layout is following: 
+       // | descriptors array |   buffers array   |
+       //
+       uint32 buffSize = BufferSize + sizeof(__type);
+       buffSize *=     __count; 
+       buffSize = (buffSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
+       fArea = create_area(DRIVER_NAME "_data_ring", (void**)&fDescriptors, 
+                       B_ANY_KERNEL_ADDRESS, buffSize, 
+                       B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
+       if(fArea < 0) {
+               TRACE_ALWAYS("Cannot create area with size %d bytes:%#010x\n", 
+                               buffSize, fArea);
+               return fStatus = fArea;
+       }       
+
+       // setup descriptors and buffers layout 
+       uint8* buffersData = (uint8*)fDescriptors;
+       uint32 descriptorsSize = sizeof(__type) * __count;
+       buffersData += descriptorsSize;
+
+       physical_entry table = {0};
+
+       for(size_t i = 0; i < __count; i++) {
+               fBuffers[i] = buffersData + BufferSize * i; 
+
+               get_memory_map((void*)fBuffers[i], BufferSize, &table, 1);
+               fDescriptors[i].Init(table.address, i == (__count - 1));
+       }
+
+       get_memory_map((void*)fDescriptors, descriptorsSize, &table, 1);
+
+       _SetBaseAddress(table.address);
+
+       return fStatus = B_OK;
+}
+
+
+template<typename __type, uint32 __count>
+status_t
+DataRing<__type, __count>::Open()
+{
+       if(fStatus != B_OK && _InitArea() != B_OK) {
+               return fStatus;
+       }
+
+       if(fIsTx) {
+               fSemaphore = create_sem(__count, "SiS19X Transmit");
+       } else {
+               fSemaphore = create_sem(0, "SiS19X Receive");
+       }
+
+       if(fSemaphore < 0) {
+               TRACE_ALWAYS("Cannot create %s semaphore:%#010x\n", 
+                               fIsTx ? "transmit" : "receive", fSemaphore);
+               return fStatus = fSemaphore;
+       }
+
+       set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
+
+       return fStatus = B_OK;
+}
+
+
+template<typename __type, uint32 __count>
+status_t
+DataRing<__type, __count>::Close()
+{
+       delete_sem(fSemaphore);
+       fSemaphore = 0;
+
+       return B_OK;
+}
+
+
+template<typename __type, uint32 __count>
+void
+DataRing<__type, __count>::Trace()
+{
+       int32 count = 0;
+       get_sem_count(fSemaphore, &count);
+       TRACE_ALWAYS("%s:[count:%d] n:%lu l:%lu d:%lu\n", fIsTx ? "Tx" : "Rx",
+                       count, fHead, fTail, fHead - fTail);
+}
+
+
+#endif //_SiS19X_DATARING_H_
+

Added: haiku/branches/developer/siarzhuk/sis19x/Device.cpp
===================================================================
--- haiku/branches/developer/siarzhuk/sis19x/Device.cpp                         
(rev 0)
+++ haiku/branches/developer/siarzhuk/sis19x/Device.cpp 2009-12-03 20:59:10 UTC 
(rev 34476)
@@ -0,0 +1,624 @@
+/*
+ *     SiS 190/191 NIC Driver.
+ *     Copyright (c) 2009 S.Zharski <imker@xxxxxx>
+ *     Distributed under the terms of the MIT license.
+ *
+ */
+
+
+#include "Device.h"
+
+#include <net/if_media.h>
+#include <lock.h>
+
+#include "Driver.h"
+#include "Settings.h"
+#include "Registers.h"
+
+
+Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo)
+               :       
+               fStatus(B_ERROR),
+               fPCIInfo(PCIInfo),
+               fInfo(DeviceInfo),
+               fIOBase(0),
+               fHWSpinlock(0),
+               fInterruptsNest(0),
+               fFrameSize(MaxFrameSize),
+               fMII(this),
+               fOpen(false),
+               fBlockFlag(0),          
+               fLinkStateChangeSem(-1),
+               fHasConnection(false),
+               fTxDataRing(this, true),
+               fRxDataRing(this, false)
+{ 
+       memset((struct timer*)this, 0, sizeof(struct timer));   
+
+       uint32 cmdRegister = gPCIModule->read_pci_config(PCIInfo.bus, 
+                       PCIInfo.device, PCIInfo.function, PCI_command, 2);
+       TRACE_ALWAYS("cmdRegister:%#010x\n", cmdRegister);
+       cmdRegister |= PCI_command_io | PCI_command_memory | PCI_command_master;
+       gPCIModule->write_pci_config(PCIInfo.bus, PCIInfo.device,
+                       PCIInfo.function, PCI_command, 2, cmdRegister);
+
+       fIOBase = PCIInfo.u.h0.base_registers[1];
+       TRACE_ALWAYS("fIOBase:%#010x\n", fIOBase);
+
+       fStatus = B_OK;
+}
+
+
+Device::~Device()
+{
+}
+
+
+status_t
+Device::Open(uint32 flags)
+{
+       TRACE("flags:%x\n", flags);
+       if (fOpen) {
+               TRACE_ALWAYS("An attempt to re-open device ignored.\n");
+               return B_BUSY;
+       }
+
+       status_t result = fMII.Init();
+       if(result != B_OK) {
+               TRACE_ALWAYS("MII initialization failed: %#010x.\n", result);
+               return result;
+       }
+
+       _Reset();
+
+       if((fMII.LinkState().media & IFM_ACTIVE) == 0/*fNegotiationComplete*/) {
+               fMII.UpdateLinkState();
+       } 
+
+       fMII.SetMedia();
+
+       WritePCI32(RxMACAddress, 0);
+       _InitRxFilter();
+
+       fRxDataRing.Open();
+       fTxDataRing.Open();
+
+       if(atomic_add(&fInterruptsNest, 1) == 0) {
+               install_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 
+                               InterruptHandler, this, 0);
+               TRACE("Interrupt handler installed at line %d.\n", 
+                               fPCIInfo.u.h0.interrupt_line);
+       }
+
+       _SetRxMode(false);
+
+       // enable al known interrupts
+       WritePCI32(IntMask, knownInterruptsMask);
+
+       // enable Rx and Tx
+       uint32 control = ReadPCI32(RxControl);
+       control |= RxControlEnable | RxControlPoll;
+       WritePCI32(RxControl, control);
+
+       control = ReadPCI32(TxControl);
+       control |= TxControlEnable /*| TxControlPoll*/;
+       WritePCI32(TxControl, control);
+
+       add_timer((timer*)this, _TimerHandler, 1000000LL, B_PERIODIC_TIMER);
+
+       //fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
+       fOpen = true;
+       return B_OK; 
+}
+
+
+status_t
+Device::Close()
+{
+       TRACE("closed!\n");
+
+       // disable interrupts
+       WritePCI32(IntMask, 0);
+       spin(2000);
+
+       // Stop Tx/Rx status machine
+       uint32 status = ReadPCI32(IntControl);
+       status |= 0x00008000;
+       WritePCI32(IntControl, status);
+       spin(50);
+       status &= ~0x00008000;
+       WritePCI32(IntControl, status);
+
+       if(atomic_add(&fInterruptsNest, -1) == 1) {
+               remove_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 
+                               InterruptHandler, this);
+               TRACE("Interrupt handler at line %d uninstalled.\n", 
+                               fPCIInfo.u.h0.interrupt_line);
+       }
+
+       fRxDataRing.Close();
+       fTxDataRing.Close();
+
+       cancel_timer((timer*)this);
+
+       TRACE("timer cancelled\n");
+
+       fOpen = false;
+
+       return B_OK;
+}
+
+
+status_t
+Device::Free()
+{
+       //      fRxDataRing.Free();
+       //      fTxDataRing.Free();
+
+       TRACE("freed\n");
+       return B_OK;
+}
+
+
+status_t
+Device::Read(uint8 *buffer, size_t *numBytes)
+{
+       return fRxDataRing.Read(buffer, numBytes);
+}
+
+
+status_t
+Device::Write(const uint8 *buffer, size_t *numBytes)
+{
+       if((fMII.LinkState().media & IFM_ACTIVE) == 0) {
+               TRACE_ALWAYS("Write failed. link is inactive!\n");
+               return B_OK; // return OK because of well-known DHCP 
"moustreap"!
+       }
+
+       return fTxDataRing.Write(buffer, numBytes);
+}
+
+
+status_t
+Device::Control(uint32 op, void *buffer, size_t length)
+{
+       switch (op) {
+               case ETHER_INIT:
+                       TRACE("ETHER_INIT\n");
+                       return B_OK;
+
+               case ETHER_GETADDR:
+                       memcpy(buffer, &fMACAddress, sizeof(fMACAddress));
+                       TRACE("ETHER_GETADDR 
%#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_OK;
+
+               case ETHER_GETFRAMESIZE:
+                       *(uint32 *)buffer = fFrameSize;
+                       TRACE("ETHER_ETHER_GETFRAMESIZE:%d\n",fFrameSize);
+                       return B_OK;
+
+               case ETHER_NONBLOCK: 
+                       TRACE("ETHER_NONBLOCK\n");
+                       fBlockFlag = *((uint32*)buffer) ? B_TIMEOUT : 0;
+                       return B_OK;
+
+               case ETHER_SETPROMISC: 
+                       TRACE("ETHER_SETPROMISC\n");
+                       return _SetRxMode(*((uint8*)buffer));
+
+               case ETHER_ADDMULTI:
+               case ETHER_REMMULTI:
+                       TRACE_ALWAYS("Multicast operations are not 
implemented.\n");
+                       return B_ERROR;
+
+               case ETHER_SET_LINK_STATE_SEM:
+                       fLinkStateChangeSem = *(sem_id *)buffer;
+                       TRACE_ALWAYS("ETHER_SET_LINK_STATE_SEM\n");
+                       return B_OK;
+
+               case ETHER_GET_LINK_STATE:
+                       return GetLinkState((ether_link_state *)buffer);
+
+               default:
+                       TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op);
+       }
+
+       return B_DEV_INVALID_IOCTL;
+}
+
+
+status_t
+Device::SetupDevice()
+{
+       ether_address address;
+       status_t result = ReadMACAddress(address);
+       if(result != B_OK) {
+               TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result);
+               return result;
+       }
+
+       TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n",
+                       address.ebyte[0], address.ebyte[1], address.ebyte[2], 
+                       address.ebyte[3], address.ebyte[4], address.ebyte[5]);
+
+       fMACAddress = address;
+
+       uint16 info = _ReadEEPROM(EEPROMInfo);
+       fMII.SetRGMII((info & 0x0080) != 0);
+
+       TRACE("RGMII is '%s'. EEPROM info word:%#06x.\n",
+                       fMII.HasRGMII() ? "on" : "off", info);
+
+       fMII.SetGigagbitCapable(fInfo.Id() == SiS191);
+
+       return B_OK; 
+}
+
+
+void
+Device::TeardownDevice()
+{
+
+}
+
+
+uint8 
+Device::ReadPCI8(int offset)
+{
+       return gPCIModule->read_io_8(fIOBase + offset);
+}
+
+
+uint16
+Device::ReadPCI16(int offset)
+{
+       return gPCIModule->read_io_16(fIOBase + offset);
+}
+
+
+uint32
+Device::ReadPCI32(int offset)
+{
+       return gPCIModule->read_io_32(fIOBase + offset);
+}
+
+
+void
+Device::WritePCI8(int offset, uint8  value)
+{
+       gPCIModule->write_io_8(fIOBase + offset, value);
+}
+
+
+void
+Device::WritePCI16(int offset, uint16 value)
+{
+       gPCIModule->write_io_16(fIOBase + offset, value);
+}
+
+
+void
+Device::WritePCI32(int offset, uint32 value)
+{
+       gPCIModule->write_io_32(fIOBase + offset, value);
+}
+
+/*
+   cpu_status
+   Device::Lock() 
+   {
+   cpu_status st = disable_interrupts();
+   acquire_spinlock(&fHWSpinlock);
+   return st;
+   }
+
+
+   void
+   Device::Unlock(cpu_status st) 
+   {
+   release_spinlock(&fHWSpinlock);
+   restore_interrupts(st);
+   }
+   */
+
+int32
+Device::InterruptHandler(void *InterruptParam)
+{
+       Device *device = (Device*)InterruptParam;
+       if(device == 0) {
+               TRACE_ALWAYS("Invalid parameter in the interrupt handler.\n");
+               return B_HANDLED_INTERRUPT;
+       }
+
+       int32 result = B_UNHANDLED_INTERRUPT;
+
+       acquire_spinlock(&device->fHWSpinlock);
+
+       // disable interrupts...
+       device->WritePCI32(IntMask, 0);
+
+       //int maxWorks = 40;
+
+       //do {
+       uint32 status = device->ReadPCI32(IntSource);
+
+#if STATISTICS
+       device->fStatistics.PutStatus(status);
+#endif
+       device->WritePCI32(IntSource, status);
+
+       if((status & knownInterruptsMask) != 0) {
+               //break;
+               //}
+
+               // XXX: ????
+               result = B_HANDLED_INTERRUPT;
+
+       if((status & (/*INT_TXIDLE |*/ INT_TXDONE)) != 0 ) {
+               result = device->fTxDataRing.InterruptHandler();
+       }
+
+       if((status & (/*INT_RXIDLE |*/ INT_RXDONE)) != 0 ) {
+               result = device->fRxDataRing.InterruptHandler();
+       }
+
+       /*if((status & (INT_LINK)) != 0 ) {
+       //if(!device->fMII.isLinkUp()) {
+       device->fTxDataRing.CleanUp();
+       //}
+       }*/
+       }
+
+       //} while(--maxWorks > 0);
+
+       // enable interrupts...
+       device->WritePCI32(IntMask, knownInterruptsMask);
+
+       release_spinlock(&device->fHWSpinlock);
+
+       return result;
+}
+
+
+status_t
+Device::GetLinkState(ether_link_state *linkState)
+{
+       status_t result = user_memcpy(linkState, &fMII.LinkState(), 
+                       sizeof(ether_link_state));
+
+#if STATISTICS
+       fStatistics.Trace();
+       fRxDataRing.Trace();
+       fTxDataRing.Trace();
+       uint32 rxControl = ReadPCI32(RxControl);
+       uint32 txControl = ReadPCI32(TxControl);
+       TRACE_ALWAYS("RxControl:%#010x;TxControl:%#010x\n", rxControl, 
txControl);
+#endif
+
+       TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", 
+                       (linkState->media & IFM_ACTIVE) ? "active" : "inactive",
+                       linkState->speed / 1000,
+                       (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
+
+       return result;
+}
+
+
+status_t
+Device::_SetRxMode(bool isPromiscuousModeOn)
+{
+       // clean the Rx MAC Control register
+       WritePCI16(RxMACControl, (ReadPCI16(RxMACControl) & ~RXM_Mask));
+
+       uint16 rxMode = RXM_Broadcast | RXM_Multicast | RXM_Physical;
+       if(isPromiscuousModeOn) {
+               rxMode |= RXM_AllPhysical;
+       }
+
+       // set multicast filters
+       WritePCI32(RxHashTable, 0xffffffff);
+       WritePCI32(RxHashTable + 4, 0xffffffff);
+
+       // update rx mode
+       WritePCI16(RxMACControl, ReadPCI16(RxMACControl) | rxMode);
+
+       return B_OK; 
+}
+
+
+int32
+Device::_TimerHandler(struct timer* timer)
+{
+       Device* device = (Device*)timer;
+
+       bool linkChanged = false;
+       int32 result = device->fMII.TimerHandler(&linkChanged);
+
+       if(linkChanged) {
+               if(device->fMII.IsLinkUp()) {
+                       device->fTxDataRing.CleanUp();
+                       //device->WritePCI32(IntControl, 0x8000);
+                       //device->ReadPCI32(IntControl);
+                       //spin(100);
+                       //device->WritePCI32(IntControl, 0x0);
+               } 
+       }
+
+       if(linkChanged && device->fLinkStateChangeSem > B_OK) {

[... truncated: 1856 lines follow ...]

Other related posts:

  • » [haiku-commits] r34476 - in haiku/branches/developer: . siarzhuk siarzhuk/sis19x - zharik