From 80127f8edbe677de66d15a52273075e5e82851f8 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Mon, 15 Mar 2004 07:13:03 +0000 Subject: [PATCH] Some fixes, some warning fixed, added a lot of code for the MII handling (almost completely "stolen" from Axel's sis900 driver), not yet working. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6988 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/wb840/device.c | 13 +- .../kernel/drivers/network/wb840/interface.c | 76 ++--- .../kernel/drivers/network/wb840/interface.h | 4 +- .../kernel/drivers/network/wb840/wb840.c | 319 ++++++++++++++++-- .../kernel/drivers/network/wb840/wb840.h | 128 ++++++- 5 files changed, 451 insertions(+), 89 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/wb840/device.c b/src/add-ons/kernel/drivers/network/wb840/device.c index 8e0b8f62e1..c2ac267dc5 100644 --- a/src/add-ons/kernel/drivers/network/wb840/device.c +++ b/src/add-ons/kernel/drivers/network/wb840/device.c @@ -67,14 +67,13 @@ wb840_open(const char *name, uint32 flags, void** cookie) LOG(("wb840: reg_base=%x\n", (int)data->reg_base)); wb_read_eeprom(data, &data->myaddr, 0, 3, 0); - print_address((void*)&data->myaddr); data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus, data->pciInfo->device, data->pciInfo->function, PCI_line_size, sizeof (PCI_line_size)) & 0xff; if (wb_create_semaphores(data) == B_OK) { - /* reset the card */ - wb_reset(data); + wb_initPHYs(data); + wb_init(data); /* Setup interrupts */ data->irq = data->pciInfo->u.h0.interrupt_line; @@ -87,15 +86,9 @@ wb840_open(const char *name, uint32 flags, void** cookie) WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON); write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF); WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON); - //write32(data->reg_base + WB_TXSTART, 0xFFFFFFFF); - - //dump_registers(data); add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER); -#if DEBUG - dump_registers(data); -#endif return B_OK; // Everything after this line is an error } else @@ -149,11 +142,13 @@ wb840_read(void* cookie, off_t position, void *buf, size_t* num_bytes) *num_bytes = 0; } else { size = WB_RXBYTES(check); + size -= CRC_SIZE; LOG((DEVICE_NAME": received %d bytes\n", (int)size)); if (size > WB_MAX_FRAMELEN || size > *num_bytes) { LOG(("ERROR: Bad frame size: %d", (int)size)); size = *num_bytes; } + *num_bytes = size; memcpy(buf, (void *)device->rxBuffer[current], size); } diff --git a/src/add-ons/kernel/drivers/network/wb840/interface.c b/src/add-ons/kernel/drivers/network/wb840/interface.c index 14d26d893b..62f0ab216b 100644 --- a/src/add-ons/kernel/drivers/network/wb840/interface.c +++ b/src/add-ons/kernel/drivers/network/wb840/interface.c @@ -51,43 +51,7 @@ #define MII_DELAY(x) read32(x->reg_base + WB_SIO) - -void -wb_eeprom_putbyte(wb_device *device, int addr) -{ - int d, i; - int delay; - - d = addr | WB_EECMD_READ; - - /* - * Feed in each bit and strobe the clock. - */ - for (i = 0x400; i; i >>= 1) { - if (d & i) { - SIO_SET(WB_SIO_EE_DATAIN); - } else { - SIO_CLR(WB_SIO_EE_DATAIN); - } - for (delay = 0; delay < 100; delay++) - MII_DELAY(device); - - SIO_SET(WB_SIO_EE_CLK); - - for (delay = 0; delay < 150; delay++) - MII_DELAY(device); - - SIO_CLR(WB_SIO_EE_CLK); - - for (delay = 0; delay < 100; delay++) - MII_DELAY(device); - - } - - return; -} - - + static void mii_sync(struct wb_device *device) { @@ -269,7 +233,7 @@ wb_miibus_readreg(wb_device *device, int phy, int reg) frame.mii_regaddr = reg; wb_mii_readreg(device, &frame); - return(frame.mii_data); + return frame.mii_data; } @@ -298,6 +262,42 @@ wb_miibus_statchg(wb_device *device) #define EEPROM_DELAY(x) read32(x->reg_base + WB_SIO) + +void +wb_eeprom_putbyte(wb_device *device, int addr) +{ + int d, i; + int delay; + + d = addr | WB_EECMD_READ; + + /* + * Feed in each bit and strobe the clock. + */ + for (i = 0x400; i; i >>= 1) { + if (d & i) { + SIO_SET(WB_SIO_EE_DATAIN); + } else { + SIO_CLR(WB_SIO_EE_DATAIN); + } + for (delay = 0; delay < 100; delay++) + MII_DELAY(device); + + SIO_SET(WB_SIO_EE_CLK); + + for (delay = 0; delay < 150; delay++) + MII_DELAY(device); + + SIO_CLR(WB_SIO_EE_CLK); + + for (delay = 0; delay < 100; delay++) + MII_DELAY(device); + + } + + return; +} + static void wb_eeprom_askdata(wb_device *device, int addr) diff --git a/src/add-ons/kernel/drivers/network/wb840/interface.h b/src/add-ons/kernel/drivers/network/wb840/interface.h index e8c93298f0..fd78af92f5 100644 --- a/src/add-ons/kernel/drivers/network/wb840/interface.h +++ b/src/add-ons/kernel/drivers/network/wb840/interface.h @@ -4,6 +4,6 @@ #include "wb840.h" extern void wb_read_eeprom(struct wb_device *, void* dest, int offset, int count, int swap); -extern uint16 mii_read(struct wb_device *, int phy_id, int location); - +extern int wb_miibus_readreg(struct wb_device *, int phy_id, int location); +extern void wb_miibus_writereg(struct wb_device *, int phy, int location, int data); #endif diff --git a/src/add-ons/kernel/drivers/network/wb840/wb840.c b/src/add-ons/kernel/drivers/network/wb840/wb840.c index 2e2b76cc8d..96dec13cff 100644 --- a/src/add-ons/kernel/drivers/network/wb840/wb840.c +++ b/src/add-ons/kernel/drivers/network/wb840/wb840.c @@ -18,6 +18,40 @@ #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) +// MII chip info table + +#define PHY_ID0_WB840_INTERNAL 0x0181 +#define PHY_ID1_WB840_INTERNAL 0xb800 +#define MII_HOME 0x0001 +#define MII_LAN 0x0002 + +const static struct mii_chip_info +{ + const char *name; + uint16 id0, id1; + uint8 types; +} + +gMIIChips[] = { + {"WB840 Internal MII PHY", PHY_ID0_WB840_INTERNAL, PHY_ID1_WB840_INTERNAL, MII_LAN}, + {NULL,0,0,0} +}; + + +static int +mii_readstatus(wb_device *device) +{ + // status bit has to be retrieved 2 times + int i = 0; + int status; + + while (i++ < 2) + status = wb_miibus_readreg(device, device->phy, MII_STATUS); + + return status; +} + + static uint32 physicalAddress(volatile void *addr, uint32 length) { @@ -85,35 +119,117 @@ wb_disable_interrupts(struct wb_device *device) void -wb_reset(wb_device *device) +wb_selectPHY(wb_device *device) { - int i = 0; - cpu_status status; + uint16 status; - LOG((DEVICE_NAME": reset()\n")); + // ToDo: need to be changed, select PHY in relation to the link mode + device->currentPHY = device->firstPHY; + device->phy = device->currentPHY->address; + status = wb_miibus_readreg(device, device->phy, MII_CONTROL); + status &= ~MII_CONTROL_ISOLATE; + + wb_miibus_writereg(device, device->phy, MII_CONTROL, status); +} + + +uint16 +wb_resetPHY(wb_device *device) +{ + uint16 status = mii_readstatus(device); + dprintf("wb_resetPHY: %d\n", status); + wb_miibus_writereg(device, device->phy, MII_CONTROL, MII_CONTROL_RESET); - status = disable_interrupts(); + return status; +} + + +status_t +wb_initPHYs(wb_device *device) +{ + uint16 phy; + // search for total of 32 possible MII PHY addresses + for (phy = 0; phy < 32; phy++) { + struct mii_phy *mii; + uint16 status; + int i = 0; - device->wb_txthresh = WB_TXTHRESH_INIT; + status = wb_miibus_readreg(device, phy, MII_STATUS); + status = wb_miibus_readreg(device, phy, MII_STATUS); + + 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 = wb_miibus_readreg(device, phy, MII_PHY_ID0); + mii->id1 = wb_miibus_readreg(device, phy, MII_PHY_ID1); + mii->types = MII_HOME; + mii->next = device->firstPHY; + device->firstPHY = mii; - write32(device->reg_base + WB_NETCFG, 0L); - write32(device->reg_base + WB_BUSCTL, 0L); - write32(device->reg_base + WB_TXADDR, 0L); - write32(device->reg_base + WB_RXADDR, 0L); - - WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); - WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); - - for (i = 0; i < WB_TIMEOUT; i++) { - if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET)) - break; + while (gMIIChips[i].name != NULL) { + if (gMIIChips[i].id0 == mii->id0 && gMIIChips[i].id1 == (mii->id1 & 0xfff0)) { + dprintf("Found MII PHY: %s\n", gMIIChips[i].name); + mii->types = gMIIChips[i].types; + break; + } + i++; + } + if (gMIIChips[i].name == NULL) + dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n",mii->id0, mii->id1); + } + + if (device->firstPHY == NULL) { + dprintf("No MII PHY transceiver found!\n"); + return B_ENTRY_NOT_FOUND; } - if (i == WB_TIMEOUT) - LOG(("reset hasn't completed!!!")); + wb_selectPHY(device); + + // if the internal PHY is selected, reset it + if (device->currentPHY->id0 == PHY_ID0_WB840_INTERNAL + && (device->currentPHY->id1 & 0xfff0) == PHY_ID1_WB840_INTERNAL) { + if (wb_resetPHY(device) & MII_STATUS_LINK) { + uint16 poll = MII_STATUS_LINK; + while (poll) { + poll ^= wb_miibus_readreg(device, device->phy, 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); + } + */ - write32(device->reg_base + WB_BUSCTL, WB_BUSCTL_MUSTBEONE|WB_BUSCTL_ARBITRATION); - WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG); + device->link = mii_readstatus(device) & MII_STATUS_LINK; + + return B_OK; +} + + +void +wb_init(wb_device *device) +{ + LOG((DEVICE_NAME": init()\n")); + + wb_reset(device); + + device->wb_txthresh = WB_TXTHRESH_INIT; switch(device->wb_cachesize) { case 32: @@ -131,6 +247,9 @@ wb_reset(wb_device *device) break; } + write32(device->reg_base + WB_BUSCTL, WB_BUSCTL_MUSTBEONE|WB_BUSCTL_ARBITRATION); + WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG); + write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG); /* Early TX interrupt; doesn't tend to work too well at 100Mbps */ @@ -150,7 +269,36 @@ wb_reset(wb_device *device) //Disable capture broadcast WB_CLRBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_BROAD); - +} + + +void +wb_reset(wb_device *device) +{ + int i = 0; + cpu_status status; + + LOG((DEVICE_NAME": reset()\n")); + + status = disable_interrupts(); + // XXX: What about a spinlock here ? + + write32(device->reg_base + WB_NETCFG, 0L); + write32(device->reg_base + WB_BUSCTL, 0L); + write32(device->reg_base + WB_TXADDR, 0L); + write32(device->reg_base + WB_RXADDR, 0L); + + WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); + WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); + + for (i = 0; i < WB_TIMEOUT; i++) { + if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET)) + break; + } + + if (i == WB_TIMEOUT) + LOG(("reset hasn't completed!!!")); + restore_interrupts(status); /* Wait a bit while the chip reorders his toughts */ @@ -159,9 +307,42 @@ wb_reset(wb_device *device) //XXX Initialize MII interface } + void wb_updateLink(struct wb_device *device) -{ +{ + if (!device->autoNegotiationComplete) { + int32 mode = wb_read_mode(device); + if (mode) + wb_set_mode(device, mode); + + return; + } + + if (device->link) { // link lost + uint16 status = mii_readstatus(device); + + if ((status & MII_STATUS_LINK) == 0) { + device->link = false; + dprintf(DEVICE_NAME ": link lost\n"); + + // if it's the internal SiS900 MII PHY, reset it + //if (device->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL + // && (device->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) + // sis900_resetPHY(device); + } + } + if (!device->link) { // new link established + uint16 status; + + wb_selectPHY(device); + + status = mii_readstatus(device); + if (status & MII_STATUS_LINK) { + //sis900_checkMode(device); + device->link = true; + } + } } @@ -362,17 +543,19 @@ wb_create_semaphores(struct wb_device *device) { device->rxSem = create_sem(0, "wb840 receive"); if (device->rxSem < B_OK) { - LOG(("Couldn't create sem, sem_id %d\n", (int)device->rxSem)); + LOG(("Couldn't create sem, sem_id %ld\n", device->rxSem)); return device->rxSem; } + set_sem_owner(device->rxSem, B_SYSTEM_TEAM); device->txSem = create_sem(WB_TX_LIST_CNT, "wb840 transmit"); if (device->txSem < B_OK) { - LOG(("Couldn't create sem, sem_id %d\n", (int)device->txSem)); + LOG(("Couldn't create sem, sem_id %ld\n", device->txSem)); delete_sem(device->rxSem); return device->txSem; } + set_sem_owner(device->txSem, B_SYSTEM_TEAM); device->rxLock = 0; @@ -387,9 +570,10 @@ wb_create_rings(struct wb_device *device) { int i; - if ((device->rxArea = create_area("wb840 rx buffer", (void **)&device->rxBuffer[0], + device->rxArea = create_area("wb840 rx buffer", (void **)&device->rxBuffer[0], B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_RX_LIST_CNT), - B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_OK) + B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); + if (device->rxArea < B_OK) return device->rxArea; for (i = 1; i < WB_RX_LIST_CNT; i++) @@ -404,9 +588,10 @@ wb_create_rings(struct wb_device *device) device->rxFree = WB_RX_LIST_CNT; device->rxDescriptor[WB_RX_LIST_CNT - 1].wb_ctl |= WB_RXCTL_RLAST; - if ((device->txArea = create_area("wb840 tx buffer", (void **)&device->txBuffer[0], + device->txArea = create_area("wb840 tx buffer", (void **)&device->txBuffer[0], B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_TX_LIST_CNT), - B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_OK) { + B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); + if (device->txArea < B_OK) { delete_area(device->rxArea); return device->txArea; } @@ -444,3 +629,79 @@ wb_delete_rings(struct wb_device *device) delete_area(device->rxArea); delete_area(device->txArea); } + + +int32 +wb_read_mode(wb_device *info) +{ + uint16 autoAdv, autoLinkPartner; + int32 speed, duplex; + + uint16 status = mii_readstatus(info); + if (!(status & MII_STATUS_LINK)) { + //dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status); + return 0; + } + + // auto negotiation completed + autoAdv = wb_miibus_readreg(info, info->phy, MII_AUTONEG_ADV); + autoLinkPartner = wb_miibus_readreg(info, info->phy, 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; + + dprintf("status: 0x%x\n", status); + 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; +} + + +void +wb_set_mode(wb_device *info, int mode) +{ + /*uint32 address = (uint32)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((uint32)info->registers + SiS900_MAC_Tx_CONFIG, txFlags); + write32((uint32)info->registers + SiS900_MAC_Rx_CONFIG, rxFlags); +*/ +} diff --git a/src/add-ons/kernel/drivers/network/wb840/wb840.h b/src/add-ons/kernel/drivers/network/wb840/wb840.h index 8dc0c32067..f4678d7a47 100644 --- a/src/add-ons/kernel/drivers/network/wb840/wb840.h +++ b/src/add-ons/kernel/drivers/network/wb840/wb840.h @@ -197,17 +197,13 @@ enum interruptMaskBits { WB_IMR_ABNORMAL = 0x00008000, WB_IMR_NORMAL = 0x00010000, }; + #define WB_INTRS \ (WB_IMR_RX_OK|WB_IMR_RX_IDLE|WB_IMR_RX_ERR|WB_IMR_TX_OK| \ WB_IMR_RX_NOBUF|WB_IMR_RX_ERR|WB_IMR_RX_EARLY| \ WB_IMR_TX_NOBUF|WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \ WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY) -/*#define WB_INTRS \ - (WB_IMR_RX_OK|WB_IMR_TX_OK|WB_IMR_RX_ERR| \ - WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \ - WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY) -*/ /* * Serial I/O (EEPROM/ROM) bits. */ @@ -300,11 +296,12 @@ struct wb_desc { #define WB_MAX_FRAMELEN 1536 #define WB_UNSENT 0x1234 -#define WB_BUFBYTES (1024 * sizeof(uint32)) +#define WB_BUFBYTES 2048 /* Ethernet defines */ #define CRC_SIZE 4 #define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)5000000) /* five seconds */ +#define WB_TIMEOUT 1000 typedef struct wb_mii_frame wb_mii_frame; struct wb_mii_frame { @@ -355,9 +352,15 @@ struct wb_device { int16 txInterruptIndex; int16 txSent; + struct mii_phy *firstPHY; + struct mii_phy *currentPHY; + uint16 phy; + bool autoNegotiationComplete; + bool link; + uint16 fixedMode; + volatile int32 blockFlag; - ether_address_t myaddr; /* my ethernet address */ - //volatile int interrupted; /* interrupted system call */ + ether_address_t myaddr; spinlock intLock; const char* deviceName; @@ -366,7 +369,99 @@ struct wb_device { int wb_cachesize; }; -#define WB_TIMEOUT 1000 + + + +/* MII Interface */ + +struct mii_phy { + struct mii_phy *next; + uint16 id0, id1; + uint16 address; + uint8 types; +}; + +// taken from Axel's Sis900 driver +enum MII_address { + // standard registers + MII_CONTROL = 0x00, + MII_STATUS = 0x01, + MII_PHY_ID0 = 0x02, + MII_PHY_ID1 = 0x03, + MII_AUTONEG_ADV = 0x04, + MII_AUTONEG_LINK_PARTNER = 0x05, + MII_AUTONEG_EXT = 0x06 + + // SiS900 specific registers + /*MII_CONFIG1 = 0x10, + MII_CONFIG2 = 0x11, + MII_LINK_STATUS = 0x12, + MII_MASK = 0x13, + MII_RESERVED = 0x14*/ +}; + +enum MII_control { + MII_CONTROL_RESET = 0x8000, + MII_CONTROL_RESET_AUTONEG = 0x0200, + MII_CONTROL_AUTO = 0x1000, + MII_CONTROL_FULL_DUPLEX = 0x0100, + MII_CONTROL_ISOLATE = 0x0400 +}; + +enum MII_commands { + MII_CMD_READ = 0x6000, + MII_CMD_WRITE = 0x5002, + + MII_PHY_SHIFT = 7, + MII_REG_SHIFT = 2, +}; + +enum MII_status_bits { + MII_STATUS_EXT = 0x0001, + MII_STATUS_JAB = 0x0002, + MII_STATUS_LINK = 0x0004, + MII_STATUS_CAN_AUTO = 0x0008, + MII_STATUS_FAULT = 0x0010, + MII_STATUS_AUTO_DONE = 0x0020, + MII_STATUS_CAN_T = 0x0800, + MII_STATUS_CAN_T_FDX = 0x1000, + MII_STATUS_CAN_TX = 0x2000, + MII_STATUS_CAN_TX_FDX = 0x4000, + MII_STATUS_CAN_T4 = 0x8000 +}; + +enum MII_auto_negotiation { + MII_NWAY_NODE_SEL = 0x001f, + MII_NWAY_CSMA_CD = 0x0001, + MII_NWAY_T = 0x0020, + MII_NWAY_T_FDX = 0x0040, + MII_NWAY_TX = 0x0080, + MII_NWAY_TX_FDX = 0x0100, + MII_NWAY_T4 = 0x0200, + MII_NWAY_PAUSE = 0x0400, + MII_NWAY_RF = 0x2000, + MII_NWAY_ACK = 0x4000, + MII_NWAY_NP = 0x8000 +}; + + +enum MII_link_status { + MII_LINK_FAIL = 0x4000, + MII_LINK_100_MBIT = 0x0080, + MII_LINK_FULL_DUPLEX = 0x0040 +}; + +enum link_modes { + LINK_HALF_DUPLEX = 0x0100, + LINK_FULL_DUPLEX = 0x0200, + LINK_DUPLEX_MASK = 0xff00, + + LINK_SPEED_HOME = 1, + LINK_SPEED_10_MBIT = 10, + LINK_SPEED_100_MBIT = 100, + LINK_SPEED_DEFAULT = LINK_SPEED_100_MBIT, + LINK_SPEED_MASK = 0x00ff +}; /* * Vendor and Card IDs @@ -387,13 +482,24 @@ struct wb_device { // Prototypes extern int32 wb_interrupt(void *arg); -extern status_t wb_create_semaphores(struct wb_device *device); -extern status_t wb_create_rings(struct wb_device *device); +extern status_t wb_create_semaphores(wb_device *device); +extern status_t wb_create_rings(wb_device *device); extern void wb_delete_rings(wb_device *device); + +extern void wb_init(wb_device *device); extern void wb_reset(wb_device *device); + +extern status_t wb_initPHYs(wb_device *device); + extern void wb_disable_interrupts(wb_device *device); extern void wb_enable_interrupts(wb_device *device); + +extern void wb_set_mode(wb_device *device, int mode); +extern int32 wb_read_mode(wb_device *device); + extern int32 wb_tick(timer *arg); extern void wb_free_rx_descriptor(wb_desc *desc); +extern void print_address(ether_address_t *addr); + #endif //__WB840_H