VIARhine network device example driver

VIARhine network device example driver:

        #include "devinter.h"
        #include "events.h"
        #include "skyos.h"
        #include "pci.h"
        #include "net/ksock.h"
        #include "dd_net.h"

        unsigned int uiDeviceIndex = 0;

        #define DEVICE_NAME "VIA Rhine II"
DEFINE_MODULE_DATA;

/* removed, obsolete
        MODULE_SHORT_DESCRIPTION("VIA Rhine II network card device driver");
        MODULE_VERSION("1.0");
        MODULE_LONG_DESCRIPTION("");
        MODULE_AUTHOR("Robert Szeleney");
        MODULE_DATE("28.07.2002");
        MODULE_DEPEND("tcpip");
*/
        static DMHANDLE hDriver;

        #define write8(  offset , value)        outportb ((offset), (value) )
        #define write16( offset , value)        outportw ((offset), (value) )
        #define write32( offset , value)        outportl ((offset), (value) )
                
        #define read8(  offset )                        inportb((offset))
        #define read16( offset )                        inportw((offset))
        #define read32( offset )                        inportl((offset))


        typedef struct sPciInfo
        {
                const char *name;
                unsigned short  vendor_id, device_id;
        } sPciInfo; 

        static sPciInfo pPciInfo[] =
        {
        { "VIA VT3042 Rhine", 0x1106 ,0x3043},
        { "VIA VT6102 Rhine-II", 0x1106, 0x3065},
        { "VIA VT86C100A Rhine-II", 0x1106, 0x6100},
        { "VIA VT6105M/LOM Rhine-III",0x1106, 0x3106},
        { "VIA VT6105M Rhine-III Management Adaptor"},
        {0,},                                           
        }; 

        #define TX_BUFFERS        8
        #define RX_BUFFERS        16

        #define BUFFER_SIZE       2048L              // Enough to hold a 1536 Frame     
        #define MAX_FRAME_SIZE    1536               // 1536                            
        #define MAX_MULTI         32                 // Hardware Related, Do not change 

        #define TRANSMIT_TIMEOUT       ((bigtime_t)10000)   // 1/100 Second    
        #define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)1000000)     // One Second      

        #define MIN_PCI_LATENCY   64

        enum viarhine_register_offsets
        {
                StationAddr      = 0x00,
                RxConfig         = 0x06,
                TxConfig         = 0x07,
                ChipCmd          = 0x08,
                IntrStatus       = 0x0C,
                IntrEnable       = 0x0E,
                MulticastFilter0 = 0x10,
                MulticastFilter1 = 0x14,
                RxRingPtr        = 0x18,
                TxRingPtr        = 0x1C,
                MIIPhyAddr       = 0x6C,
                MIIStatus        = 0x6D,
                PCIBusConfig     = 0x6E,
                MIICmd           = 0x70,
                MIIRegAddr       = 0x71,
                MIIData          = 0x72,
                Config           = 0x78,
                RxMissed         = 0x7C,
                RxCRCErrs        = 0x7E,
        };

        // Command Bits
        enum viarhine_chip_cmd_bits
        {
                CmdInit     = 0x0001,
                CmdStart    = 0x0002,
                CmdStop     = 0x0004,
                CmdRxOn     = 0x0008,
                CmdTxOn     = 0x0010,
                CmdTxDemand = 0x0020,
                CmdRxDemand = 0x0040,
                CmdEarlyRx  = 0x0100,
                CmdEarlyTx  = 0x0200,
                CmdFDuplex  = 0x0400,
                CmdNoTxPoll = 0x0800,
                CmdReset    = 0x8000
        };

        // Interrupt Status Bits
        
        enum viarhine_intr_status_bits
        {
                IntrRxDone          = 0x0001,
                IntrRxErr           = 0x0004,
                IntrRxEmpty         = 0x0020,
                IntrTxDone          = 0x0002,
                IntrTxAbort         = 0x0008,
                IntrTxUnderrun      = 0x0010,
                IntrPCIErr          = 0x0040,
                IntrStatsMax        = 0x0080,
                IntrRxEarly         = 0x0100,
                IntrMIIChange       = 0x0200,
                IntrRxOverflow      = 0x0400,
                IntrRxDropped       = 0x0800,
                IntrRxNoBuf         = 0x1000,
                IntrTxAborted       = 0x2000,
                IntrLinkChange      = 0x4000,
                IntrRxWakeUp        = 0x8000,
                IntrNormalSummary   = 0x0003,
                IntrAbnormalSummary = 0xC260,
        };

        // RX Status Bits
        
        enum viarhine_rx_status_bits
        {
                RxOK       = 0x8000,
                RxWholePkt = 0x0300,
                RxErr      = 0x008F
        };

        // Desc Status Bits
        
        enum viarhine_desc_status_bits
        {
                DescOwn       = 0x80000000,
                DescEndPacket = 0x4000,
                DescIntr      = 0x1000
        };

        // PCI ID Information
        
        struct viarhine_pci_id_info
        {
                const char *name;
                unsigned short      vendor_id,
                                        device_id,
                                        device_id_mask,
                                        flags;
                int         io_size;
        };

        // Chip Compatibility
        
        enum viarhine_chip_capability_flags
        {
                CanHaveMII = 1
        };

        // Chip Information
        struct viarhine_chip_info
        {
                int io_size;
                int flags;
        };

        // RX Descriptor
        
        typedef struct
        {
                unsigned int rx_status ;
                unsigned int desc_length ;

                unsigned int addr ;
                unsigned int next ;
        } viarhine_rx_desc;

        // TX Descriptor
        
        typedef struct
        {
                unsigned int tx_status ;
                unsigned int desc_length ;

                unsigned int addr ;
                unsigned int next ;
        } viarhine_tx_desc;



        typedef struct sVia
        {
                DMHANDLE hDevice;
                netif *nif;

                sPciDevice pPciDevice;
                // Rings
                
                viarhine_tx_desc  *tx_desc;  // TX Frame Descriptor                  
                viarhine_rx_desc  *rx_desc;  // RX Frame Descriptor                  
                unsigned char            *tx_buf;               // TX Buffer                            
                unsigned char            *rx_buf;               // RX Buffer                            

                unsigned int           cookieID;  // Cookie Area ID           
                int                                     devID;     // Device ID                
                unsigned int            addr;      // Base Address of HostRegs 
                unsigned char     macaddr[6];   // Ethernet Address         

                unsigned char   tx_thresh;
                unsigned char   rx_thresh;
                unsigned short  cmd;
                unsigned char   interrupted;

                unsigned char duplex_full;   // Full-Duplex Operation Requested. 
                unsigned char duplex_lock;

                unsigned char  cur_rx;
                unsigned char  cur_tx;
                int    nonblocking;

                
                // MII Transceiver Section
                int           mii_cnt;          // MII Device Addresses.    
                unsigned short        mii_advertising;  // NWay Media Advertisement 
                unsigned char mii_phys[8];      // MII Device Addresses.    

                volatile int tx_free;
                sWaitQueue wq;
                char bOpened;
                
        } sVia;

        unsigned int ring_init(sVia *device);
        void rx_setmode(sVia *device);
        void duplex_check(sVia *device);


        void cmd_reset(sVia *via)
        {
                write16(via->addr + ChipCmd, CmdReset);
        }

        void cmd_getmacaddr(sVia *via)
        {
                int i;

                for (i = 0; i < 6; i++)
                        via->macaddr[i] = read8(via->addr + StationAddr + i);
        } 

        static unsigned int viaDeviceInit(unsigned char *lpstrDeviceInitParameter,
                                                                        DMHANDLE *hInitializedDevice)
        {
                *hInitializedDevice = (DMHANDLE)lpstrDeviceInitParameter;
                return ERR_OK;
        }

        static unsigned int viaDeviceDeInit(DMHANDLE hInitializedDevice)
        {
                return ERR_OK;
        }

        static unsigned int viaDeviceIoControl(DMHANDLE hDevice,
                                                                                unsigned long ulIoControlCode,
                                                                                void* pArg, char bUser)
        {
        netif *nif;

        nif = (netif*)hDevice;

        switch (ulIoControlCode)
        {
        }

        return ERR_OK;
        }


        static void viaNetReceive(sVia *device)
        {
                unsigned int      entry;
                char             *addr;
                unsigned int data_size;
                unsigned int desc_status;
                netbuf *pPacket;
                int i;

                for (entry=0;entry<RX_BUFFERS;entry++)
                {
                        if (!(device->rx_desc[entry].rx_status & DescOwn))
                        {
                                desc_status = device->rx_desc[entry].rx_status;
                                data_size   = (desc_status >> 16) - 4;
                                
                                addr = &device->rx_buf[entry * BUFFER_SIZE];

                                pPacket = netbuf_alloc(data_size + 2);
                                if (!pPacket)
                                {
                                        printk("viarhine.c: OOM");
                                }
                                else
                                        memcpy(pPacket->pData, addr, data_size);


                                device->rx_desc[entry].desc_length = MAX_FRAME_SIZE;
                                device->rx_desc[entry].rx_status   = DescOwn;

                                if (device->bOpened)
                                {
                                        pPacket->dev = device->nif; 
                                        net_recv(pPacket);
                                }
                        }
                }

                write16(device->addr + ChipCmd, CmdRxDemand | device->cmd); 
        }
         
        static int viaNetInterrupt(int irq, sVia *device)
        {
                unsigned int flags;
                short             worklimit = 20;
                unsigned short             reg;
                unsigned int i, j;
                int               wakeup_reader = 0;
                int               wakeup_writer = 0;

                save_flags(flags);
                cli();

                do
                {
                        reg = read16(device->addr + IntrStatus);
                
                        // Acknowledge All of the Current Interrupt Sources ASAP.
                        write16(device->addr + IntrStatus, reg & 0xffff);

                        if (reg == 0)
                                break;

                        if (reg & IntrRxDone)
                        {
                                viaNetReceive(device);
                                continue;
                        }
                        if (reg & IntrTxDone)
                        {
                                device->tx_free = 0;
                                for (i=0;i<TX_BUFFERS;i++)
                                {
                                        if (!(device->tx_desc[i].tx_status & DescOwn))
                                        {
                                                device->tx_free++;
                                        }
                                }
                                wakeup_writer++;
                                continue;
                        }

                        printk("viarhine.c: Abnormal interrupt reason: %04X", reg);

                        if (reg & (IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
                        {
                                write16(device->addr + ChipCmd, CmdRxDemand | read16(device->addr + ChipCmd));
                                continue;
                        }
                        if (reg & IntrTxAbort)
                        {
                                // Just restart Tx. 
                                write16(device->addr + ChipCmd, CmdTxDemand | read16(device->addr + ChipCmd));
                                continue;
                        }
                        if (reg & IntrTxUnderrun)
                        {
                                if (device->tx_thresh < 0xE0)
                                        write8(device->addr + TxConfig, device->tx_thresh += 0x20);
                                write16(device->addr + ChipCmd, CmdTxDemand | read16(device->addr + ChipCmd));
                                continue;
                        }

                        if (--worklimit < 0)
                                break;
                } while (1);

                restore_flags(flags);

                if (wakeup_writer)
                        WaitQueueWakeup(&device->wq, -1);
                
                return 0;       
        }


        static int viaNetSend(void *data)
        {
                netbuf *skb = (netbuf*)data;
                netif *nif;
                unsigned int flags;
                sVia *device;
                HRESULT hr;
                int buflen;
                unsigned int      entry; 
                void             *addr; 
                int iDiff;
                int i;

                nif = skb->dev;
                device = nif->data;

                save_flags(flags);
                cli();

        again:

                if (!((volatile)device->tx_free))
                {
                                device->tx_free = 0;
                                for (i=0;i<TX_BUFFERS;i++)
                                {
                                        if (!(device->tx_desc[i].tx_status & DescOwn))
                                        {
                                                device->tx_free++;
                                        }
                                }
                                if (!((volatile)device->tx_free))
                                {
                                                hr = WaitQueueAddInternal(&device->wq, WQ_FLAG_UNINTERRUPTABLE, 1000, NULL);
                                                if (hr != S_OK)
                                                {
                                                        
                                                        Notification(EVENT_ID_HARDWARE, "VIA Rhine Netcard problem", 
                                                                "The VIA Rhine network card transmitter\n"
                                                                "lockup up. The network may not be reachable\n"
                                                                "anymore.");

                                                        printk("viarhine.c: send timedout %d", device->tx_free);
                                                        restore_flags(flags);
                                                        return -EINTR;
                                                }
                                                goto again;
                                }
                }

                entry = device->cur_tx;
                while(device->tx_desc[entry].tx_status & DescOwn)
                {
                        entry++;
                        entry %= TX_BUFFERS;
                }

                buflen = skb->iSize;

                device->tx_desc[entry].tx_status = DescOwn;
                addr = &device->tx_buf[entry * BUFFER_SIZE];

                memcpy(addr, skb->pData, buflen);

                iDiff = 0;
                if (buflen < 60)
                {
                        iDiff = 60 - buflen;
                        buflen = 60;
                }

                if (buflen & 3) 
                {
                        iDiff = 4 - (buflen & 3);
                        buflen &= (~3);
                        buflen += 4;
                }

                if (iDiff)
                        memset((void*)((unsigned int)addr + skb->iSize), 0, iDiff);
                
                device->tx_desc[entry].desc_length = 0x00E08000 | buflen;
                entry++;
                entry %= TX_BUFFERS;
                device->cur_tx = entry;

                ((volatile)device->tx_free)--;

                write16(device->addr + ChipCmd, device->cmd | CmdTxDemand); 

                restore_flags(flags);
                netbuf_discard(skb, 1, "viarhine");

                return 0;
        }

        static int viaNetOpen(netif *nif)
        {
                sVia *via;

                via = nif->data;

                if (via->bOpened)
                        return -EBUSY;

                via->bOpened = 1;
                
                return 0;
        }

        static int viaNetClose(netif *nif)
        {
                sVia *via;

                via = nif->data;
                via->bOpened = 0;
                
                return ERR_OK;
        }

        HRESULT viaInitDevice(sPciDevice *pPciDevice, char *ucDeviceName)
        {
                netif *nif;
                unsigned char str[255];
                unsigned int status;
                sVia *via;
                int i;
                unsigned short pci_command;

                via = (sVia*)valloc(sizeof(sVia));
                if (!via)
                        return E_OUTOFMEMORY;
                memset(via ,0, sizeof(sVia));

                memcpy(&via->pPciDevice, pPciDevice, sizeof(sPciDevice));

                sprintf(str, "via%d", uiDeviceIndex++);
                nif = netif_new(str, NET_HARDWARE_TYPE_ETHERNET);
                if (!nif)
                        return S_FALSE;

                nif->send = viaNetSend;
                nif->open = viaNetOpen;
                nif->close = viaNetClose;
                nif->ioctl = 0;

                nif->loopback_device = 0;
                via->nif         = nif;
                nif->data    = via;

                WaitQueueCreate(&via->wq, "VIARHINE");

                if (DeviceClaim(pPciDevice->uiDeviceID, DEVICE_NAME, DEVICE_TYPE_NETWORK) != S_OK)
                {
                        printk("via.c: Unable to claim device\n");
                        netif_delete(nif);
                        vfree(via);
                        return S_FALSE;
                }

                netif_setname(nif, ucDeviceName);

                BusPciRead(pPciDevice, PCI_COMMAND, 2, &pci_command);
                pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
                BusPciWrite(pPciDevice, PCI_COMMAND, 2, pci_command);
          
                printk("viarhine.c: VIA Rhine II at 0x%X, IRQ: %d, Latency: %d",
                        pPciDevice->uiBase0 & PCI_BASE_ADDRESS_IO_MASK,
                        pPciDevice->ucIRQ,
                        pPciDevice->ucLatency);
                        
                if (pPciDevice->ucLatency < 64)
                {
                        printk("via.c: Adjusted VIA Rhine latency");
                        BusPciWrite(pPciDevice, PCI_LATENCY_TIMER, 1, 64);
                }


                via->addr     = pPciDevice->uiBase0 & PCI_BASE_ADDRESS_IO_MASK;

                status = DmDeviceDoInit(nif->name, "DdNetvia",&via->hDevice, "");
                if (status != ERR_OK)
                {
                        printk("via.c: Unable to init device..\n");
                        DeviceUnClaim(pPciDevice->uiDeviceID, DEVICE_UNCLAIM_REASON_ERROR, "Unable to register device");
                        netif_delete(nif);
                        vfree(via);
                        return S_FALSE;
                }

                cmd_reset(via);
                ThreadBusyWait(2);
                cmd_getmacaddr(via);

                printk("viarhine.c: MAC %02X:%02X:%02X:%02X:%02X:%02X",
                        via->macaddr[0],
                        via->macaddr[1],
                        via->macaddr[2],
                        via->macaddr[3],
                        via->macaddr[4],
                        via->macaddr[5]);



                // Initialize MII Chip
                {
                        int phy, phy_idx = 0;
                        
                        via->mii_phys[0] = 1;  // Standard for this chip.
                        for (phy = 1; (phy < 32) && (phy_idx < 4); phy++)
                        {
                                int mii_status = mdio_read(via, phy, 1);
                                
                                if ((mii_status != 0xffff) && (mii_status != 0x0000))
                                {
                                        via->mii_phys[phy_idx++] = phy;
                                        via->mii_advertising     = mdio_read(via, phy, 4);

                                        if (mii_status & 0x04)
                                                printk( "viarhine.c: Cable is connected." );
                                        
                                }
                        }
                        
                        via->mii_cnt = phy_idx;
                }

                // Allocate and Initialize Frame Buffer Rings & Descriptors
                if (ring_init(via) != S_OK)
                {
                        vfree(via);     
                        DeviceUnClaim(pPciDevice->uiDeviceID, DEVICE_UNCLAIM_REASON_ERROR, "Unable to init rings");
                        netif_delete(nif);
                        return S_FALSE;
                }

                for (i = 0; i < 6; i++)
                {
                        write8(via->addr + StationAddr + i, via->macaddr[i]);
                        nif->dev_addr[i] = via->macaddr[i];
                }

                write32(via->addr + TxRingPtr, &via->tx_desc[0]);
                write32(via->addr + RxRingPtr, &via->rx_desc[0]);

                // Initialize Other Registers.
                write16(via->addr + PCIBusConfig, 0x0006);

                // Configure the FIFO Thresholds.
                via->tx_thresh = 0x20;
                via->rx_thresh = 0x60;  // Written in device_rx_setmode(). 

                write8(via->addr + TxConfig, 0x20);
                rx_setmode(via);

                if (ResourceUseIRQ(via->pPciDevice.uiDeviceID, via->pPciDevice.ucIRQ, "VIARHINE", (unsigned int)viaNetInterrupt, via , IRQ_SHARED, via))
                {
                printk("via.c: Irq %d already in use.",via->pPciDevice.ucIRQ);
                DeviceUnClaim(via->pPciDevice.ucIRQ, DEVICE_UNCLAIM_REASON_ERROR, DEVICE_UNCLAIM_ERROR_TEXT_RESOURCES);
                vfree(via);     
                netif_delete(nif);
                return S_FALSE;
                }

                via->tx_free = TX_BUFFERS;

                // Enable interrupts by setting the interrupt mask.
                write16(via->addr + IntrEnable,
                                IntrRxDone | IntrRxErr    | IntrRxEmpty    | IntrRxOverflow | 
                                IntrTxDone | IntrTxAbort  | IntrTxUnderrun | IntrRxDropped  |
                                IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange);

                via->cmd = CmdStart | CmdTxOn | CmdRxOn | CmdNoTxPoll;

                if (via->duplex_lock)
                        via->cmd |= CmdFDuplex;

                write16(via->addr + ChipCmd, via->cmd);

                duplex_check(via);
                return S_OK;
        }

        HRESULT viaProbe(void)
        {
                unsigned int i;
                unsigned int uiIndex=0;
                char bFound = 0;
                sPciDevice dev;

                while (BusPciEnumDevices(uiIndex, &dev) == S_OK)
                {
                        i = 0;
                        
                        while (1)
                        {
                                if (pPciInfo[i].vendor_id == 0)
                                        break;

                                if ((dev.usVendorID == pPciInfo[i].vendor_id) && 
                                        (dev.usDeviceID == pPciInfo[i].device_id))
                                {
                                        if (viaInitDevice(&dev, (char*)pPciInfo[i].name) == S_OK)
                                                bFound = 1;
                                        break;
                                }
                                i++;
                        }
                        if (bFound)
                                break;

                        uiIndex++;
                }

                if (!bFound)
                {
                printk("via.c: no via Ethernet controller found");
                return S_FALSE;
                }

                if (bFound)
                        return S_OK;

                return E_FILE_NOT_FOUND;
        }

        int mdio_read(sVia *via, int phy_id, int regnum)
        {
                int boguscnt = 1024;

                // Wait for a previous command to complete. 
                while ((read8(via->addr + MIICmd) & 0x60) && --boguscnt > 0)
                        ;

                write8(via->addr + MIICmd,     0x00);
                write8(via->addr + MIIPhyAddr, phy_id);
                write8(via->addr + MIIRegAddr, regnum);
                write8(via->addr + MIICmd,     0x40);    // Trigger Read 

                boguscnt = 1024;
                while ((read8(via->addr + MIICmd) & 0x40) && --boguscnt > 0)
                        ;
                        
                return read16(via->addr + MIIData);
        }

        void mdio_write(sVia *via, int phy_id, int regnum, int value)
        {
                int boguscnt = 1024;

                if ((phy_id == via->mii_phys[0]) && (regnum == 4))
                        via->mii_advertising = value;

                // Wait for a previous command to complete. 
                while ((read8(via->addr + MIICmd) & 0x60) && --boguscnt > 0)
                        ;

                write8(via->addr + MIICmd,     0x00);
                write8(via->addr + MIIPhyAddr, phy_id);
                write8(via->addr + MIIRegAddr, regnum);
                write8(via->addr + MIIData,    value);
                write8(via->addr + MIICmd,     0x20);     // Trigger Write. 
        } 

        unsigned int ring_init(sVia *device)
        {
                unsigned int i;
                void *p;

                p = valloc_aligned(sizeof(viarhine_tx_desc) * TX_BUFFERS, 0x1000);
                device->tx_desc = p;
                        
                // Create Transmit Buffer Area
                
                device->tx_buf = (unsigned char*)alloc_pages(BUFFER_SIZE * TX_BUFFERS / 4096 + 1, &i);
                if (!device->tx_buf)
                        return S_FALSE;

                // Initialize TX Buffer Descriptors
                for ( i = 0; i < TX_BUFFERS; i++)
                {
                        device->tx_desc[i].tx_status   = 0;
                        device->tx_desc[i].desc_length = 0;
                        device->tx_desc[i].addr        = (unsigned int)device->tx_buf + i * BUFFER_SIZE;
                        device->tx_desc[i].next        = (unsigned int)&device->tx_desc[i+1];
                }
                device->tx_desc[i - 1].next = (unsigned int)&device->tx_desc[0];

                p = valloc_aligned(sizeof(viarhine_rx_desc) * RX_BUFFERS, 0x1000);
                device->rx_desc = p;

                device->rx_buf = (unsigned char*)alloc_pages(BUFFER_SIZE * RX_BUFFERS / 4096 + 1, &i);
                if (!device->rx_buf)
                        return S_FALSE;

                for ( i = 0; i < RX_BUFFERS; i++)
                {
                        device->rx_desc[i].rx_status   = DescOwn;
                        device->rx_desc[i].desc_length = MAX_FRAME_SIZE;
                        device->rx_desc[i].addr        = (unsigned int)device->rx_buf + i * BUFFER_SIZE;
                        device->rx_desc[i].next        =  (unsigned int)&device->rx_desc[i+1];
                }
                device->rx_desc[i - 1].next = (unsigned int)&device->rx_desc[0];

                return S_OK;
        }


        void rx_setmode(sVia *device)
        {
                unsigned char rx_mode; // Note: 0x02 = Accept Runt, 0x01 = Accept Errors
                
                write32(device->addr + MulticastFilter0, 0);    
                write32(device->addr + MulticastFilter1, 0);    
                rx_mode = 0xA; // was 0x1A => PRO should not be set

                write8(device->addr + RxConfig, device->rx_thresh | rx_mode);
        }

        void duplex_check(sVia *device)
        {
                int mii_reg5;
                int negotiated;
                int duplex;

                mii_reg5   = mdio_read(device, device->mii_phys[0], 5);
                negotiated = mii_reg5 & device->mii_advertising;

                if (device->duplex_lock || mii_reg5 == 0xffff)
                        return;

                duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
                if (device->duplex_full != duplex)
                {
                        device->duplex_full = duplex;

                        if (duplex)
                                device->cmd |= CmdFDuplex;
                        else
                                device->cmd &= ~CmdFDuplex;

                        write16(device->addr + ChipCmd, device->cmd);
                }
        }
         
        static int deinit(module_data *data)
        {
                unsigned int ret;

                ret = DmDeleteDDriver(hDriver);
                if (ret)
                        return ret;

                return 0;
        }


        DLM_EXPORT int KernelModuleMain(module_data* data)
        {
        DM_DD_Functions viaFunctions;
        DM_ERROR status;

        int ret=0;
          
        SET_MODULE_DATA(data);
        data->deinit = deinit;

        printk("via.c: Initializing....");
                
        viaFunctions.ulDeviceInit                       = viaDeviceInit;
        viaFunctions.ulDeviceDeInit             = viaDeviceDeInit;
        viaFunctions.ulDeviceShutDown           = 0;
        viaFunctions.ulDeviceOpen                       = 0;
        viaFunctions.ulDeviceClose              = 0;
        viaFunctions.ulDeviceRead                       = 0;
        viaFunctions.ulDeviceWrite              = 0;
        viaFunctions.ulDeviceIoControl  = 0;

        status = DmInstallDDriver("DdNetvia", 0, (unsigned long)&viaFunctions, &hDriver);
        if (status != ERR_OK)
        {
                printk("via.c: Failed to install driver..\n");
                return status;
        }

        return viaProbe();
        }


To compile this driver, use:

  gcc mydriver.c -o /boot/system/drivers/libmydrivers.so -kernel -O2
To load the driver:
  mod -l /boot/system/drivers/libmydrivers.so
And to unload:
  mod -u /boot/system/drivers/libmydrivers.so

Generated on Wed Aug 9 19:32:44 2006 for SkyOS - DDK by  doxygen 1.4.4