Hi Axel, i added a new device to the driver. I have attached the already modified sis900.c from the haiku tree, so you just need to replace it. This is the change for track: #define PHY_ID0_VIA_6103 0x0101 #define PHY_ID1_VIA_6103 0x8f20 {"VIA 6103 PHY", PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN}, Take care, Bernd www.berndsworld.com
/* SiS 900 chip specific functions * * Copyright © 2001-2005 pinc Software. All Rights Reserved. * Distributed under the terms of the MIT license. */ #include <OS.h> #include <KernelExport.h> #include <Drivers.h> #include <PCI.h> #include <SupportDefs.h> #include <stdlib.h> #include <string.h> #include "ether_driver.h" #include "driver.h" #include "device.h" #include "interface.h" #include "sis900.h" // prototypes uint16 sis900_resetPHY(struct sis_info *info); void sis900_selectPHY(struct sis_info *info); void sis900_setMode(struct sis_info *info, int32 mode); int32 sis900_readMode(struct sis_info *info); // MII chip info table #define PHY_ID0_SiS900_INTERNAL 0x001d #define PHY_ID1_SiS900_INTERNAL 0x8000 #define PHY_ID0_ICS_1893 0x0015 #define PHY_ID1_ICS_1893 0xff40 #define PHY_ID0_REALTEK_8201 0x0000 #define PHY_ID1_REALTEK_8201 0x8200 #define PHY_ID0_VIA_6103 0x0101 #define PHY_ID1_VIA_6103 0x8f20 #define MII_HOME 0x0001 #define MII_LAN 0x0002 const static struct mii_chip_info { const char *name; uint16 id0, id1; uint8 types; } gMIIChips[] = { {"SiS 900 Internal MII PHY", PHY_ID0_SiS900_INTERNAL, PHY_ID1_SiS900_INTERNAL, MII_LAN}, {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830, MII_LAN}, {"AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, MII_LAN}, {"AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, MII_HOME}, {"ICS 1893 LAN PHY", PHY_ID0_ICS_1893, PHY_ID1_ICS_1893, MII_LAN}, {"NS 83851 PHY", 0x2000, 0x5C20, MII_LAN | MII_HOME}, {"Realtek RTL8201 PHY", PHY_ID0_REALTEK_8201, PHY_ID1_REALTEK_8201, MII_LAN}, {"VIA 6103 PHY", PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN}, {NULL, 0, 0, 0} }; /***************************** helper functions *****************************/ static uint32 physicalAddress(volatile void *address, uint32 length) { physical_entry table; get_memory_map((void *)address, length, &table, 1); return (uint32)table.address; } /***************************** interrupt handling *****************************/ // #pragma mark - int32 intrCounter = 0; int32 lastIntr[100]; static int32 sis900_rxInterrupt(struct sis_info *info) { int32 handled = B_UNHANDLED_INTERRUPT; int16 releaseRxSem = 0; int16 limit; acquire_spinlock(&info->rxSpinlock); HACK(spin(10000)); // check for packet ownership for (limit = info->rxFree; limit > 0; limit--) { if (!(info->rxDescriptor[info->rxInterruptIndex].status & SiS900_DESCR_OWN)) { // if (limit == info->rxFree) // { //dprintf("here!\n"); // limit++; // continue; // } break; } //dprintf("received frame %d!\n",info->rxInterruptIndex); releaseRxSem++; info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK; info->rxFree--; } release_spinlock(&info->rxSpinlock); // reenable rx queue write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE); if (releaseRxSem) { release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } return handled; } static int32 sis900_txInterrupt(struct sis_info *info) { int16 releaseTxSem = 0; uint32 status; int16 limit; acquire_spinlock(&info->txSpinlock); HACK(spin(10000)); for (limit = info->txSent; limit > 0; limit--) { status = info->txDescriptor[info->txInterruptIndex].status; //dprintf("txIntr: %d: mem = %lx : hardware = %lx\n",info->txInterruptIndex, // physicalAddress(&info->txDescriptor[info->txInterruptIndex],sizeof(struct buffer_desc)), // read32(info->registers + SiS900_MAC_Tx_DESCR)); /* Does the device generate extra interrupts? */ if (status & SiS900_DESCR_OWN) { struct buffer_desc *descriptor = (void *)read32(info->registers + SiS900_MAC_Tx_DESCR); int16 that; for (that = 0; that < NUM_Tx_DESCR && (void *)physicalAddress(&info->txDescriptor[that], sizeof(struct buffer_desc)) != descriptor; that++) { } if (that == NUM_Tx_DESCR) that = 0; //dprintf("tx busy %d: %lx (hardware status %d = %lx)!\n",info->txInterruptIndex,status,that,info->txDescriptor[that].status); // if (limit == info->txSent) // { //dprintf("oh no!\n"); // limit++; // continue; // } break; } if (status & (SiS900_DESCR_Tx_ABORT | SiS900_DESCR_Tx_UNDERRUN | SiS900_DESCR_Tx_OOW_COLLISION)) { dprintf("tx error: %lx\n", status); } else info->txDescriptor[info->txInterruptIndex].status = 0; releaseTxSem++; /* this many buffers are free */ info->txInterruptIndex = (info->txInterruptIndex + 1) & NUM_Tx_MASK; info->txSent--; if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR) dprintf("ERROR interrupt: txSent = %d\n", info->txSent); } release_spinlock(&info->txSpinlock); if (releaseTxSem) { release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } return B_HANDLED_INTERRUPT; } int32 sis900_interrupt(void *data) { struct sis_info *info = data; int32 handled = B_UNHANDLED_INTERRUPT; int16 worklimit = 20; uint32 intr; cpu_status former; former = disable_interrupts(); acquire_spinlock(&info->lock); while (worklimit-- > 0) { // reading the interrupt status register clears all interrupts intr = read32(info->registers + SiS900_MAC_INTR_STATUS); if (!intr) break; TRACE(("************ interrupt received: %08lx **************\n", intr)); intrCounter = (intrCounter + 1) % 100; lastIntr[intrCounter] = intr; // wake-up event interrupt if (intr & SiS900_INTR_WAKEUP_EVENT) { TRACE(("wake-up event received: %ld\n", read32(info->registers + SiS900_MAC_WAKEUP_EVENT))); // clear PM event register write32(info->registers + SiS900_MAC_WAKEUP_EVENT, SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS); handled = B_HANDLED_INTERRUPT; } // receive packet interrupts if (intr & (/*SiS900_INTR_Rx_STATUS_OVERRUN |*/ SiS900_INTR_Rx_OVERRUN | SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK)) handled = sis900_rxInterrupt(info); // transmit packet interrupts if (intr & (SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR | SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK)) handled = sis900_txInterrupt(info); } release_spinlock(&info->lock); restore_interrupts(former); return handled; } void sis900_disableInterrupts(struct sis_info *info) { write32(info->registers + SiS900_MAC_INTR_MASK, 0); write32(info->registers + SiS900_MAC_INTR_ENABLE, 0); } void sis900_enableInterrupts(struct sis_info *info) { write32(info->registers + SiS900_MAC_INTR_ENABLE, 0); // enable link detection write32(info->registers + SiS900_MAC_WAKEUP_CONTROL, SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS); // set interrupt mask write32(info->registers + SiS900_MAC_INTR_MASK, //SiS900_INTR_WAKEUP_EVENT | SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR | SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK | SiS900_INTR_Rx_STATUS_OVERRUN | SiS900_INTR_Rx_OVERRUN | SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK); write32(info->registers + SiS900_MAC_INTR_ENABLE,1); } /***************************** PHY and link mode *****************************/ // #pragma mark - int32 sis900_timer(timer *t) { struct sis_info *info = (struct sis_info *)t; if (!info->autoNegotiationComplete) { int32 mode = sis900_readMode(info); if (mode) sis900_setMode(info, mode); return 0; } if (info->link) { // link lost uint16 status = mdio_status(info); if ((status & MII_STATUS_LINK) == 0) { info->link = false; dprintf(DEVICE_NAME ": link lost\n"); // if it's the internal SiS900 MII PHY, reset it if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) sis900_resetPHY(info); } } if (!info->link) { // new link established uint16 status; sis900_selectPHY(info); status = mdio_status(info); if (status & MII_STATUS_LINK) { sis900_checkMode(info); info->link = true; } } // revision = info->pciInfo->revision; // if (!(revision == SiS900_REVISION_SiS630E || revision == SiS900_REVISION_SiS630EA1 // || revision == SiS900_REVISION_SiS630A || revision == SiS900_REVISION_SiS630ET)) // bug(DEVICE_NAME ": set_eq() not needed!\n"); // else // bug("********* set_eq() would be needed! ********\n"); return 0; } uint16 sis900_resetPHY(struct sis_info *info) { uint16 status = mdio_status(info); mdio_write(info, MII_CONTROL, MII_CONTROL_RESET); return status; } status_t sis900_initPHYs(struct sis_info *info) { uint16 phy; // search for total of 32 possible MII PHY addresses for (phy = 0; phy < 32; phy++) { struct mii_phy *mii; uint16 status; int32 i; status = mdio_statusFromPHY(info, phy); if (status == 0xffff || status == 0x0000) // this MII is not accessable continue; mii = (struct mii_phy *)malloc(sizeof(struct mii_phy)); if (mii == NULL) return B_NO_MEMORY; mii->address = phy; mii->id0 = mdio_readFromPHY(info, phy, MII_PHY_ID0); mii->id1 = mdio_readFromPHY(info, phy, MII_PHY_ID1); mii->types = MII_HOME; mii->next = info->firstPHY; info->firstPHY = mii; for (i = 0; gMIIChips[i].name; i++) { if (gMIIChips[i].id0 != mii->id0 || gMIIChips[i].id1 != (mii->id1 & 0xfff0)) continue; dprintf("Found MII PHY: %s\n", gMIIChips[i].name); mii->types = gMIIChips[i].types; break; } if (gMIIChips[i].name == NULL) dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n", mii->id0, mii->id1); } if (info->firstPHY == NULL) { dprintf("No MII PHY transceiver found!\n"); return B_ENTRY_NOT_FOUND; } sis900_selectPHY(info); // if the internal PHY is selected, reset it if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) { if (sis900_resetPHY(info) & MII_STATUS_LINK) { uint16 poll = MII_STATUS_LINK; while (poll) { poll ^= mdio_read(info, MII_STATUS) & poll; } } } // workaround for ICS1893 PHY if (info->currentPHY->id0 == PHY_ID0_ICS_1893 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_ICS_1893) mdio_write(info, 0x0018, 0xD200); // SiS 630E has some bugs on default value of PHY registers if (info->pciInfo->revision == SiS900_REVISION_SiS630E) { mdio_write(info, MII_AUTONEG_ADV, 0x05e1); mdio_write(info, MII_CONFIG1, 0x22); mdio_write(info, MII_CONFIG2, 0xff00); mdio_write(info, MII_MASK, 0xffc0); } info->link = mdio_status(info) & MII_STATUS_LINK; return B_OK; } void sis900_selectPHY(struct sis_info *info) { uint16 status; // ToDo: need to be changed, select PHY in relation to the link mode info->currentPHY = info->firstPHY; info->phy = info->currentPHY->address; status = mdio_read(info, MII_CONTROL); status &= ~MII_CONTROL_ISOLATE; mdio_write(info, MII_CONTROL, status); } void sis900_setMode(struct sis_info *info, int32 mode) { uint32 address = info->registers + SiS900_MAC_CONFIG; uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES; uint32 rxFlags = 0; int32 speed = mode & LINK_SPEED_MASK; if (read32(address) & SiS900_MAC_CONFIG_EDB_MASTER) { TRACE((DEVICE_NAME ": EDB master is set!\n")); txFlags |= 5 << SiS900_DMA_SHIFT; rxFlags = 5 << SiS900_DMA_SHIFT; } // link speed FIFO thresholds if (speed == LINK_SPEED_HOME || speed == LINK_SPEED_10_MBIT) { rxFlags |= SiS900_Rx_10_MBIT_DRAIN_THRES; txFlags |= SiS900_Tx_10_MBIT_DRAIN_THRES; } else { rxFlags |= SiS900_Rx_100_MBIT_DRAIN_THRES; txFlags |= SiS900_Tx_100_MBIT_DRAIN_THRES; } // duplex mode if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX) { txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE; rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS; } write32(info->registers + SiS900_MAC_Tx_CONFIG, txFlags); write32(info->registers + SiS900_MAC_Rx_CONFIG, rxFlags); } int32 sis900_readMode(struct sis_info *info) { struct mii_phy *phy = info->currentPHY; uint16 autoAdv, autoLinkPartner; int32 speed, duplex; uint16 status = mdio_status(info); if (!(status & MII_STATUS_LINK)) { dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status); return 0; } // auto negotiation completed autoAdv = mdio_read(info, MII_AUTONEG_ADV); autoLinkPartner = mdio_read(info, MII_AUTONEG_LINK_PARTNER); status = autoAdv & autoLinkPartner; speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) ? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT; duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) ? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX; info->autoNegotiationComplete = true; // workaround for Realtek RTL8201 PHY issue if (phy->id0 == PHY_ID0_REALTEK_8201 && (phy->id1 & 0xFFF0) == PHY_ID1_REALTEK_8201) { if (mdio_read(info, MII_CONTROL) & MII_CONTROL_FULL_DUPLEX) duplex = LINK_FULL_DUPLEX; if (mdio_read(info, 0x0019) & 0x01) speed = LINK_SPEED_100_MBIT; } dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n", speed == LINK_SPEED_100_MBIT ? "0" : "", duplex == LINK_FULL_DUPLEX ? "full" : "half"); return speed | duplex; } static void sis900_setAutoNegotiationCapabilities(struct sis_info *info) { uint16 status = mdio_status(info); uint16 capabilities = MII_NWAY_CSMA_CD | (status & MII_STATUS_CAN_TX_FDX ? MII_NWAY_TX_FDX : 0) | (status & MII_STATUS_CAN_TX ? MII_NWAY_TX : 0) | (status & MII_STATUS_CAN_T_FDX ? MII_NWAY_T_FDX : 0) | (status & MII_STATUS_CAN_T ? MII_NWAY_T : 0); TRACE((DEVICE_NAME ": write capabilities %d\n", capabilities)); mdio_write(info, MII_AUTONEG_ADV, capabilities); } static void sis900_autoNegotiate(struct sis_info *info) { uint16 status = mdio_status(info); if ((status & MII_STATUS_LINK) == 0) { TRACE((DEVICE_NAME ": media link off\n")); info->autoNegotiationComplete = true; return; } TRACE((DEVICE_NAME ": auto negotiation started...\n")); // reset auto negotiation mdio_write(info, MII_CONTROL, MII_CONTROL_AUTO | MII_CONTROL_RESET_AUTONEG); info->autoNegotiationComplete = false; } void sis900_checkMode(struct sis_info *info) { uint32 address = info->registers + SiS900_MAC_CONFIG; if (info->fixedMode != 0) { TRACE((DEVICE_NAME ": link mode set via settings\n")); // ToDo: what about the excessive deferral timer? sis900_setMode(info, info->fixedMode); info->autoNegotiationComplete = true; } else if (info->currentPHY->types == MII_LAN) { TRACE((DEVICE_NAME ": PHY type is LAN\n")); // enable excessive deferral timer write32(address, ~SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL & read32(address)); sis900_setAutoNegotiationCapabilities(info); sis900_autoNegotiate(info); } else { TRACE((DEVICE_NAME ": PHY type is not LAN\n")); // disable excessive deferral timer write32(address, SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL | read32(address)); sis900_setMode(info, LINK_SPEED_HOME | LINK_HALF_DUPLEX); info->autoNegotiationComplete = true; } } /***************************** MACs, rings & config *****************************/ // #pragma mark - bool sis900_getMACAddress(struct sis_info *info) { if (info->pciInfo->revision >= SiS900_REVISION_SiS96x) { // SiS 962 & 963 are using a different method to access the EEPROM // than the standard SiS 630 addr_t eepromAccess = info->registers + SiS900_MAC_EEPROM_ACCESS; uint32 tries = 0; write32(eepromAccess, SiS96x_EEPROM_CMD_REQ); while (tries < 1000) { if (read32(eepromAccess) & SiS96x_EEPROM_CMD_GRANT) { int i; /* get MAC address from EEPROM */ for (i = 0; i < 3; i++) { uint16 id; id = eeprom_read(info, SiS900_EEPROM_MAC_ADDRESS + i); info->address.ebyte[i*2 + 1] = id >> 8; info->address.ebyte[i*2] = id & 0xff; } write32(eepromAccess, SiS96x_EEPROM_CMD_DONE); return true; } else { spin(2); tries++; } } write32(eepromAccess, SiS96x_EEPROM_CMD_DONE); return false; } else if (info->pciInfo->revision >= SiS900_REVISION_SiS630E) { /* SiS630E and above are using CMOS RAM to store MAC address */ pci_info isa; int32 index; for (index = 0; pci->get_nth_pci_info(index, &isa) == B_OK; index++) { if (isa.vendor_id == VENDOR_ID_SiS && isa.device_id == DEVICE_ID_SiS_ISA_BRIDGE) { uint8 reg,i; addr_t registers = isa.u.h0.base_registers[0]; reg = pci->read_pci_config(isa.bus,isa.device,isa.function,0x48,1); pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg | 0x40); for (i = 0; i < 6; i++) { write8(registers + 0x70,0x09 + i); info->address.ebyte[i] = read8(registers + 0x71); } pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg & ~0x40); return true; } } return false; } else { /* SiS630 stores the MAC in an eeprom */ uint16 signature; int i; /* check to see if we have sane EEPROM */ signature = eeprom_read(info,SiS900_EEPROM_SIGNATURE); if (signature == 0xffff || signature == 0x0000) { dprintf(DEVICE_NAME ": cannot read EEPROM signature\n"); return false; } /* get MAC address from EEPROM */ for (i = 0; i < 3; i++) { uint16 id; id = eeprom_read(info,SiS900_EEPROM_MAC_ADDRESS + i); info->address.ebyte[i*2 + 1] = id >> 8; info->address.ebyte[i*2] = id & 0xff; } return true; } return false; } status_t sis900_reset(struct sis_info *info) { addr_t address = info->registers + SiS900_MAC_COMMAND; int16 tries = 1000; TRACE(("sis900 reset\n")); write32(address, SiS900_MAC_CMD_RESET); write32(info->registers + SiS900_MAC_Rx_FILTER_CONTROL, SiS900_RxF_ENABLE | SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST); // wait until the chip leaves reset state while ((read32(address) & SiS900_MAC_CMD_RESET) && tries-- > 0) snooze(2); write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE); return B_OK; } void sis900_setPromiscuous(struct sis_info *info, bool on) { addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL; int32 filter = read32(filterControl); // accept all incoming packets (or not) if (on) { write32(filterControl, SiS900_RxF_ENABLE | SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST); } else write32(filterControl, filter | ~SiS900_RxF_ACCEPT_ALL_ADDRESSES); } void sis900_setRxFilter(struct sis_info *info) { addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL; addr_t filterData = info->registers + SiS900_MAC_Rx_FILTER_DATA; int32 i; // set MAC address as receive filter for (i = 0; i < 3; i++) { write32(filterControl, i << SiS900_Rx_FILTER_ADDRESS_SHIFT); write32(filterData, info->address.ebyte[i*2] | (info->address.ebyte[i*2 + 1] << 8)); } write32(filterControl, SiS900_RxF_ENABLE | SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST /*| SiS900_RxF_ACCEPT_ALL_ADDRESSES*/); } void sis900_deleteRings(struct sis_info *info) { delete_area(info->txArea); delete_area(info->rxArea); } status_t sis900_createRings(struct sis_info *info) { uint16 i; // create transmit buffer area info->txArea = create_area("sis900 tx buffer", (void **)&info->txBuffer[0], B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Tx_DESCR), B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); if (info->txArea < B_OK) return info->txArea; // initialize transmit buffer descriptors for (i = 1; i < NUM_Tx_DESCR; i++) info->txBuffer[i] = (void *)(((uint32)info->txBuffer[0]) + (i * BUFFER_SIZE)); for (i = 0; i < NUM_Tx_DESCR; i++) { info->txDescriptor[i].status = 0; info->txDescriptor[i].buffer = physicalAddress(info->txBuffer[i], BUFFER_SIZE); info->txDescriptor[i].link = #if (NUM_Tx_DESCR == 1) 0; #else physicalAddress(&info->txDescriptor[(i + 1) & NUM_Tx_MASK], sizeof(struct buffer_desc)); #endif } // create receive buffer area info->rxArea = create_area("sis900 rx buffer", (void **)&info->rxBuffer[0], B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Rx_DESCR), B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); if (info->rxArea < B_OK) { delete_area(info->txArea); return info->rxArea; } // initialize receive buffer descriptors for (i = 1; i < NUM_Rx_DESCR; i++) info->rxBuffer[i] = (void *)(((uint32)info->rxBuffer[0]) + (i * BUFFER_SIZE)); for (i = 0; i < NUM_Rx_DESCR; i++) { info->rxDescriptor[i].status = MAX_FRAME_SIZE; info->rxDescriptor[i].buffer = physicalAddress(info->rxBuffer[i], BUFFER_SIZE); info->rxDescriptor[i].link = physicalAddress(&info->rxDescriptor[(i + 1) & NUM_Rx_MASK], sizeof(struct buffer_desc)); } info->rxFree = NUM_Rx_DESCR; // set descriptor pointer registers write32(info->registers + SiS900_MAC_Tx_DESCR, physicalAddress(&info->txDescriptor[0], sizeof(struct buffer_desc))); write32(info->registers + SiS900_MAC_Rx_DESCR, physicalAddress(&info->rxDescriptor[0], sizeof(struct buffer_desc))); return B_OK; }