pegasus: Replace with the upstream FreeBSD version.

Fixes #19745.

Change-Id: Ie540beecbf9f0a998f016f015357a38d1fa95bfd
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9599
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
Augustin Cavalier
2026-03-16 21:30:32 +00:00
committed by waddlesplash
parent 83be3b3da0
commit d5a5f22579
13 changed files with 1657 additions and 1874 deletions
+1 -1
View File
@@ -327,6 +327,7 @@ SYSTEM_ADD_ONS_DRIVERS_NET = [ FFilterByBuildFeatures
marvell_yukon
nforce
pcnet
pegasus
rtl8125
rtl8139
rtl81xx
@@ -339,7 +340,6 @@ SYSTEM_ADD_ONS_DRIVERS_NET = [ FFilterByBuildFeatures
}@ # x86,x86_64,riscv64
etherpci
pegasus
usb_davicom
usb_rndis
wb840
@@ -2,7 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel drivers network ether ;
# Haiku-native drivers
HaikuSubInclude etherpci ;
HaikuSubInclude pegasus ;
HaikuSubInclude virtio ;
HaikuSubInclude usb_davicom ;
HaikuSubInclude usb_ecm ;
@@ -26,6 +25,7 @@ HaikuSubInclude jmicron2x0 ;
HaikuSubInclude marvell_yukon ;
HaikuSubInclude nforce ;
HaikuSubInclude pcnet ;
HaikuSubInclude pegasus ;
HaikuSubInclude rdc ;
HaikuSubInclude rtl8139 ;
HaikuSubInclude rtl81xx ;
@@ -1,16 +1,31 @@
SubDir HAIKU_TOP src add-ons kernel drivers network ether pegasus ;
SubDirSysHdrs $(HAIKU_TOP) headers os drivers ;
UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ]
: true ;
UsePrivateHeaders net system ;
UsePrivateKernelHeaders ;
# For ether_driver.h
UsePrivateHeaders net ;
SubDirCcFlags [ FDefines _KERNEL=1 FBSD_DRIVER=1 ] ;
UseHeaders [ FDirName $(SUBDIR) ] : true ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) dev usb net ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) dev mii ] ;
KernelAddon pegasus :
driver.c
devlist.c
glue.c
if_aue.c
acphy.c
:
freebsd_usb.a
freebsd_mii.a
libfreebsd_network.a
;
ObjectHdrs [ FGristFiles driver$(SUFOBJ) if_aue$(SUFOBJ) ]
ObjectHdrs [ FGristFiles if_aue$(SUFOBJ) ]
: [ FDirName $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) libs compat freebsd_network ] ;
Includes [ FGristFiles driver.c if_aue.c ] : <src!libs!compat!freebsd_network>usbdevs.h ;
Includes [ FGristFiles if_aue.c ] : <src!libs!compat!freebsd_network>usbdevs.h ;
ObjectHdrs [ FGristFiles acphy$(SUFOBJ) ]
: [ FDirName $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) libs compat freebsd_network ] ;
Includes [ FGristFiles acphy.c ] : <src!libs!compat!freebsd_network>miidevs.h ;
@@ -0,0 +1,242 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 1997 Manuel Bouyer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
/*
* Driver for Altima AC101 10/100 PHY
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <net/if.h>
#include <net/if_media.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include "miidevs.h"
#include <dev/mii/acphyreg.h>
#include "miibus_if.h"
static int acphy_probe(device_t);
static int acphy_attach(device_t);
static device_method_t acphy_methods[] = {
/* device interface */
DEVMETHOD(device_probe, acphy_probe),
DEVMETHOD(device_attach, acphy_attach),
DEVMETHOD(device_detach, mii_phy_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD_END
};
static driver_t acphy_driver = {
"acphy",
acphy_methods,
sizeof(struct mii_softc)
};
DRIVER_MODULE(acphy, miibus, acphy_driver, 0, 0);
static int acphy_service(struct mii_softc *, struct mii_data *, int);
static void acphy_reset(struct mii_softc *);
static void acphy_status(struct mii_softc *);
static const struct mii_phydesc acphys[] = {
MII_PHY_DESC(ALTIMA, AC101),
MII_PHY_DESC(ALTIMA, AC101L),
/* XXX This is reported to work, but it's not from any data sheet. */
MII_PHY_DESC(ALTIMA, ACXXX),
MII_PHY_END
};
static const struct mii_phy_funcs acphy_funcs = {
acphy_service,
acphy_status,
acphy_reset
};
static int
acphy_probe(device_t dev)
{
return (mii_phy_dev_probe(dev, acphys, BUS_PROBE_DEFAULT));
}
static int
acphy_attach(device_t dev)
{
struct mii_softc *sc;
sc = device_get_softc(dev);
mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &acphy_funcs, 0);
PHY_RESET(sc);
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
device_printf(dev, " ");
#define ADD(m) ifmedia_add(&sc->mii_pdata->mii_media, (m), 0, NULL)
if ((PHY_READ(sc, MII_ACPHY_MCTL) & AC_MCTL_FX_SEL) != 0) {
sc->mii_flags |= MIIF_HAVEFIBER;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst));
printf("100baseFX, ");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst));
printf("100baseFX-FDX, ");
}
#undef ADD
mii_phy_add_media(sc);
printf("\n");
MIIBUS_MEDIAINIT(sc->mii_dev);
return (0);
}
static int
acphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
int reg;
switch (cmd) {
case MII_POLLSTAT:
break;
case MII_MEDIACHG:
/* Wake & deisolate up if necessary */
reg = PHY_READ(sc, MII_BMCR);
if (reg & (BMCR_ISO | BMCR_PDOWN))
PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN));
mii_phy_setmedia(sc);
break;
case MII_TICK:
/*
* This PHY's autonegotiation doesn't need to be kicked.
*/
break;
}
/* Update the media status. */
PHY_STATUS(sc);
/* Callback if something changed. */
mii_phy_update(sc, cmd);
return (0);
}
static void
acphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmsr, bmcr, diag;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
bmsr = PHY_READ(sc, MII_BMSR) |
PHY_READ(sc, MII_BMSR);
if (bmsr & BMSR_LINK)
mii->mii_media_status |= IFM_ACTIVE;
bmcr = PHY_READ(sc, MII_BMCR);
if (bmcr & BMCR_ISO) {
mii->mii_media_active |= IFM_NONE;
mii->mii_media_status = 0;
return;
}
if (bmcr & BMCR_LOOP)
mii->mii_media_active |= IFM_LOOP;
if (bmcr & BMCR_AUTOEN) {
if ((bmsr & BMSR_ACOMP) == 0) {
/* Erg, still trying, I guess... */
mii->mii_media_active |= IFM_NONE;
return;
}
diag = PHY_READ(sc, MII_ACPHY_DIAG);
if (diag & AC_DIAG_SPEED)
mii->mii_media_active |= IFM_100_TX;
else
mii->mii_media_active |= IFM_10_T;
if (diag & AC_DIAG_DUPLEX)
mii->mii_media_active |=
IFM_FDX | mii_phy_flowstatus(sc);
else
mii->mii_media_active |= IFM_HDX;
} else
mii->mii_media_active = ife->ifm_media;
}
static void
acphy_reset(struct mii_softc *sc)
{
mii_phy_reset(sc);
PHY_WRITE(sc, MII_ACPHY_INT, 0);
}
@@ -0,0 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Semen Ustimenko ([email protected])
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _DEV_MII_ACPHYREG_H_
#define _DEV_MII_ACPHYREG_H_
/*
* Register definitions for the Altima Communications AC101
*/
#define MII_ACPHY_POL 0x10 /* Polarity int level */
/* High byte is interrupt mask register */
#define MII_ACPHY_INT 0x11 /* Interrupt control/status */
#define AC_INT_ACOMP 0x0001 /* Autoneg complete */
#define AC_INT_REM_FLT 0x0002 /* Remote fault */
#define AC_INT_LINK_DOWN 0x0004 /* Link not OK */
#define AC_INT_LP_ACK 0x0008 /* FLP ack recved */
#define AC_INT_PD_FLT 0x0010 /* Parallel detect fault */
#define AC_INT_PAGE_RECV 0x0020 /* New page recved */
#define AC_INT_RX_ER 0x0040 /* RX_ER transitions high */
#define AC_INT_JAB 0x0080 /* Jabber detected */
#define MII_ACPHY_DIAG 0x12 /* Diagnostic */
#define AC_DIAG_RX_LOCK 0x0100
#define AC_DIAG_RX_PASS 0x0200
#define AC_DIAG_SPEED 0x0400 /* Aneg speed result */
#define AC_DIAG_DUPLEX 0x0800 /* Aneg duplex result */
#define MII_ACPHY_PWRLOOP 0x13 /* Power/Loopback */
#define MII_ACPHY_CBLMEAS 0x14 /* Cable meas. */
#define MII_ACPHY_MCTL 0x15 /* Mode control */
#define AC_MCTL_FX_SEL 0x0001 /* FX mode */
#define AC_MCTL_BYP_PCS 0x0002 /* Bypass PCS */
#define AC_MCTL_SCRMBL 0x0004 /* Data scrambling */
#define AC_MCTL_REM_LOOP 0x0008 /* Remote loopback */
#define AC_MCTL_DIS_WDT 0x0010 /* Disable watchdog timer */
#define AC_MCTL_DIS_REC 0x0020 /* Disable recv error counter */
#define AC_MCTL_REC_FULL 0x0040 /* Recv error counter full */
#define AC_MCTL_FRC_FEF 0x0080 /* Force Far End Fault Insert. */
#define AC_MCTL_DIS_FEF 0x0100 /* Disable FEF Insertion */
#define AC_MCTL_LED_SEL 0x0200 /* Compat LED config */
#define AC_MCTL_ALED_SEL 0x0400 /* ActLED RX&TX - RX only */
#define AC_MCTL_10BT_SEL 0x0800 /* Enable 7-wire interface */
#define AC_MCTL_DIS_JAB 0x1000 /* Disable jabber */
#define AC_MCTL_FRC_LINK 0x2000 /* Force TX link up */
#define AC_MCTL_DIS_NLP 0x4000 /* Disable NLP check */
#define MII_ACPHY_REC 0x18 /* Recv error counter */
#endif /* _DEV_MII_ACPHYREG_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,220 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <[email protected]>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Register definitions for ADMtek Pegasus AN986 USB to Ethernet
* chip. The Pegasus uses a total of four USB endpoints: the control
* endpoint (0), a bulk read endpoint for receiving packets (1),
* a bulk write endpoint for sending packets (2) and an interrupt
* endpoint for passing RX and TX status (3). Endpoint 0 is used
* to read and write the ethernet module's registers. All registers
* are 8 bits wide.
*
* Packet transfer is done in 64 byte chunks. The last chunk in a
* transfer is denoted by having a length less that 64 bytes. For
* the RX case, the data includes an optional RX status word.
*/
#define AUE_UR_READREG 0xF0
#define AUE_UR_WRITEREG 0xF1
#define AUE_CONFIG_INDEX 0 /* config number 1 */
#define AUE_IFACE_IDX 0
/*
* Note that while the ADMtek technically has four endpoints, the control
* endpoint (endpoint 0) is regarded as special by the USB code and drivers
* don't have direct access to it (we access it using usbd_do_request()
* when reading/writing registers. Consequently, our endpoint indexes
* don't match those in the ADMtek Pegasus manual: we consider the RX data
* endpoint to be index 0 and work up from there.
*/
enum {
AUE_BULK_DT_WR,
AUE_BULK_DT_RD,
AUE_INTR_DT_RD,
AUE_N_TRANSFER,
};
#define AUE_INTR_PKTLEN 0x8
#define AUE_CTL0 0x00
#define AUE_CTL1 0x01
#define AUE_CTL2 0x02
#define AUE_MAR0 0x08
#define AUE_MAR1 0x09
#define AUE_MAR2 0x0A
#define AUE_MAR3 0x0B
#define AUE_MAR4 0x0C
#define AUE_MAR5 0x0D
#define AUE_MAR6 0x0E
#define AUE_MAR7 0x0F
#define AUE_MAR AUE_MAR0
#define AUE_PAR0 0x10
#define AUE_PAR1 0x11
#define AUE_PAR2 0x12
#define AUE_PAR3 0x13
#define AUE_PAR4 0x14
#define AUE_PAR5 0x15
#define AUE_PAR AUE_PAR0
#define AUE_PAUSE0 0x18
#define AUE_PAUSE1 0x19
#define AUE_PAUSE AUE_PAUSE0
#define AUE_RX_FLOWCTL_CNT 0x1A
#define AUE_RX_FLOWCTL_FIFO 0x1B
#define AUE_REG_1D 0x1D
#define AUE_EE_REG 0x20
#define AUE_EE_DATA0 0x21
#define AUE_EE_DATA1 0x22
#define AUE_EE_DATA AUE_EE_DATA0
#define AUE_EE_CTL 0x23
#define AUE_PHY_ADDR 0x25
#define AUE_PHY_DATA0 0x26
#define AUE_PHY_DATA1 0x27
#define AUE_PHY_DATA AUE_PHY_DATA0
#define AUE_PHY_CTL 0x28
#define AUE_USB_STS 0x2A
#define AUE_TXSTAT0 0x2B
#define AUE_TXSTAT1 0x2C
#define AUE_TXSTAT AUE_TXSTAT0
#define AUE_RXSTAT 0x2D
#define AUE_PKTLOST0 0x2E
#define AUE_PKTLOST1 0x2F
#define AUE_PKTLOST AUE_PKTLOST0
#define AUE_REG_7B 0x7B
#define AUE_GPIO0 0x7E
#define AUE_GPIO1 0x7F
#define AUE_REG_81 0x81
#define AUE_CTL0_INCLUDE_RXCRC 0x01
#define AUE_CTL0_ALLMULTI 0x02
#define AUE_CTL0_STOP_BACKOFF 0x04
#define AUE_CTL0_RXSTAT_APPEND 0x08
#define AUE_CTL0_WAKEON_ENB 0x10
#define AUE_CTL0_RXPAUSE_ENB 0x20
#define AUE_CTL0_RX_ENB 0x40
#define AUE_CTL0_TX_ENB 0x80
#define AUE_CTL1_HOMELAN 0x04
#define AUE_CTL1_RESETMAC 0x08
#define AUE_CTL1_SPEEDSEL 0x10 /* 0 = 10mbps, 1 = 100mbps */
#define AUE_CTL1_DUPLEX 0x20 /* 0 = half, 1 = full */
#define AUE_CTL1_DELAYHOME 0x40
#define AUE_CTL2_EP3_CLR 0x01 /* reading EP3 clrs status regs */
#define AUE_CTL2_RX_BADFRAMES 0x02
#define AUE_CTL2_RX_PROMISC 0x04
#define AUE_CTL2_LOOPBACK 0x08
#define AUE_CTL2_EEPROMWR_ENB 0x10
#define AUE_CTL2_EEPROM_LOAD 0x20
#define AUE_EECTL_WRITE 0x01
#define AUE_EECTL_READ 0x02
#define AUE_EECTL_DONE 0x04
#define AUE_PHYCTL_PHYREG 0x1F
#define AUE_PHYCTL_WRITE 0x20
#define AUE_PHYCTL_READ 0x40
#define AUE_PHYCTL_DONE 0x80
#define AUE_USBSTS_SUSPEND 0x01
#define AUE_USBSTS_RESUME 0x02
#define AUE_TXSTAT0_JABTIMO 0x04
#define AUE_TXSTAT0_CARLOSS 0x08
#define AUE_TXSTAT0_NOCARRIER 0x10
#define AUE_TXSTAT0_LATECOLL 0x20
#define AUE_TXSTAT0_EXCESSCOLL 0x40
#define AUE_TXSTAT0_UNDERRUN 0x80
#define AUE_TXSTAT1_PKTCNT 0x0F
#define AUE_TXSTAT1_FIFO_EMPTY 0x40
#define AUE_TXSTAT1_FIFO_FULL 0x80
#define AUE_RXSTAT_OVERRUN 0x01
#define AUE_RXSTAT_PAUSE 0x02
#define AUE_GPIO_IN0 0x01
#define AUE_GPIO_OUT0 0x02
#define AUE_GPIO_SEL0 0x04
#define AUE_GPIO_IN1 0x08
#define AUE_GPIO_OUT1 0x10
#define AUE_GPIO_SEL1 0x20
#define AUE_TIMEOUT 100 /* 10*ms */
#define AUE_MIN_FRAMELEN 60
#define AUE_RXSTAT_MCAST 0x01
#define AUE_RXSTAT_GIANT 0x02
#define AUE_RXSTAT_RUNT 0x04
#define AUE_RXSTAT_CRCERR 0x08
#define AUE_RXSTAT_DRIBBLE 0x10
#define AUE_RXSTAT_MASK 0x1E
#define GET_MII(sc) uether_getmii(&(sc)->sc_ue)
struct aue_intrpkt {
uint8_t aue_txstat0;
uint8_t aue_txstat1;
uint8_t aue_rxstat;
uint8_t aue_rxlostpkt0;
uint8_t aue_rxlostpkt1;
uint8_t aue_wakeupstat;
uint8_t aue_rsvd;
} __packed;
struct aue_rxpkt {
uint16_t aue_pktlen;
uint8_t aue_rxstat;
uint8_t pad;
} __packed;
struct aue_softc {
struct usb_ether sc_ue;
struct mtx sc_mtx;
struct usb_xfer *sc_xfer[AUE_N_TRANSFER];
int sc_flags;
#define AUE_FLAG_LSYS 0x0001 /* use Linksys reset */
#define AUE_FLAG_PNA 0x0002 /* has Home PNA */
#define AUE_FLAG_PII 0x0004 /* Pegasus II chip */
#define AUE_FLAG_LINK 0x0008 /* wait for link to come up */
#define AUE_FLAG_VER_2 0x0200 /* chip is version 2 */
#define AUE_FLAG_DUAL_PHY 0x0400 /* chip has two transcivers */
};
#define AUE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AUE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define AUE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)
@@ -1,128 +0,0 @@
/*
* Copyright 2004-2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*
* Some portions of code are copyrighted by
* USB Joystick driver for BeOS R5
* Copyright 2000 (C) ITO, Takayuki. All rights reserved
*/
#include "driver.h"
#include <stdlib.h>
#include <string.h>
sem_id gDeviceListLock = -1;
bool gDeviceListChanged = true; /* added or removed */
/* dynamically generated */
char **gDeviceNames = NULL;
static pegasus_dev *sDeviceList = NULL;
static int sDeviceCount = 0;
void
add_device_info(pegasus_dev *device)
{
ASSERT(device != NULL);
acquire_sem(gDeviceListLock);
device->next = sDeviceList;
sDeviceList = device;
sDeviceCount++;
gDeviceListChanged = true;
release_sem(gDeviceListLock);
}
void
remove_device_info(pegasus_dev *device)
{
ASSERT(device != NULL);
acquire_sem(gDeviceListLock);
if (sDeviceList == device) {
sDeviceList = device->next;
--sDeviceCount;
gDeviceListChanged = true;
} else {
pegasus_dev *previous;
for (previous = sDeviceList; previous != NULL; previous = previous->next) {
if (previous->next == device) {
previous->next = device->next;
--sDeviceCount;
gDeviceListChanged = true;
break;
}
}
ASSERT(previous != NULL);
}
release_sem(gDeviceListLock);
}
pegasus_dev *
search_device_info(const char* name)
{
pegasus_dev *device;
acquire_sem(gDeviceListLock);
for (device = sDeviceList; device != NULL; device = device->next) {
if (strcmp(device->name, name) == 0)
break;
}
release_sem(gDeviceListLock);
return device;
}
// #pragma mark - device names
void
alloc_device_names(void)
{
ASSERT(gDeviceNames == NULL);
gDeviceNames = malloc(sizeof(char *) * (sDeviceCount + 1));
}
void
free_device_names(void)
{
if (gDeviceNames != NULL) {
int i;
for (i = 0; gDeviceNames [i] != NULL; i++) {
free(gDeviceNames[i]);
}
free(gDeviceNames);
gDeviceNames = NULL;
}
}
void
rebuild_device_names(void)
{
int i;
pegasus_dev *device;
ASSERT(gDeviceNames != NULL);
acquire_sem(gDeviceListLock);
for (i = 0, device = sDeviceList; device != NULL; device = device->next) {
gDeviceNames[i++] = strdup(device->name);
DPRINTF_INFO(MY_ID "publishing %s\n", device->name);
}
gDeviceNames[i] = NULL;
release_sem(gDeviceListLock);
}
@@ -1,837 +0,0 @@
/*
* Pegasus BeOS Driver
*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "driver.h"
#include "usbdevs.h"
typedef struct driver_cookie {
struct driver_cookie *next;
pegasus_dev *device;
} driver_cookie;
int32 api_version = B_CUR_DRIVER_API_VERSION;
static status_t pegasus_device_added(const usb_device dev, void **cookie);
static status_t pegasus_device_removed(void *cookie);
static int sDeviceNumber = 0;
static const char *kBaseName = "net/pegasus/";
static const char *kDriverName = DRIVER_NAME;
usb_module_info *usb;
usb_support_descriptor supported_devices[] = {
{ 0, 0, 0, USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10},
{ 0, 0, 0, USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA},
{ 0, 0, 0, USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC},
{ 0, 0, 0, USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001},
{ 0, 0, 0, USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS},
{ 0, 0, 0, USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII},
{ 0, 0, 0, USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2},
{ 0, 0, 0, USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3},
{ 0, 0, 0, USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN},
{ 0, 0, 0, USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100},
{ 0, 0, 0, USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100},
{ 0, 0, 0, USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100},
{ 0, 0, 0, USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100},
{ 0, 0, 0, USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX},
{ 0, 0, 0, USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2},
{ 0, 0, 0, USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650},
{ 0, 0, 0, USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0},
{ 0, 0, 0, USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1},
{ 0, 0, 0, USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2},
{ 0, 0, 0, USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3},
{ 0, 0, 0, USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX},
{ 0, 0, 0, USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET},
{ 0, 0, 0, USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100},
{ 0, 0, 0, USB_VENDOR_HP, USB_PRODUCT_HP_HN210E},
{ 0, 0, 0, USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX},
{ 0, 0, 0, USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS},
{ 0, 0, 0, USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA},
{ 0, 0, 0, USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2},
{ 0, 0, 0, USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110},
{ 0, 0, 0, USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1},
{ 0, 0, 0, USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5},
{ 0, 0, 0, USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5},
{ 0, 0, 0, USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101},
{ 0, 0, 0, USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM},
{ 0, 0, 0, USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},
{ 0, 0, 0, USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB},
{ 0, 0, 0, USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB},
{ 0, 0, 0, USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100},
};
static const struct aue_type aue_devs[] = {
{{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA|PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 },
{{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 },
{{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 },
{{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII },
{{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA },
{{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII },
{{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII },
{{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII },
{{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII },
{{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 },
{{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA },
{{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 },
{{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII },
{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 },
{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS|PII },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS|PII },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS|PII },
{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, LSYS },
{{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 },
{{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS },
{{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 },
{{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS },
{{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII },
{{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 },
{{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII },
{{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII },
{{ USB_VENDOR_IODATA, 0x092a /* USB_PRODUCT_IODATA_ETXUS2 */}, PII },
{{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 },
{{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII },
{{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS|PII },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS|PNA },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS },
{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS|PII },
{{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII },
{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 },
{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 },
{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII },
{{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII },
{{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII },
{{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII },
{{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 },
{{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII },
{{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 },
};
static status_t
pegasus_checkdeviceinfo(pegasus_dev *dev)
{
if (!dev || dev->cookieMagic != PEGASUS_COOKIE_MAGIC)
return EINVAL;
return B_OK;
}
pegasus_dev *
create_device(const usb_device dev, const usb_interface_info *ii, uint16 ifno)
{
pegasus_dev *device = NULL;
sem_id sem;
ASSERT(usb != NULL && dev != 0);
device = malloc(sizeof(pegasus_dev));
if (device == NULL)
return NULL;
memset(device, 0, sizeof(pegasus_dev));
device->sem_lock = sem = create_sem(1, DRIVER_NAME "_lock");
if (sem < B_OK) {
DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
free(device);
return NULL;
}
device->rx_sem = sem = create_sem(1, DRIVER_NAME"_receive");
if (sem < B_OK) {
DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
delete_sem(device->sem_lock);
free(device);
return NULL;
}
set_sem_owner(device->rx_sem, B_SYSTEM_TEAM);
device->rx_sem_cb = sem = create_sem(0, DRIVER_NAME"_receive_cb");
if (sem < B_OK) {
DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
delete_sem(device->rx_sem);
delete_sem(device->sem_lock);
free(device);
return NULL;
}
set_sem_owner(device->rx_sem_cb, B_SYSTEM_TEAM);
device->tx_sem = sem = create_sem(1, DRIVER_NAME"_transmit");
if (sem < B_OK) {
delete_sem(device->sem_lock);
delete_sem(device->rx_sem);
delete_sem(device->rx_sem_cb);
free(device);
return NULL;
}
set_sem_owner(device->tx_sem, B_SYSTEM_TEAM);
device->tx_sem_cb = sem = create_sem(0, DRIVER_NAME"_transmit_cb");
if (sem < B_OK) {
delete_sem(device->sem_lock);
delete_sem(device->rx_sem);
delete_sem(device->rx_sem_cb);
delete_sem(device->tx_sem);
free(device);
return NULL;
}
set_sem_owner(device->tx_sem_cb, B_SYSTEM_TEAM);
device->number = sDeviceNumber++;
device->cookieMagic = PEGASUS_COOKIE_MAGIC;
sprintf(device->name, "%s%d", kBaseName, device->number);
device->dev = dev;
device->ifno = ifno;
device->open = 0;
device->open_fds = NULL;
device->aue_dying = false;
device->flags = 0;
device->maxframesize = 1514; // XXX is MAXIMUM_ETHERNET_FRAME_SIZE = 1518 too much?
return device;
}
void
remove_device(pegasus_dev *device)
{
ASSERT(device != NULL);
delete_sem(device->rx_sem);
delete_sem(device->tx_sem);
delete_sem(device->rx_sem_cb);
delete_sem(device->tx_sem_cb);
delete_sem(device->sem_lock);
free(device);
}
/**
\fn:
*/
static status_t
setup_endpoints(const usb_interface_info *uii, pegasus_dev *dev)
{
ssize_t epts[3] = { -1, -1, -1 };
size_t ep = 0;
for(; ep < uii->endpoint_count; ep++){
usb_endpoint_descriptor *ed = uii->endpoint[ep].descr;
DPRINTF_INFO("try endpoint:%ld %x %x %lx\n", ep, ed->attributes,
ed->endpoint_address, uii->endpoint[ep].handle);
if ((ed->attributes & USB_ENDPOINT_ATTR_MASK) == USB_ENDPOINT_ATTR_BULK) {
if ((ed->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
== USB_ENDPOINT_ADDR_DIR_IN) {
epts[0] = ep;
} else
epts[1] = ep;
} else if ((ed->attributes & USB_ENDPOINT_ATTR_MASK)
== USB_ENDPOINT_ATTR_INTERRUPT) {
epts[2] = ep;
}
}
dev->pipe_in = uii->endpoint[epts[0]].handle;
dev->pipe_out = uii->endpoint[epts[1]].handle;
dev->pipe_intr = uii->endpoint[epts[2]].handle;
DPRINTF_INFO("endpoint:%lx %lx %lx\n", dev->pipe_in, dev->pipe_out, dev->pipe_intr);
return ((epts[0] > -1) && (epts[1] > -1) && (epts[2] > -1)) ? B_OK : B_ENTRY_NOT_FOUND;
}
static void
pegasus_rx_callback(void *cookie, status_t status, void *data, size_t actual_len)
{
pegasus_dev *dev = (pegasus_dev *)cookie;
DPRINTF_INFO("pegasus_rx_callback() %ld %ld\n", status, actual_len);
if (status == B_CANCELED) {
/* cancelled: device is unplugged */
DPRINTF_ERR("pegasus_rx_callback() cancelled\n");
return;
}
ASSERT(cookie != NULL);
dev->rx_actual_length = actual_len;
dev->rx_status = status; /* B_USB_STATUS_* */
release_sem(dev->rx_sem_cb);
DPRINTF_INFO("pegasus_rx_callback release sem %ld\n", dev->rx_sem_cb);
}
static void
pegasus_tx_callback(void *cookie, status_t status, void *data, size_t actual_len)
{
pegasus_dev *dev = (pegasus_dev *)cookie;
DPRINTF_INFO("pegasus_tx_callback() %ld %ld\n", status, actual_len);
if (status == B_CANCELED) {
/* cancelled: device is unplugged */
DPRINTF_ERR("pegasus_tx_callback() cancelled\n");
return;
}
ASSERT(cookie != NULL);
dev->tx_actual_length = actual_len;
dev->tx_status = status; /* B_USB_STATUS_* */
release_sem(dev->tx_sem_cb);
DPRINTF_INFO("pegasus_tx_callback release sem %ld\n", dev->tx_sem_cb);
}
// #pragma mark - device hooks
static status_t
pegasus_device_added(const usb_device dev, void **cookie)
{
pegasus_dev *device;
const usb_device_descriptor *dev_desc;
const usb_configuration_info *conf;
const usb_interface_info *intf;
status_t status;
uint16 ifno;
unsigned int i;
ASSERT(dev != 0 && cookie != NULL);
DPRINTF_INFO("device_added()\n");
dev_desc = usb->get_device_descriptor(dev);
DPRINTF_INFO("vendor ID 0x%04X, product ID 0x%04X\n", dev_desc->vendor_id,
dev_desc->product_id);
if ((conf = usb->get_nth_configuration(dev, DEFAULT_CONFIGURATION))
== NULL) {
DPRINTF_ERR("cannot get default configuration\n");
return B_ERROR;
}
ifno = AUE_IFACE_IDX;
intf = conf->interface [ifno].active;
/* configuration */
if ((status = usb->set_configuration(dev, conf)) != B_OK) {
DPRINTF_ERR("set_configuration() failed %s\n", strerror(status));
return B_ERROR;
}
if ((device = create_device(dev, intf, ifno)) == NULL) {
DPRINTF_ERR("create_device() failed\n");
return B_ERROR;
}
device->aue_vendor = dev_desc->vendor_id;
device->aue_product = dev_desc->product_id;
for (i=0; i < sizeof(aue_devs) / sizeof(struct aue_type); i++)
if (aue_devs[i].aue_dev.vendor == dev_desc->vendor_id
&& aue_devs[i].aue_dev.product == dev_desc->product_id) {
device->aue_flags = aue_devs[i].aue_flags;
break;
}
/* Find endpoints. */
setup_endpoints(intf, device);
aue_attach(device);
DPRINTF_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
device->macaddr[0], device->macaddr[1], device->macaddr[2],
device->macaddr[3], device->macaddr[4], device->macaddr[5]);
aue_init(device);
/* create a port */
add_device_info(device);
*cookie = device;
DPRINTF_INFO("added %s\n", device->name);
return B_OK;
}
static status_t
pegasus_device_removed(void *cookie)
{
pegasus_dev *device = cookie;
ASSERT(cookie != NULL);
DPRINTF_INFO("device_removed(%s)\n", device->name);
aue_uninit(device);
usb->cancel_queued_transfers(device->pipe_in);
usb->cancel_queued_transfers(device->pipe_out);
usb->cancel_queued_transfers(device->pipe_intr);
remove_device_info(device);
if (device->open == 0) {
remove_device(device);
} else {
DPRINTF_INFO("%s still open\n", device->name);
AUE_LOCK(device);
device->aue_dying = true;
AUE_UNLOCK(device);
}
return B_OK;
}
static status_t
pegasus_device_open(const char *name, uint32 flags,
driver_cookie **out_cookie)
{
driver_cookie *cookie;
pegasus_dev *device;
status_t err;
ASSERT(name != NULL);
ASSERT(out_cookie != NULL);
DPRINTF_INFO("open(%s)\n", name);
if ((device = search_device_info(name)) == NULL)
return B_ENTRY_NOT_FOUND;
if ((cookie = malloc(sizeof(driver_cookie))) == NULL)
return B_NO_MEMORY;
if ((err = acquire_sem(device->sem_lock)) != B_OK) {
free(cookie);
return err;
}
device->nonblocking = (flags & O_NONBLOCK) != 0;
cookie->device = device;
cookie->next = device->open_fds;
device->open_fds = cookie;
device->open++;
release_sem(device->sem_lock);
*out_cookie = cookie;
DPRINTF_INFO("device %s open (%d)\n", name, device->open);
return B_OK;
}
static status_t
pegasus_device_read(driver_cookie *cookie, off_t position, void *buffer, size_t *_length)
{
pegasus_dev *dev;
status_t status;
int32 blockFlag;
size_t size;
DPRINTF_INFO("device %p read\n", cookie);
if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) {
DPRINTF_ERR("EINVAL\n");
#ifndef __HAIKU__
*_length = 0;
// net_server work-around; it obviously doesn't care about error conditions
// For Haiku, this can be removed
#endif
return B_BAD_VALUE;
}
if (dev->aue_dying)
return B_DEVICE_NOT_FOUND; /* already unplugged */
blockFlag = dev->nonblocking ? B_TIMEOUT : 0;
// block until receive is available (if blocking is allowed)
if ((status = acquire_sem_etc(dev->rx_sem, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) {
DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status));
#ifndef __HAIKU__
*_length = 0;
#endif
return status;
}
// queue new request
status = usb->queue_bulk(dev->pipe_in, dev->rx_buffer, MAX_FRAME_SIZE, &pegasus_rx_callback, dev);
if (status != B_OK) {
DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
goto rx_done;
}
// block until data is available (if blocking is allowed)
if ((status = acquire_sem_etc(dev->rx_sem_cb, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) {
DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status));
#ifndef __HAIKU__
*_length = 0;
#endif
goto rx_done;
}
if (dev->rx_status != B_OK) {
status = usb->clear_feature(dev->pipe_in, USB_FEATURE_ENDPOINT_HALT);
if (status != B_OK)
DPRINTF_ERR("clear_feature() error %s\n", strerror(status));
goto rx_done;
}
// copy buffer
size = dev->rx_actual_length;
if (size > MAX_FRAME_SIZE || (size - 2) > *_length) {
DPRINTF_ERR("ERROR read: bad frame size %ld\n", size);
size = *_length;
} else if (size < *_length)
*_length = size - 2;
memcpy(buffer, dev->rx_buffer, size);
DPRINTF_INFO("read done %ld\n", *_length);
rx_done:
release_sem(dev->rx_sem);
return status;
}
static status_t
pegasus_device_write(driver_cookie *cookie, off_t position, const void *buffer, size_t *_length)
{
pegasus_dev *dev;
status_t status;
uint16 frameSize;
DPRINTF_INFO("device %p write %ld\n", cookie, *_length);
if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) {
DPRINTF_ERR("EINVAL\n");
return EINVAL;
}
if (dev->aue_dying)
return B_DEVICE_NOT_FOUND; /* already unplugged */
// block until a free tx descriptor is available
if ((status = acquire_sem_etc(dev->tx_sem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT)) < B_NO_ERROR) {
DPRINTF_ERR("write: acquiring sem failed: %" B_PRIx32 ", %s\n", status, strerror(status));
return status;
}
if (*_length > MAX_FRAME_SIZE)
*_length = MAX_FRAME_SIZE;
frameSize = *_length;
/* Copy data to tx buffer */
memcpy(dev->tx_buffer+2, buffer, frameSize);
/*
* The ADMtek documentation says that the packet length is
* supposed to be specified in the first two bytes of the
* transfer, however it actually seems to ignore this info
* and base the frame size on the bulk transfer length.
*/
dev->tx_buffer[0] = (uint8)frameSize;
dev->tx_buffer[1] = (uint8)(frameSize >> 8);
// queue new request, bulk length is one more if size is a multiple of 64
status = usb->queue_bulk(dev->pipe_out, dev->tx_buffer, ((frameSize + 2) & 0x3f) ? frameSize + 2 : frameSize + 3,
&pegasus_tx_callback, dev);
if (status != B_OK){
DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
goto tx_done;
}
// block until data is sent (if blocking is allowed)
if ((status = acquire_sem_etc(dev->tx_sem_cb, 1, B_CAN_INTERRUPT, 0)) != B_NO_ERROR) {
DPRINTF_ERR("cannot acquire write done sem: %" B_PRIx32 ", %s\n", status, strerror(status));
#ifndef __HAIKU__
*_length = 0;
#endif
goto tx_done;
}
if (dev->tx_status != B_OK) {
status = usb->clear_feature(dev->pipe_out, USB_FEATURE_ENDPOINT_HALT);
if (status != B_OK)
DPRINTF_ERR("clear_feature() error %s\n", strerror(status));
goto tx_done;
}
*_length = frameSize;
tx_done:
release_sem(dev->tx_sem);
return status;
}
static status_t
pegasus_device_control(driver_cookie *cookie, uint32 op,
void *arg, size_t len)
{
status_t err = B_ERROR;
pegasus_dev *device;
ASSERT(cookie != NULL);
device = cookie->device;
ASSERT(device != NULL);
DPRINTF_INFO("ioctl(0x%x)\n", (int)op);
if (device->aue_dying)
return B_DEVICE_NOT_FOUND; /* already unplugged */
switch (op) {
case ETHER_INIT:
DPRINTF_INFO("control() ETHER_INIT\n");
return B_OK;
case ETHER_GETADDR:
DPRINTF_INFO("control() ETHER_GETADDR\n");
memcpy(arg, &device->macaddr, sizeof(device->macaddr));
return B_OK;
case ETHER_NONBLOCK:
if (*(int32 *)arg) {
DPRINTF_INFO("non blocking mode on\n");
device->nonblocking = true;
} else {
DPRINTF_INFO("non blocking mode off\n");
device->nonblocking = false;
}
return B_OK;
case ETHER_ADDMULTI:
DPRINTF_INFO("control() ETHER_ADDMULTI\n");
break;
case ETHER_REMMULTI:
DPRINTF_INFO("control() ETHER_REMMULTI\n");
return B_OK;
case ETHER_SETPROMISC:
if (*(int32 *)arg) {
DPRINTF_INFO("control() ETHER_SETPROMISC on\n");
} else {
DPRINTF_INFO("control() ETHER_SETPROMISC off\n");
}
return B_OK;
case ETHER_GETFRAMESIZE:
DPRINTF_INFO("control() ETHER_GETFRAMESIZE, framesize = %ld (MTU = %ld)\n", device->maxframesize, device->maxframesize - ENET_HEADER_SIZE);
*(uint32*)arg = device->maxframesize;
return B_OK;
default:
DPRINTF_INFO("control() Invalid command\n");
break;
}
return err;
}
static status_t
pegasus_device_close(driver_cookie *cookie)
{
pegasus_dev *device;
ASSERT(cookie != NULL && cookie->device != NULL);
device = cookie->device;
DPRINTF_INFO("close(%s)\n", device->name);
/* detach the cookie from list */
acquire_sem(device->sem_lock);
if (device->open_fds == cookie)
device->open_fds = cookie->next;
else {
driver_cookie *p;
for (p = device->open_fds; p != NULL; p = p->next) {
if (p->next == cookie) {
p->next = cookie->next;
break;
}
}
}
--device->open;
release_sem(device->sem_lock);
return B_OK;
}
static status_t
pegasus_device_free(driver_cookie *cookie)
{
pegasus_dev *device;
ASSERT(cookie != NULL && cookie->device != NULL);
device = cookie->device;
DPRINTF_INFO("free(%s)\n", device->name);
free(cookie);
if (device->open > 0)
DPRINTF_INFO("%d opens left\n", device->open);
else if (device->aue_dying) {
DPRINTF_INFO("removed %s\n", device->name);
remove_device(device);
}
return B_OK;
}
/* Driver Hooks ---------------------------------------------------------
**
** These functions provide the glue used by DevFS to load/unload
** the driver and also handle registering with the USB bus manager
** to receive device added and removed events
*/
static usb_notify_hooks notify_hooks =
{
&pegasus_device_added,
&pegasus_device_removed
};
status_t
init_hardware(void)
{
return B_OK;
}
status_t
init_driver(void)
{
DPRINTF_INFO("init_driver(), built %s %s\n", __DATE__, __TIME__);
#if DEBUG_DRIVER
if (load_driver_symbols(drivername) == B_OK) {
DPRINTF_INFO("loaded symbols\n");
} else {
DPRINTF_INFO("no symbols for you!\n");
}
#endif
if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) {
DPRINTF_INFO("cannot get module \"%s\"\n", B_USB_MODULE_NAME);
return B_ERROR;
}
if ((gDeviceListLock = create_sem(1, "dev_list_lock")) < 0) {
put_module(B_USB_MODULE_NAME);
return gDeviceListLock;
}
usb->register_driver(kDriverName, supported_devices,
sizeof(supported_devices)/sizeof(usb_support_descriptor), NULL);
usb->install_notify(kDriverName, &notify_hooks);
return B_OK;
}
void
uninit_driver(void)
{
DPRINTF_INFO("uninit_driver()\n");
usb->uninstall_notify(kDriverName);
delete_sem(gDeviceListLock);
put_module(B_USB_MODULE_NAME);
free_device_names();
}
const char**
publish_devices(void)
{
if (gDeviceListChanged) {
free_device_names();
alloc_device_names();
if (gDeviceNames != NULL)
rebuild_device_names();
gDeviceListChanged = false;
}
ASSERT(gDeviceNames != NULL);
return (const char **) gDeviceNames;
}
device_hooks*
find_device(const char* name)
{
static device_hooks hooks = {
(device_open_hook)pegasus_device_open,
(device_close_hook)pegasus_device_close,
(device_free_hook)pegasus_device_free,
(device_control_hook)pegasus_device_control,
(device_read_hook)pegasus_device_read,
(device_write_hook)pegasus_device_write,
NULL
};
if (search_device_info(name) != NULL)
return &hooks;
return NULL;
}
@@ -1,166 +0,0 @@
/*
* Pegasus BeOS Driver
*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#ifndef _DEV_PEGASUS_H_
#define _DEV_PEGASUS_H_
#include <Drivers.h>
#include <OS.h>
#include <SupportDefs.h>
#include <USB3.h>
#include "ether_driver.h"
#include "ByteOrder.h"
// compat
#define u_uint8_t uint8
#define u_uint16_t uint16
#define u_int8_t int8
#define u_int16_t int16
#define DELAY snooze
#include "if_auereg.h"
#define VERSION "Version 0, Copyright (c) 2006 Jérôme Duval, compiled on " ## __DATE__ ## " " ## __TIME__
#define DRIVER_NAME "pegasus"
#define MY_ID "\033[34m" DRIVER_NAME ":\033[m "
#define MY_ERR "\033[31merror:\033[m "
#define MY_WARN "\033[31mwarning:\033[m "
//#define DEBUG 1
#if DEBUG
#define DPRINTF_INFO(x...) dprintf(MY_ID x)
#define DPRINTF_ERR(x...) dprintf(MY_ID x)
#else
#define DPRINTF_INFO(x...)
#define DPRINTF_ERR(x...) dprintf(MY_ID x)
#endif
#define ASSERT(x) \
((x) ? 0 : dprintf (MY_ID "assertion failed at " __FILE__ ", line %d\n", __LINE__))
#define NUM_CARDS 3
#define DEVNAME 32
#define DEFAULT_CONFIGURATION 0
#define ENET_HEADER_SIZE 14
#define ETHER_ADDRESS_LENGTH 6
#define MAX_FRAME_SIZE 1536
#define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)5000000)
/* five seconds */
/*
* Various supported device vendors/products.
*/
struct aue_type {
struct usb_devno {
uint16 vendor;
uint16 product;
} aue_dev;
uint16 aue_flags;
#define LSYS 0x0001 /* use Linksys reset */
#define PNA 0x0002 /* has Home PNA */
#define PII 0x0004 /* Pegasus II chip */
};
/*
* Devices
*/
typedef struct _pegasus_dev {
/* list structure */
struct _pegasus_dev *next;
uint32 cookieMagic;
/* maintain device */
sem_id sem_lock;
char name[DEVNAME]; /* used for resources */
int type;
usb_device dev;
uint16 aue_vendor;
uint16 aue_product;
uint16 ifno;
int open;
struct driver_cookie *open_fds;
volatile bool aue_dying;
int number;
uint flags;
int aue_unit;
uint16 aue_flags;
volatile bool nonblocking;
uint32 maxframesize; // 14 bytes header + MTU
uint8 macaddr[6];
usb_pipe pipe_in; /**/
usb_pipe pipe_out; /**/
usb_pipe pipe_intr; /**/
uint16 phy;
bool link;
// receive data
sem_id rx_sem;
sem_id rx_sem_cb;
char rx_buffer[MAX_FRAME_SIZE];
status_t rx_status;
size_t rx_actual_length;
// transmit data
sem_id tx_sem;
sem_id tx_sem_cb;
char tx_buffer[MAX_FRAME_SIZE];
status_t tx_status;
size_t tx_actual_length;
} pegasus_dev;
#define PEGASUS_COOKIE_MAGIC 'pega'
/* driver.c */
extern usb_module_info *usb;
pegasus_dev *create_device(const usb_device dev, const usb_interface_info *ii, uint16 ifno);
void remove_device(pegasus_dev *device);
/* devlist.c */
extern sem_id gDeviceListLock;
extern bool gDeviceListChanged;
void add_device_info(pegasus_dev *device);
void remove_device_info(pegasus_dev *device);
pegasus_dev *search_device_info(const char *name);
extern char **gDeviceNames;
void alloc_device_names(void);
void free_device_names(void);
void rebuild_device_names(void);
/* if_aue.c */
void aue_attach(pegasus_dev *sc);
void aue_init(pegasus_dev *sc);
void aue_uninit(pegasus_dev *sc);
#endif /* _DEV_PEGASUS_H_ */
@@ -0,0 +1,27 @@
/*
* Copyright 2025, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#include <sys/bus.h>
extern driver_t* DRIVER_MODULE_NAME(aue, uhub);
HAIKU_FBSD_DRIVERS_GLUE(pegasus)
HAIKU_DRIVER_REQUIREMENTS(0);
HAIKU_FBSD_MII_DRIVER(acphy);
NO_HAIKU_CHECK_DISABLE_INTERRUPTS();
NO_HAIKU_REENABLE_INTERRUPTS();
void
__haiku_init_hardware()
{
driver_t *usb_drivers[] = {
DRIVER_MODULE_NAME(aue, uhub),
NULL
};
_fbsd_init_hardware_uhub(usb_drivers);
}
@@ -1,458 +0,0 @@
/*
* Pegasus BeOS Driver
*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
/*-
* Copyright (c) 1997, 1998, 1999, 2000
* Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "driver.h"
#include "usbdevs.h"
extern usb_module_info *usb;
#define AUE_SETBIT(sc, reg, x) \
aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
#define AUE_CLRBIT(sc, reg, x) \
aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
static int
aue_csr_read_1(pegasus_dev *sc, int reg)
{
status_t err;
uint8 val = 0;
size_t length;
if (sc->aue_dying)
return (0);
AUE_LOCK(sc);
err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
AUE_UR_READREG, 0, reg, 1, &val, &length);
AUE_UNLOCK(sc);
if (err) {
return (0);
}
return (val);
}
static int
aue_csr_read_2(pegasus_dev *sc, int reg)
{
status_t err;
uint16 val = 0;
size_t length;
if (sc->aue_dying)
return (0);
AUE_LOCK(sc);
err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
AUE_UR_READREG, 0, reg, 2, &val, &length);
AUE_UNLOCK(sc);
if (err) {
return (0);
}
return (val);
}
static int
aue_csr_write_1(pegasus_dev *sc, int reg, int val)
{
status_t err;
size_t length = 1;
if (sc->aue_dying)
return (0);
AUE_LOCK(sc);
err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
AUE_UR_WRITEREG, val, reg, 1, &val, &length);
AUE_UNLOCK(sc);
if (err) {
return (-1);
}
return (0);
}
static int
aue_csr_write_2(pegasus_dev *sc, int reg, int val)
{
status_t err;
size_t length = 2;
if (sc->aue_dying)
return (0);
AUE_LOCK(sc);
err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
AUE_UR_WRITEREG, val, reg, 2, &val, &length);
AUE_UNLOCK(sc);
if (err) {
return (-1);
}
return (0);
}
/*
* Read a word of data stored in the EEPROM at address 'addr.'
*/
static void
aue_eeprom_getword(pegasus_dev *sc, int addr, u_int16_t *dest)
{
int i;
u_int16_t word = 0;
aue_csr_write_1(sc, AUE_EE_REG, addr);
aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ);
for (i = 0; i < AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
break;
}
if (i == AUE_TIMEOUT) {
dprintf("aue%d: EEPROM read timed out\n",
sc->aue_unit);
}
word = aue_csr_read_2(sc, AUE_EE_DATA);
*dest = word;
return;
}
/*
* Read a sequence of words from the EEPROM.
*/
static void
aue_read_eeprom(pegasus_dev *sc, caddr_t dest, int off, int cnt, int swap)
{
int i;
u_int16_t word = 0, *ptr;
for (i = 0; i < cnt; i++) {
aue_eeprom_getword(sc, off + i, &word);
ptr = (u_int16_t *)(dest + (i * 2));
if (swap)
*ptr = B_BENDIAN_TO_HOST_INT16(word);
else
*ptr = word;
}
return;
}
static int
aue_miibus_readreg(pegasus_dev *sc, int phy, int reg)
{
int i;
u_int16_t val = 0;
/*
* The Am79C901 HomePNA PHY actually contains
* two transceivers: a 1Mbps HomePNA PHY and a
* 10Mbps full/half duplex ethernet PHY with
* NWAY autoneg. However in the ADMtek adapter,
* only the 1Mbps PHY is actually connected to
* anything, so we ignore the 10Mbps one. It
* happens to be configured for MII address 3,
* so we filter that out.
*/
if (sc->aue_vendor == USB_VENDOR_ADMTEK &&
sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) {
if (phy == 3)
return (0);
#ifdef notdef
if (phy != 1)
return (0);
#endif
}
aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
for (i = 0; i < AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
break;
}
if (i == AUE_TIMEOUT) {
dprintf("aue%d: MII read timed out\n", sc->aue_unit);
}
val = aue_csr_read_2(sc, AUE_PHY_DATA);
return (val);
}
static int
aue_miibus_writereg(pegasus_dev *sc, int phy, int reg, int data)
{
int i;
if (phy == 3)
return (0);
aue_csr_write_2(sc, AUE_PHY_DATA, data);
aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
for (i = 0; i < AUE_TIMEOUT; i++) {
if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
break;
}
if (i == AUE_TIMEOUT) {
dprintf("aue%d: MII read timed out\n",
sc->aue_unit);
}
return (0);
}
static uint16
aue_miibus_read(pegasus_dev *dev, uint16 reg)
{
return aue_miibus_readreg(dev, dev->phy, reg);
}
static void
aue_miibus_write(pegasus_dev *dev, uint16 reg, uint16 value)
{
aue_miibus_writereg(dev, dev->phy, reg, value);
}
static uint16
aue_miibus_status_from_phy(pegasus_dev *dev, uint16 phy)
{
uint16 status;
int i = 0;
// the status must be retrieved two times, because the first
// one may not work on some PHYs (notably ICS 1893)
while (i++ < 2)
status = aue_miibus_readreg(dev, phy, MII_STATUS);
return status;
}
static uint16
aue_miibus_status(pegasus_dev *dev)
{
return aue_miibus_status_from_phy(dev, dev->phy);
}
static status_t
aue_init_phy(pegasus_dev *dev)
{
uint16 phy, status;
int i;
dev->phy = 255;
// search for total of 32 possible MII PHY addresses
for (phy = 0; phy < 32; phy++) {
uint16 status;
status = aue_miibus_status_from_phy(dev, phy);
if (status == 0xffff || status == 0x0000)
// this MII is not accessable
continue;
dev->phy = phy;
}
if (dev->phy == 255) {
DPRINTF_ERR("No MII PHY transceiver found!\n");
return B_ENTRY_NOT_FOUND;
}
DPRINTF_INFO("aue_init_phy MII PHY found at %d\n", dev->phy);
status = aue_miibus_read(dev, MII_CONTROL);
status &= ~MII_CONTROL_ISOLATE;
aue_miibus_write(dev, MII_CONTROL, status);
aue_miibus_write(dev, MII_CONTROL, MII_CONTROL_RESET);
for (i = 0; i < 100; i++) {
if ((aue_miibus_read(dev, MII_STATUS) & MII_CONTROL_RESET) == 0)
break;
DELAY(1000);
}
dev->link = aue_miibus_status(dev) & MII_STATUS_LINK;
return B_OK;
}
static void
aue_reset_pegasus_II(pegasus_dev *sc)
{
/* Magic constants taken from Linux driver. */
aue_csr_write_1(sc, AUE_REG_1D, 0);
aue_csr_write_1(sc, AUE_REG_7B, 2);
#if 0
if ((sc->aue_flags & HAS_HOME_PNA) && mii_mode)
aue_csr_write_1(sc, AUE_REG_81, 6);
else
#endif
aue_csr_write_1(sc, AUE_REG_81, 2);
}
static void
aue_reset(pegasus_dev *sc)
{
int i;
AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
for (i = 0; i < AUE_TIMEOUT; i++) {
if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
break;
}
if (i == AUE_TIMEOUT)
dprintf("aue%d: reset failed\n", sc->aue_unit);
/*
* The PHY(s) attached to the Pegasus chip may be held
* in reset until we flip on the GPIO outputs. Make sure
* to set the GPIO pins high so that the PHY(s) will
* be enabled.
*
* Note: We force all of the GPIO pins low first, *then*
* enable the ones we want.
*/
aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0);
aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0|AUE_GPIO_SEL1);
if (sc->aue_flags & LSYS) {
/* Grrr. LinkSys has to be different from everyone else. */
aue_csr_write_1(sc, AUE_GPIO0,
AUE_GPIO_SEL0 | AUE_GPIO_SEL1);
aue_csr_write_1(sc, AUE_GPIO0,
AUE_GPIO_SEL0 | AUE_GPIO_SEL1 | AUE_GPIO_OUT0);
}
if (sc->aue_flags & PII)
aue_reset_pegasus_II(sc);
/* Wait a little while for the chip to get its brains in order. */
DELAY(10000);
return;
}
/*
* Attach
*/
void
aue_attach(pegasus_dev *sc)
{
u_char eaddr[ETHER_ADDRESS_LENGTH];
AUE_LOCK(sc);
/* Reset the adapter. */
aue_reset(sc);
/*
* Get station address from the EEPROM.
*/
aue_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 0);
memcpy(sc->macaddr, eaddr, ETHER_ADDRESS_LENGTH);
if (aue_init_phy(sc) != B_OK)
goto done;
sc->aue_dying = 0;
done:
AUE_UNLOCK(sc);
}
void
aue_init(pegasus_dev *sc)
{
/* Enable RX and TX */
aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB);
AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR);
}
void
aue_uninit(pegasus_dev *sc)
{
aue_csr_write_1(sc, AUE_CTL0, 0);
aue_csr_write_1(sc, AUE_CTL1, 0);
aue_reset(sc);
}
@@ -1,276 +0,0 @@
/*
* Pegasus BeOS Driver
*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
/*-
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD: /repoman/r/ncvs/src/sys/dev/usb/if_auereg.h,v 1.22 2005/06/10 16:49:15 brooks Exp $
*/
/*
* Register definitions for ADMtek Pegasus AN986 USB to Ethernet
* chip. The Pegasus uses a total of four USB endpoints: the control
* endpoint (0), a bulk read endpoint for receiving packets (1),
* a bulk write endpoint for sending packets (2) and an interrupt
* endpoint for passing RX and TX status (3). Endpoint 0 is used
* to read and write the ethernet module's registers. All registers
* are 8 bits wide.
*
* Packet transfer is done in 64 byte chunks. The last chunk in a
* transfer is denoted by having a length less that 64 bytes. For
* the RX case, the data includes an optional RX status word.
*/
#define AUE_UR_READREG 0xF0
#define AUE_UR_WRITEREG 0xF1
#define AUE_CONFIG_NO 1
#define AUE_IFACE_IDX 0
/*
* Note that while the ADMtek technically has four
* endpoints, the control endpoint (endpoint 0) is
* regarded as special by the USB code and drivers
* don't have direct access to it. (We access it
* using usbd_do_request() when reading/writing
* registers.) Consequently, our endpoint indexes
* don't match those in the ADMtek Pegasus manual:
* we consider the RX data endpoint to be index 0
* and work up from there.
*/
#define AUE_ENDPT_RX 0x0
#define AUE_ENDPT_TX 0x1
#define AUE_ENDPT_INTR 0x2
#define AUE_ENDPT_MAX 0x3
#define AUE_INTR_PKTLEN 0x8
#define AUE_CTL0 0x00
#define AUE_CTL1 0x01
#define AUE_CTL2 0x02
#define AUE_MAR0 0x08
#define AUE_MAR1 0x09
#define AUE_MAR2 0x0A
#define AUE_MAR3 0x0B
#define AUE_MAR4 0x0C
#define AUE_MAR5 0x0D
#define AUE_MAR6 0x0E
#define AUE_MAR7 0x0F
#define AUE_MAR AUE_MAR0
#define AUE_PAR0 0x10
#define AUE_PAR1 0x11
#define AUE_PAR2 0x12
#define AUE_PAR3 0x13
#define AUE_PAR4 0x14
#define AUE_PAR5 0x15
#define AUE_PAR AUE_PAR0
#define AUE_PAUSE0 0x18
#define AUE_PAUSE1 0x19
#define AUE_PAUSE AUE_PAUSE0
#define AUE_RX_FLOWCTL_CNT 0x1A
#define AUE_RX_FLOWCTL_FIFO 0x1B
#define AUE_REG_1D 0x1D
#define AUE_EE_REG 0x20
#define AUE_EE_DATA0 0x21
#define AUE_EE_DATA1 0x22
#define AUE_EE_DATA AUE_EE_DATA0
#define AUE_EE_CTL 0x23
#define AUE_PHY_ADDR 0x25
#define AUE_PHY_DATA0 0x26
#define AUE_PHY_DATA1 0x27
#define AUE_PHY_DATA AUE_PHY_DATA0
#define AUE_PHY_CTL 0x28
#define AUE_USB_STS 0x2A
#define AUE_TXSTAT0 0x2B
#define AUE_TXSTAT1 0x2C
#define AUE_TXSTAT AUE_TXSTAT0
#define AUE_RXSTAT 0x2D
#define AUE_PKTLOST0 0x2E
#define AUE_PKTLOST1 0x2F
#define AUE_PKTLOST AUE_PKTLOST0
#define AUE_REG_7B 0x7B
#define AUE_GPIO0 0x7E
#define AUE_GPIO1 0x7F
#define AUE_REG_81 0x81
#define AUE_CTL0_INCLUDE_RXCRC 0x01
#define AUE_CTL0_ALLMULTI 0x02
#define AUE_CTL0_STOP_BACKOFF 0x04
#define AUE_CTL0_RXSTAT_APPEND 0x08
#define AUE_CTL0_WAKEON_ENB 0x10
#define AUE_CTL0_RXPAUSE_ENB 0x20
#define AUE_CTL0_RX_ENB 0x40
#define AUE_CTL0_TX_ENB 0x80
#define AUE_CTL1_HOMELAN 0x04
#define AUE_CTL1_RESETMAC 0x08
#define AUE_CTL1_SPEEDSEL 0x10 /* 0 = 10mbps, 1 = 100mbps */
#define AUE_CTL1_DUPLEX 0x20 /* 0 = half, 1 = full */
#define AUE_CTL1_DELAYHOME 0x40
#define AUE_CTL2_EP3_CLR 0x01 /* reading EP3 clrs status regs */
#define AUE_CTL2_RX_BADFRAMES 0x02
#define AUE_CTL2_RX_PROMISC 0x04
#define AUE_CTL2_LOOPBACK 0x08
#define AUE_CTL2_EEPROMWR_ENB 0x10
#define AUE_CTL2_EEPROM_LOAD 0x20
#define AUE_EECTL_WRITE 0x01
#define AUE_EECTL_READ 0x02
#define AUE_EECTL_DONE 0x04
#define AUE_PHYCTL_PHYREG 0x1F
#define AUE_PHYCTL_WRITE 0x20
#define AUE_PHYCTL_READ 0x40
#define AUE_PHYCTL_DONE 0x80
#define AUE_USBSTS_SUSPEND 0x01
#define AUE_USBSTS_RESUME 0x02
#define AUE_TXSTAT0_JABTIMO 0x04
#define AUE_TXSTAT0_CARLOSS 0x08
#define AUE_TXSTAT0_NOCARRIER 0x10
#define AUE_TXSTAT0_LATECOLL 0x20
#define AUE_TXSTAT0_EXCESSCOLL 0x40
#define AUE_TXSTAT0_UNDERRUN 0x80
#define AUE_TXSTAT1_PKTCNT 0x0F
#define AUE_TXSTAT1_FIFO_EMPTY 0x40
#define AUE_TXSTAT1_FIFO_FULL 0x80
#define AUE_RXSTAT_OVERRUN 0x01
#define AUE_RXSTAT_PAUSE 0x02
#define AUE_GPIO_IN0 0x01
#define AUE_GPIO_OUT0 0x02
#define AUE_GPIO_SEL0 0x04
#define AUE_GPIO_IN1 0x08
#define AUE_GPIO_OUT1 0x10
#define AUE_GPIO_SEL1 0x20
struct aue_intrpkt {
u_int8_t aue_txstat0;
u_int8_t aue_txstat1;
u_int8_t aue_rxstat;
u_int8_t aue_rxlostpkt0;
u_int8_t aue_rxlostpkt1;
u_int8_t aue_wakeupstat;
u_int8_t aue_rsvd;
};
struct aue_rxpkt {
u_int16_t aue_pktlen;
u_int8_t aue_rxstat;
};
#define AUE_RXSTAT_MCAST 0x01
#define AUE_RXSTAT_GIANT 0x02
#define AUE_RXSTAT_RUNT 0x04
#define AUE_RXSTAT_CRCERR 0x08
#define AUE_RXSTAT_DRIBBLE 0x10
#define AUE_RXSTAT_MASK 0x1E
#define AUE_INC(x, y) (x) = (x + 1) % y
#if 0
#define AUE_LOCK(_sc) mtx_lock(&(_sc)->aue_mtx)
#define AUE_UNLOCK(_sc) mtx_unlock(&(_sc)->aue_mtx)
#else
#define AUE_LOCK(_sc)
#define AUE_UNLOCK(_sc)
#endif
#define AUE_TIMEOUT 1000
#define AUE_MIN_FRAMELEN 60
#define AUE_TX_TIMEOUT 10000 /* ms */
#define AUE_INTR_INTERVAL 100 /* ms */
#define AUE_BUFSZ 1536
#define ETHER_ALIGN 2
/***************************** Media Independent Interface *****************************/
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,
};
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 SiS900_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_link_status {
MII_LINK_FAIL = 0x4000,
MII_LINK_100_MBIT = 0x0080,
MII_LINK_FULL_DUPLEX = 0x0040
};