root/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c
/*
 * Copyright 2011, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Author(s):
 *              Axel Dörfler <axeld@pinc-software.de>
 *              Siarzhuk Zharski <imker@gmx.li>
 */


#include <sys/bus.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <shared.h>

#include <net/if.h>
#include <net/if_var.h>

#include "if_dcreg.h"


HAIKU_FBSD_DRIVERS_GLUE(dec21xxx);
HAIKU_DRIVER_REQUIREMENTS(0);


int check_disable_interrupts_dc(device_t dev);
void reenable_interrupts_dc(device_t dev);

extern int check_disable_interrupts_de(device_t dev);
extern void reenable_interrupts_de(device_t dev);


extern driver_t *DRIVER_MODULE_NAME(dc, pci);
extern driver_t *DRIVER_MODULE_NAME(de, pci);

void
__haiku_init_hardware()
{
        driver_t *drivers[] = {
                DRIVER_MODULE_NAME(dc, pci),
                DRIVER_MODULE_NAME(de, pci),
                NULL
        };
        _fbsd_init_hardware_pci(drivers);
}


extern driver_t *DRIVER_MODULE_NAME(acphy, miibus);
extern driver_t *DRIVER_MODULE_NAME(amphy, miibus);
extern driver_t *DRIVER_MODULE_NAME(dcphy, miibus);
extern driver_t *DRIVER_MODULE_NAME(pnphy, miibus);
extern driver_t *DRIVER_MODULE_NAME(ukphy, miibus);

driver_t *
__haiku_select_miibus_driver(device_t dev)
{
        driver_t *drivers[] = {
                DRIVER_MODULE_NAME(acphy, miibus),
                DRIVER_MODULE_NAME(amphy, miibus),
                DRIVER_MODULE_NAME(dcphy, miibus),
                DRIVER_MODULE_NAME(pnphy, miibus),
                DRIVER_MODULE_NAME(ukphy, miibus),
                NULL
        };

        return __haiku_probe_drivers(dev, drivers);
}


int
HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev)
{
        uint16 name = *(uint16*)dev->device_name;
        switch (name) {
                case 'cd':
                        return check_disable_interrupts_dc(dev);
                case 'ed':
                        return check_disable_interrupts_de(dev);
                default:
                        break;
        }

        panic("Unsupported device: %#x (%s)!", name, dev->device_name);
        return 0;
}


void
HAIKU_REENABLE_INTERRUPTS(device_t dev)
{
        uint16 name = *(uint16*)dev->device_name;
        switch (name) {
                case 'cd':
                        reenable_interrupts_dc(dev);
                        break;
                case 'ed':
                        reenable_interrupts_de(dev);
                        break;
                default:
                        panic("Unsupported device: %#x (%s)!", name, dev->device_name);
                        break;
        }
}


int
check_disable_interrupts_dc(device_t dev)
{
        struct dc_softc *sc = device_get_softc(dev);
        uint16_t status;
        HAIKU_INTR_REGISTER_STATE;

        HAIKU_INTR_REGISTER_ENTER();

        status = CSR_READ_4(sc, DC_ISR);
        if (status == 0xffff) {
                HAIKU_INTR_REGISTER_LEAVE();
                return 0;
        }

        if (status != 0 && (status & DC_INTRS) == 0) {
                CSR_WRITE_4(sc, DC_ISR, status);
                HAIKU_INTR_REGISTER_LEAVE();
                return 0;
        }

        if ((status & DC_INTRS) == 0) {
                HAIKU_INTR_REGISTER_LEAVE();
                return 0;
        }

        CSR_WRITE_4(sc, DC_IMR, 0);

        HAIKU_INTR_REGISTER_LEAVE();

        return 1;
}


void
reenable_interrupts_dc(device_t dev)
{
        struct dc_softc *sc = device_get_softc(dev);
        DC_LOCK(sc);
        CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
        DC_UNLOCK(sc);
}