diff --git a/sys/conf/files b/sys/conf/files index 87dd8ba2daf3..ee221ca6edca 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -260,8 +260,6 @@ dev/buslogic/bt_mca.c optional bt mca dev/buslogic/bt_pci.c optional bt pci dev/cardbus/cardbus.c optional cardbus dev/cardbus/cardbus_cis.c optional cardbus -dev/pccbb/pccbb_if.m optional cardbus -dev/pccbb/pccbb_if.m optional pccbb dev/ccd/ccd.c count ccd dev/cs/if_cs.c optional cs #dev/dpt/dpt_control.c optional dpt diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index acee08ea3fb4..32edfdde2d99 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -57,11 +57,10 @@ #include #include -#include "pccbb_if.h" +#include "power_if.h" #include "card_if.h" #include "pcib_if.h" - #if defined CARDBUS_DEBUG #define STATIC #define DPRINTF(a) printf a @@ -74,10 +73,9 @@ #if !defined(lint) static const char rcsid[] = - "$FreeBSD $"; + "$FreeBSD$"; #endif - struct cardbus_quirk { u_int32_t devid; /* Vendor/device of the card */ int type; @@ -155,6 +153,13 @@ cardbus_attach(device_t dev) return 0; } +static int +cardbus_detach(device_t dev) +{ + cardbus_detach_card(dev, DETACH_FORCE); + return 0; +} + /************************************************************************/ /* Attach/Detach card */ /************************************************************************/ @@ -188,24 +193,11 @@ static int cardbus_attach_card(device_t dev) { device_t bdev = device_get_parent(dev); - int cdstatus; int cardattached = 0; static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ int bus, slot, func; - /* inspect initial voltage */ - if (0 == (cdstatus = PCCBB_DETECT_CARD(bdev))) { - DEVPRINTF((dev, "cardbusattach: no CardBus card detected\n")); - return ENXIO; - } - - if (cdstatus & CARD_3V_CARD) { - PCCBB_POWER_SOCKET(bdev, CARD_VCC_3V); - } else { - device_printf(dev, "unsupported power: %d\n", cdstatus); - return EINVAL; - } - PCCBB_RESET(bdev); + POWER_ENABLE_SOCKET(bdev, dev); bus = pci_get_secondarybus(bdev); if (bus == 0) { @@ -253,6 +245,7 @@ cardbus_attach_card(device_t dev) } if (cardattached > 0) return 0; + POWER_DISABLE_SOCKET(bdev, dev); return ENOENT; } @@ -268,20 +261,43 @@ cardbus_detach_card(device_t dev, int flags) if (numdevs == 0) { DEVPRINTF((dev, "Detaching card: no cards to detach!\n")); + POWER_DISABLE_SOCKET(device_get_parent(dev), dev); return ENOENT; } for (tmp = 0; tmp < numdevs; tmp++) { struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]); - if (device_detach(dinfo->cfg.dev) != 0) err++; - cardbus_release_all_resources(dinfo->cfg.dev, - &dinfo->resources); - device_delete_child(dev, devlist[tmp]); + if (device_detach(dinfo->cfg.dev) == 0 || flags & DETACH_FORCE){ + cardbus_release_all_resources(dinfo->cfg.dev, + &dinfo->resources); + device_delete_child(dev, devlist[tmp]); + } else + err++; cardbus_freecfg(dinfo); } + if (err == 0) + POWER_DISABLE_SOCKET(device_get_parent(dev), dev); return err; } +static void +cardbus_driver_added(device_t dev, driver_t *driver) +{ + /* + * For this to work, we should: + * 1) power up the slot if it isn't powered. + * (Is this necessary? Can we assume _probe() doesn't need power?) + * 2) probe (we should probe even though we already have child?) + * 3) power up if we haven't done so and probe succeeds + * 4) attach if probe succeeds. + * 5) power down if probe or attach failed, and the slot was powered + * down to begin with. + */ + printf("I see you added a driver that could be a child of cardbus...\n"); + printf("If this is for a cardbus card, please remove and reinsert the card.\n"); + printf("(there is no current support for adding a driver like this)\n"); +} + /************************************************************************/ /* PCI-Like config reading (copied from pci.c */ /************************************************************************/ @@ -649,6 +665,7 @@ cardbus_add_resources(device_t dev, pcicfgregs* cfg) struct cardbus_quirk *q; struct resource_list_entry *rle; struct resource *res; + int rid; int i; for (i = 0; i < cfg->nummaps; i++) { @@ -662,15 +679,16 @@ cardbus_add_resources(device_t dev, pcicfgregs* cfg) cardbus_add_map(cbdev, dev, cfg, q->arg1); } + rid = 0; res = bus_generic_alloc_resource(cbdev, dev, SYS_RES_IRQ, - 0, 0, ~0, 1, RF_SHAREABLE); + &rid, 0, ~0, 1, RF_SHAREABLE); if (res == NULL) panic("Cannot allocate IRQ for card\n"); - resource_list_add(rl, SYS_RES_IRQ, 0, + resource_list_add(rl, SYS_RES_IRQ, rid, rman_get_start(res), rman_get_start(res), 1); - rle = resource_list_find(rl, SYS_RES_IRQ, 0); + rle = resource_list_find(rl, SYS_RES_IRQ, rid); rle->res = res; } @@ -688,8 +706,8 @@ cardbus_release_all_resources(device_t dev, struct resource_list *rl) } } -static struct -resource* cardbus_alloc_resource(device_t self, device_t child, int type, +static struct resource* +cardbus_alloc_resource(device_t self, device_t child, int type, int* rid, u_long start, u_long end, u_long count, u_int flags) { @@ -941,7 +959,7 @@ static device_method_t cardbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cardbus_probe), DEVMETHOD(device_attach, cardbus_attach), - DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_detach, cardbus_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -951,13 +969,14 @@ static device_method_t cardbus_methods[] = { DEVMETHOD(bus_probe_nomatch, cardbus_probe_nomatch), DEVMETHOD(bus_read_ivar, cardbus_read_ivar), DEVMETHOD(bus_write_ivar, cardbus_write_ivar), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_driver_added, cardbus_driver_added), DEVMETHOD(bus_alloc_resource, cardbus_alloc_resource), DEVMETHOD(bus_release_resource, cardbus_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), DEVMETHOD(bus_set_resource, cardbus_set_resource_method), DEVMETHOD(bus_get_resource, cardbus_get_resource_method), @@ -980,6 +999,7 @@ static driver_t cardbus_driver = { 0 /* no softc */ }; -static devclass_t cardbus_devclass = {}; +static devclass_t cardbus_devclass; DRIVER_MODULE(cardbus, pccbb, cardbus_driver, cardbus_devclass, 0, 0); +MODULE_DEPEND(cardbus, pccbb, 1, 1, 1); diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c index bf96a2300039..b54cc0260095 100644 --- a/sys/dev/pccbb/pccbb.c +++ b/sys/dev/pccbb/pccbb.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -72,7 +73,6 @@ #include "power_if.h" #include "card_if.h" -#include "pccbb_if.h" #include "pcib_if.h" #if defined CBB_DEBUG @@ -98,7 +98,10 @@ #define PCIC_MASK2(SC,REG,MASK,MASK2) \ PCIC_WRITE(SC,REG,(PCIC_READ(SC,REG) MASK) MASK2) -#define DETACH_FORCE 0x1 +#if !defined(lint) +static const char rcsid[] = + "$FreeBSD$"; +#endif struct pccbb_sclist { struct pccbb_softc *sc; @@ -182,16 +185,20 @@ static int cb_chipset(u_int32_t pci_id, const char** namep, int* flagp); static int pccbb_probe(device_t dev); static void pccbb_chipinit(struct pccbb_softc* sc); static int pccbb_attach(device_t dev); +static int pccbb_detach(device_t dev); +static void pccbb_driver_added(device_t dev, driver_t *driver); +static void pccbb_child_detached(device_t dev, device_t child); static void pccbb_event_thread (void *arg); static void pccbb_create_event_thread (struct pccbb_softc *sc); static void pccbb_start_threads(void *arg); static void pccbb_insert (struct pccbb_softc *sc); static void pccbb_removal (struct pccbb_softc *sc); static void pccbb_intr(void* arg); -static int pccbb_detect_voltage(struct pccbb_softc *sc); +static int pccbb_detect_voltage(device_t dev); static int pccbb_power(device_t dev, int volts); -static int pccbb_cardbus_detect_card(device_t dev); -static int pccbb_cardbus_reset(device_t dev); +static void pccbb_cardbus_reset(device_t dev); +static int pccbb_cardbus_power_enable_socket(device_t self, device_t child); +static void pccbb_cardbus_power_disable_socket(device_t self, device_t child); static int pccbb_cardbus_io_open(device_t dev, int win, u_int32_t start, u_int32_t end); static int pccbb_cardbus_mem_open(device_t dev, int win, @@ -210,6 +217,8 @@ static struct resource* pccbb_cardbus_alloc_resource(device_t self, static int pccbb_cardbus_release_resource(device_t self, device_t child, int type,int rid, struct resource *r); +static int pccbb_pcic_power_enable_socket(device_t self, device_t child); +static void pccbb_pcic_power_disable_socket(device_t self, device_t child); static void pccbb_pcic_wait_ready(struct pccbb_softc *sc); static void pccbb_pcic_do_mem_map(struct pccbb_softc *sc, int win); static int pccbb_pcic_mem_map(struct pccbb_softc *sc, int kind, @@ -234,8 +243,8 @@ static int pccbb_pcic_set_res_flags(device_t self, device_t child, int type, int rid, u_int32_t flags); static int pccbb_pcic_set_memory_offset(device_t self, device_t child, int rid, u_int32_t offset); -static int pccbb_pcic_enable_socket(device_t self, device_t child); -static void pccbb_pcic_disable_socket(device_t self, device_t child); +static int pccbb_power_enable_socket(device_t self, device_t child); +static void pccbb_power_disable_socket(device_t self, device_t child); static int pccbb_activate_resource(device_t self, device_t child, int type, int rid, struct resource *r); static int pccbb_deactivate_resource(device_t self, device_t child, int type, @@ -246,6 +255,11 @@ static struct resource* pccbb_alloc_resource(device_t self, device_t child, u_int flags); static int pccbb_release_resource(device_t self, device_t child, int type, int rid, struct resource *r); +static int pccbb_maxslots(device_t dev); +static u_int32_t pccbb_read_config(device_t dev, int b, int s, int f, + int reg, int width); +static void pccbb_write_config(device_t dev, int b, int s, int f, int reg, + u_int32_t val, int width); /************************************************************************/ @@ -372,6 +386,7 @@ pccbb_attach(device_t dev) softcs_init = 1; STAILQ_INIT(&softcs); } + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_DEF); sc->sc_chipset = cb_chipset(pci_get_devid(dev), NULL, &flags); sc->sc_dev = dev; sc->sc_flags = 0; @@ -408,6 +423,7 @@ pccbb_attach(device_t dev) if (!sc->sc_base_res){ device_printf(dev, "Could not grab register memory\n"); + mtx_destroy(&sc->sc_mtx); return ENOMEM; } pci_write_config(dev, PCCBBR_SOCKBASE, @@ -416,6 +432,7 @@ pccbb_attach(device_t dev) rman_get_start(sc->sc_base_res))); } else { device_printf(dev, "Could not map register memory\n"); + mtx_destroy(&sc->sc_mtx); return ENOMEM; } } @@ -437,6 +454,9 @@ pccbb_attach(device_t dev) RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { printf("pccbb: Unable to map IRQ...\n"); + bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + sc->sc_base_res); + mtx_destroy(&sc->sc_mtx); return ENOMEM; } @@ -446,34 +466,38 @@ pccbb_attach(device_t dev) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); + mtx_destroy(&sc->sc_mtx); return ENOMEM; } /* attach children */ sc->sc_cbdev = device_add_child(dev, "cardbus", -1); if (sc->sc_cbdev == NULL) - DEVPRINTF((dev, "Cannot add cardbus bus!\n")); + DEVPRINTF((dev, "WARNING: cannot add cardbus bus.\n")); else if (device_probe_and_attach(sc->sc_cbdev) != 0) { - DEVPRINTF((dev, "Cannot attach cardbus bus!\n")); + DEVPRINTF((dev, "WARNING: cannot attach cardbus bus!\n")); sc->sc_cbdev = NULL; } sc->sc_pccarddev = device_add_child(dev, "pccard", -1); if (sc->sc_pccarddev == NULL) - DEVPRINTF((dev, "Cannot add pccard bus!\n")); + DEVPRINTF((dev, "WARNING: cannot add pccard bus.\n")); else if (device_probe_and_attach(sc->sc_pccarddev) != 0) { - DEVPRINTF((dev, "Cannot attach pccard bus!\n")); + DEVPRINTF((dev, "WARNING: cannot attach pccard bus.\n")); sc->sc_pccarddev = NULL; } +#ifndef KLD_MODULE if (sc->sc_cbdev == NULL && sc->sc_pccarddev == NULL) { - device_printf(dev, "Failed to attach cardbus/pccard bus!\n"); + device_printf(dev, "ERROR: Failed to attach cardbus/pccard bus!\n"); bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); + mtx_destroy(&sc->sc_mtx); return ENOMEM; } +#endif { struct pccbb_sclist *sclist; @@ -485,6 +509,90 @@ pccbb_attach(device_t dev) return 0; } +static int +pccbb_detach(device_t dev) +{ + struct pccbb_softc *sc = device_get_softc(dev); + int numdevs; + device_t *devlist; + int tmp; + int error; + + device_get_children(dev, &devlist, &numdevs); + + error = 0; + for (tmp = 0; tmp < numdevs; tmp++) { + if (device_detach(devlist[tmp]) == 0) + device_delete_child(dev, devlist[tmp]); + else + error++; + } + if (error > 0) + return ENXIO; + + mtx_enter(&sc->sc_mtx, MTX_DEF); + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); + + sc->sc_flags |= PCCBB_KTHREAD_DONE; + if (sc->sc_flags & PCCBB_KTHREAD_RUNNING) { + wakeup(sc); + mtx_exit(&sc->sc_mtx, MTX_DEF); + DEVPRINTF((dev, "waiting for kthread exit...")); + error = tsleep(sc, PWAIT, "pccbb-detach-wait", 60 * hz); + if (error) + DPRINTF(("timeout\n")); + else + DPRINTF(("done\n")); + } else + mtx_exit(&sc->sc_mtx, MTX_DEF); + + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + sc->sc_base_res); + mtx_destroy(&sc->sc_mtx); + return 0; +} + +static void +pccbb_driver_added(device_t dev, driver_t *driver) +{ + struct pccbb_softc *sc = device_get_softc(dev); + device_t *devlist; + int tmp; + int numdevs; + + DEVICE_IDENTIFY(driver, dev); + device_get_children(dev, &devlist, &numdevs); + for (tmp = 0; tmp < numdevs; tmp++) { + if (device_get_state(devlist[tmp]) == DS_NOTPRESENT && + device_probe_and_attach(devlist[tmp]) == 0) { + if (devlist[tmp] == NULL) + /* NOTHING */; + else if (strcmp(driver->name, "cardbus") == 0) + sc->sc_cbdev = devlist[tmp]; + else if (strcmp(driver->name, "pccard") == 0) + sc->sc_pccarddev = devlist[tmp]; + else + device_printf(dev, + "Unsupported child bus: %s\n", + driver->name); + } + } +} + +static void +pccbb_child_detached(device_t dev, device_t child) +{ + struct pccbb_softc *sc = device_get_softc(dev); + if (child == sc->sc_cbdev) + sc->sc_cbdev = NULL; + else if (child == sc->sc_pccarddev) + sc->sc_pccarddev = NULL; + else + device_printf(dev, "Unknown child detached: %s %p/%p\n", + device_get_nameunit(child), sc->sc_cbdev, sc->sc_pccarddev); +} + /************************************************************************/ /* Kthreads */ /************************************************************************/ @@ -493,25 +601,24 @@ static void pccbb_event_thread (void *arg) { struct pccbb_softc *sc = arg; - int s; u_int32_t status; - s = splhigh(); for(;;) { - if (sc->sc_flags & PCCBB_INITIALCARD) - sc->sc_flags &= ~PCCBB_INITIALCARD; + if (!(sc->sc_flags & PCCBB_KTHREAD_RUNNING)) + sc->sc_flags |= PCCBB_KTHREAD_RUNNING; else { - splx (s); tsleep (sc, PWAIT, "pccbbev", 0); /* - * Delay some time, make sure the user is done with - * whatever he is doing. + * Delay 1 second, make sure the user is done with + * whatever he is doing. We tsleep on sc->sc_flags, + * which should never be woken up. */ - DELAY(1000*1000); - s = splhigh(); + tsleep (&sc->sc_flags, PWAIT, "pccbbev", 1*hz); } + mtx_enter(&sc->sc_mtx, MTX_DEF); + if (sc->sc_flags & PCCBB_KTHREAD_DONE) + break; - sc->sc_flags |= PCCBB_CARDSTATUS_BUSY; status = sc->sc_socketreg->socket_state; if ((status & PCCBB_SOCKET_STAT_CD) == 0) { if (!(sc->sc_flags & PCCBB_CARDATTACHED)) @@ -526,10 +633,12 @@ pccbb_event_thread (void *arg) else pccbb_removal(sc); } - sc->sc_flags &= ~PCCBB_CARDSTATUS_BUSY; - splx (s); + mtx_exit(&sc->sc_mtx, MTX_DEF); } - /* NOTREACHED */ + mtx_exit(&sc->sc_mtx, MTX_DEF); + sc->sc_flags &= ~PCCBB_KTHREAD_RUNNING; + wakeup(sc); + mtx_enter(&Giant, MTX_DEF); kthread_exit(0); } @@ -550,10 +659,6 @@ pccbb_start_threads(void *arg) struct pccbb_sclist *sclist; STAILQ_FOREACH(sclist, &softcs, entries) { - if (0 == (sclist->sc->sc_socketreg->socket_state & - PCCBB_SOCKET_STAT_CD)) { - sclist->sc->sc_flags |= PCCBB_INITIALCARD; - } pccbb_create_event_thread(sclist->sc); } } @@ -630,7 +735,6 @@ pccbb_intr(void* arg) { struct pccbb_softc *sc = arg; u_int32_t sockevent; - int tmp; if (!(sockevent = sc->sc_socketreg->socket_event)) { /* not for me. */ @@ -641,19 +745,9 @@ pccbb_intr(void* arg) sc->sc_socketreg->socket_event = sockevent | 0x01; if (sockevent & PCCBB_SOCKET_EVENT_CD) { - for (tmp = 0; tmp <= 100 && - (sc->sc_flags & PCCBB_CARDSTATUS_BUSY); tmp++) { - if (tmp == 0) - DEVPRINTF((sc->sc_dev, "(pccbbintr): busy!")); - else - DPRINTF((".")); - DELAY(1); - } - if (sc->sc_flags & PCCBB_CARDSTATUS_BUSY) { - DPRINTF(("failed! Going ahead anyway...")); - sc->sc_flags &= ~PCCBB_CARDSTATUS_BUSY; - } + mtx_enter(&sc->sc_mtx, MTX_DEF); wakeup(sc); + mtx_exit(&sc->sc_mtx, MTX_DEF); } else { if (sockevent & PCCBB_SOCKET_EVENT_CSTS) { DPRINTF((" cstsevent occures, 0x%08x\n", @@ -669,12 +763,13 @@ pccbb_intr(void* arg) } /************************************************************************/ -/* Power functions */ +/* Generic Power functions */ /************************************************************************/ static int -pccbb_detect_voltage(struct pccbb_softc *sc) +pccbb_detect_voltage(device_t dev) { + struct pccbb_softc *sc = device_get_softc(dev); u_int32_t psr; int vol = CARD_UKN_CARD; @@ -813,43 +908,56 @@ pccbb_power(device_t dev, int volts) } /************************************************************************/ -/* PCCBB methods */ +/* Cardbus power functions */ /************************************************************************/ -static int -pccbb_cardbus_detect_card(device_t dev) -{ - struct pccbb_softc *sc = device_get_softc(dev); - u_int32_t sockstat = sc->sc_socketreg->socket_state; - - if (sockstat & PCCBB_SOCKET_STAT_CB) - return pccbb_detect_voltage(sc); - return 0; -} - -static int +static void pccbb_cardbus_reset(device_t dev) { struct pccbb_softc *sc = device_get_softc(dev); - u_int32_t bcr = pci_read_config(dev, PCCBBR_BRIDGECTRL, 2); int delay_us; delay_us = sc->sc_chipset == CB_RF5C47X ? 400*1000 : 20*1000; - bcr |= PCCBBM_BRIDGECTRL_RESET; - pci_write_config(dev, PCCBBR_BRIDGECTRL, bcr, 2); + PCI_MASK_CONFIG(dev, PCCBBR_BRIDGECTRL, |PCCBBM_BRIDGECTRL_RESET, 2); DELAY(delay_us); /* If a card exists, unreset it! */ if (sc->sc_flags & PCCBB_CARDATTACHED) { - bcr &= ~PCCBBM_BRIDGECTRL_RESET; - pci_write_config(dev, PCCBBR_BRIDGECTRL, bcr, 2); + PCI_MASK_CONFIG(dev, PCCBBR_BRIDGECTRL, + &~PCCBBM_BRIDGECTRL_RESET, 2); DELAY(delay_us); } - return 1; } +static int +pccbb_cardbus_power_enable_socket(device_t self, device_t child) +{ + int voltage; + + voltage = pccbb_detect_voltage(self); + + pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + if (voltage & CARD_5V_CARD) + pccbb_power(self, CARD_VCC_5V | CARD_VPP_VCC); + else if (voltage & CARD_3V_CARD) + pccbb_power(self, CARD_VCC_3V | CARD_VPP_VCC); + else { + device_printf(self, "Unknown card voltage\n"); + return ENXIO; + } + + pccbb_cardbus_reset(self); + return 0; +} + +static void +pccbb_cardbus_power_disable_socket(device_t self, device_t child) +{ + pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + pccbb_cardbus_reset(self); +} /************************************************************************/ /* Cardbus Resource */ @@ -953,11 +1061,8 @@ pccbb_cardbus_auto_open(struct pccbb_softc *sc, int type) ends[rle->win] = rle->end; else if (rle->end < starts[rle->win]) starts[rle->win] = rle->start; - else - panic("pccbb_auto_open: Weird condition!\n"); } } - if (type == SYS_RES_MEMORY) align = PCCBB_MEMALIGN; else if (type == SYS_RES_IOPORT) @@ -970,9 +1075,9 @@ pccbb_cardbus_auto_open(struct pccbb_softc *sc, int type) if (starts[1] != 0xffffffff) starts[1] -= starts[1] % align; if (ends[0] % align != 0) - ends[0] += align - ends[0]%align; + ends[0] += align - ends[0]%align - 1; if (ends[1] % align != 0) - ends[1] += align - ends[1]%align; + ends[1] += align - ends[1]%align - 1; if (type == SYS_RES_MEMORY) { pccbb_cardbus_mem_open(sc->sc_dev, 0, starts[0], ends[0]); @@ -1008,7 +1113,6 @@ pccbb_cardbus_activate_resource(device_t self, device_t child, int type, pccbb_cardbus_auto_open(sc, type); } - return bus_generic_activate_resource(self, child, type, rid, r); } @@ -1066,7 +1170,96 @@ pccbb_cardbus_release_resource(device_t self, device_t child, int type, } /************************************************************************/ -/* PC Card Resources */ +/* PC Card Power Functions */ +/************************************************************************/ + +static int +pccbb_pcic_power_enable_socket(device_t self, device_t child) +{ + struct pccbb_softc *sc = device_get_softc(self); + + DPRINTF(("pccbb_pcic_socket_enable:\n")); + + /* power down/up the socket to reset */ + { + int voltage = pccbb_detect_voltage(self); + + pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + if (voltage & CARD_5V_CARD) + pccbb_power(self, CARD_VCC_5V | CARD_VPP_VCC); + else if (voltage & CARD_3V_CARD) + pccbb_power(self, CARD_VCC_3V | CARD_VPP_VCC); + else { + device_printf(self, "Unknown card voltage\n"); + return ENXIO; + } + } + + /* enable socket i/o */ + PCIC_MASK(sc, PCIC_PWRCTL, | PCIC_PWRCTL_OE); + + PCIC_WRITE(sc, PCIC_INTR, PCIC_INTR_ENABLE); + /* hold reset for 30ms */ + DELAY(30*1000); + /* clear the reset flag */ + PCIC_MASK(sc, PCIC_INTR, | PCIC_INTR_RESET); + /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ + DELAY(20*1000); + + pccbb_pcic_wait_ready(sc); + + /* disable all address windows */ + PCIC_WRITE(sc, PCIC_ADDRWIN_ENABLE, 0); + + { + int cardtype; + CARD_GET_TYPE(child, &cardtype); + PCIC_MASK(sc, PCIC_INTR, | ((cardtype == PCCARD_IFTYPE_IO) ? + PCIC_INTR_CARDTYPE_IO : + PCIC_INTR_CARDTYPE_MEM)); + DEVPRINTF((sc->sc_dev, "card type is %s\n", + (cardtype == PCCARD_IFTYPE_IO) ? "io" : "mem")); + } + + /* reinstall all the memory and io mappings */ + { + int win; + + for (win = 0; win < PCIC_MEM_WINS; ++win) { + if (sc->memalloc & (1 << win)) { + pccbb_pcic_do_mem_map(sc, win); + } + } + for (win = 0; win < PCIC_IO_WINS; ++win) { + if (sc->ioalloc & (1 << win)) { + pccbb_pcic_do_io_map(sc, win); + } + } + } + return 0; +} + +static void +pccbb_pcic_power_disable_socket(device_t self, device_t child) +{ + struct pccbb_softc *sc = device_get_softc(self); + + DPRINTF(("pccbb_pcic_socket_disable\n")); + + /* reset signal asserting... */ + PCIC_MASK(sc, PCIC_INTR, & ~PCIC_INTR_RESET); + DELAY(2*1000); + + /* power down the socket */ + PCIC_MASK(sc, PCIC_PWRCTL, &~PCIC_PWRCTL_OE); + pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + + /* wait 300ms until power fails (Tpf). */ + DELAY(300 * 1000); +} + +/************************************************************************/ +/* PC Card Resource Functions */ /************************************************************************/ static void @@ -1387,6 +1580,12 @@ pccbb_pcic_alloc_resource(device_t self, device_t child, int type, int* rid, struct pccbb_softc *sc = device_get_softc(self); struct pccbb_reslist *rle; + /* Nearly default */ + if (type == SYS_RES_MEMORY && start == 0 && end == ~0 && count != 1) { + start = 0xd0000; /* XXX */ + end = 0xdffff; + } + switch (type) { case SYS_RES_MEMORY: /* Nearly default */ @@ -1463,7 +1662,7 @@ pccbb_pcic_set_res_flags(device_t self, device_t child, int type, int rid, if (type != SYS_RES_MEMORY) return (EINVAL); - sc->mem[rid].kind = PCCARD_MEM_ATTR; + sc->mem[rid].kind = flags; pccbb_pcic_do_mem_map(sc, rid); return 0; } @@ -1496,93 +1695,32 @@ pccbb_pcic_set_memory_offset(device_t self, device_t child, int rid, return 0; } +/************************************************************************/ +/* POWER methods */ +/************************************************************************/ + static int -pccbb_pcic_enable_socket(device_t self, device_t child) +pccbb_power_enable_socket(device_t self, device_t child) { struct pccbb_softc *sc = device_get_softc(self); - DPRINTF(("pccbb_pcic_socket_enable:\n")); - - /* power down/up the socket to reset */ - { - int voltage = pccbb_detect_voltage(sc); - - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); - if (voltage & CARD_5V_CARD) - pccbb_power(self, CARD_VCC_5V | CARD_VPP_VCC); - else if (voltage & CARD_3V_CARD) - pccbb_power(self, CARD_VCC_3V | CARD_VPP_VCC); - else { - device_printf(self, "Unknown card voltage\n"); - return ENXIO; - } - } - - /* enable socket i/o */ - PCIC_MASK(sc, PCIC_PWRCTL, | PCIC_PWRCTL_OE); - - PCIC_WRITE(sc, PCIC_INTR, PCIC_INTR_ENABLE); - /* hold reset for 30ms */ - DELAY(30*1000); - /* clear the reset flag */ - PCIC_MASK(sc, PCIC_INTR, | PCIC_INTR_RESET); - /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ - DELAY(20*1000); - - pccbb_pcic_wait_ready(sc); - - /* disable all address windows */ - PCIC_WRITE(sc, PCIC_ADDRWIN_ENABLE, 0); - - { - int cardtype; - CARD_GET_TYPE(child, &cardtype); - PCIC_MASK(sc, PCIC_INTR, | ((cardtype == PCCARD_IFTYPE_IO) ? - PCIC_INTR_CARDTYPE_IO : - PCIC_INTR_CARDTYPE_MEM)); - DEVPRINTF((sc->sc_dev, "card type is %s\n", - (cardtype == PCCARD_IFTYPE_IO) ? "io" : "mem")); - } - - /* reinstall all the memory and io mappings */ - { - int win; - - for (win = 0; win < PCIC_MEM_WINS; ++win) { - if (sc->memalloc & (1 << win)) { - pccbb_pcic_do_mem_map(sc, win); - } - } - for (win = 0; win < PCIC_IO_WINS; ++win) { - if (sc->ioalloc & (1 << win)) { - pccbb_pcic_do_io_map(sc, win); - } - } - } - return 0; + if (sc->sc_flags & PCCBB_16BIT_CARD) + return pccbb_pcic_power_enable_socket(self, child); + else + return pccbb_cardbus_power_enable_socket(self, child); } static void -pccbb_pcic_disable_socket(device_t self, device_t child) +pccbb_power_disable_socket(device_t self, device_t child) { struct pccbb_softc *sc = device_get_softc(self); - - DPRINTF(("pccbb_pcic_socket_disable\n")); - - /* reset signal asserting... */ - PCIC_MASK(sc, PCIC_INTR, & ~PCIC_INTR_RESET); - DELAY(2*1000); - - /* power down the socket */ - PCIC_MASK(sc, PCIC_PWRCTL, &~PCIC_PWRCTL_OE); - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); - - /* wait 300ms until power fails (Tpf). */ - DELAY(300 * 1000); + if (sc->sc_flags & PCCBB_16BIT_CARD) + pccbb_pcic_power_disable_socket(self, child); + else + pccbb_cardbus_power_disable_socket(self, child); } - /************************************************************************/ -/* Methods */ +/* BUS Methods */ /************************************************************************/ @@ -1641,6 +1779,10 @@ pccbb_release_resource(device_t self, device_t child, int type, int rid, rid, r); } +/************************************************************************/ +/* PCI compat methods */ +/************************************************************************/ + static int pccbb_maxslots(device_t dev) { @@ -1648,8 +1790,7 @@ pccbb_maxslots(device_t dev) } static u_int32_t -pccbb_read_config(device_t dev, int b, int s, int f, - int reg, int width) +pccbb_read_config(device_t dev, int b, int s, int f, int reg, int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). @@ -1659,8 +1800,8 @@ pccbb_read_config(device_t dev, int b, int s, int f, } static void -pccbb_write_config(device_t dev, int b, int s, int f, - int reg, u_int32_t val, int width) +pccbb_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, + int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). @@ -1673,8 +1814,7 @@ static device_method_t pccbb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pccbb_probe), DEVMETHOD(device_attach, pccbb_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_detach, pccbb_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -1684,24 +1824,23 @@ static device_method_t pccbb_methods[] = { DEVMETHOD(bus_release_resource, pccbb_release_resource), DEVMETHOD(bus_activate_resource, pccbb_activate_resource), DEVMETHOD(bus_deactivate_resource, pccbb_deactivate_resource), + DEVMETHOD(bus_driver_added, pccbb_driver_added), + DEVMETHOD(bus_child_detached, pccbb_child_detached), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + /* 16-bit card interface */ + DEVMETHOD(card_set_res_flags, pccbb_pcic_set_res_flags), + DEVMETHOD(card_set_memory_offset, pccbb_pcic_set_memory_offset), + + /* power interface */ + DEVMETHOD(power_enable_socket, pccbb_power_enable_socket), + DEVMETHOD(power_disable_socket, pccbb_power_disable_socket), + /* pcib compatibility interface */ DEVMETHOD(pcib_maxslots, pccbb_maxslots), DEVMETHOD(pcib_read_config, pccbb_read_config), DEVMETHOD(pcib_write_config, pccbb_write_config), - - DEVMETHOD(pccbb_power_socket, pccbb_power), - DEVMETHOD(pccbb_detect_card, pccbb_cardbus_detect_card), - DEVMETHOD(pccbb_reset, pccbb_cardbus_reset), - - DEVMETHOD(card_set_res_flags, pccbb_pcic_set_res_flags), - DEVMETHOD(card_set_memory_offset, pccbb_pcic_set_memory_offset), - - DEVMETHOD(power_enable_socket, pccbb_pcic_enable_socket), - DEVMETHOD(power_disable_socket, pccbb_pcic_disable_socket), - {0,0} }; @@ -1710,9 +1849,9 @@ static driver_t pccbb_driver = { pccbb_methods, sizeof(struct pccbb_softc) }; -static devclass_t pccbb_devclass = { -}; + +static devclass_t pccbb_devclass; + DRIVER_MODULE(pccbb, pci, pccbb_driver, pccbb_devclass, 0, 0); - SYSINIT(pccbb, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, pccbb_start_threads, 0); diff --git a/sys/dev/pccbb/pccbb_if.m b/sys/dev/pccbb/pccbb_if.m deleted file mode 100644 index 2f3ddd304484..000000000000 --- a/sys/dev/pccbb/pccbb_if.m +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2000,2001 Jonathan Chen. -# 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, -# without modification, immediately at the beginning of the file. -# 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. -# -# $FreeBSD$ -# - -#include - -INTERFACE pccbb; - -METHOD int power_socket { - device_t dev; - int command; -}; - -METHOD int detect_card { - device_t dev; -}; - -METHOD int reset { - device_t dev; -}; - -HEADER { -/* result of detect_card */ - #define CARD_UKN_CARD 0x00 - #define CARD_5V_CARD 0x01 - #define CARD_3V_CARD 0x02 - #define CARD_XV_CARD 0x04 - #define CARD_YV_CARD 0x08 - -/* for power_socket */ - #define CARD_VCC_UC 0x0000 - #define CARD_VCC_3V 0x0001 - #define CARD_VCC_XV 0x0002 - #define CARD_VCC_YV 0x0003 - #define CARD_VCC_0V 0x0004 - #define CARD_VCC_5V 0x0005 - #define CARD_VCCMASK 0x000f - #define CARD_VPP_UC 0x0000 - #define CARD_VPP_VCC 0x0010 - #define CARD_VPP_12V 0x0030 - #define CARD_VPP_0V 0x0040 - #define CARD_VPPMASK 0x00f0 -}; diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h index 0a220464c445..1270ec2551d3 100644 --- a/sys/dev/pccbb/pccbbvar.h +++ b/sys/dev/pccbb/pccbbvar.h @@ -66,12 +66,13 @@ struct pccbb_softc { void *sc_intrhand; struct pccbb_socketreg *sc_socketreg; u_int32_t sc_flags; + struct mtx sc_mtx; #define PCCBB_PCIC_IO_RELOC 0x01 #define PCCBB_PCIC_MEM_32 0x02 -#define PCCBB_CARDSTATUS_BUSY 0x01000000 -#define PCCBB_CARDATTACHED 0x02000000 -#define PCCBB_16BIT_CARD 0x04000000 -#define PCCBB_INITIALCARD 0x08000000 +#define PCCBB_CARDATTACHED 0x01000000 +#define PCCBB_16BIT_CARD 0x02000000 +#define PCCBB_KTHREAD_RUNNING 0x04000000 +#define PCCBB_KTHREAD_DONE 0x08000000 int sc_chipset; /* chipset id */ #define CB_UNKNOWN 0 /* NOT Cardbus-PCI bridge */ #define CB_TI113X 1 /* TI PCI1130/1131 */ @@ -97,9 +98,30 @@ struct pccbb_softc { struct proc *event_thread; }; +/* result of detect_card */ +#define CARD_UKN_CARD 0x00 +#define CARD_5V_CARD 0x01 +#define CARD_3V_CARD 0x02 +#define CARD_XV_CARD 0x04 +#define CARD_YV_CARD 0x08 + +/* for power_socket */ +#define CARD_VCC_UC 0x0000 +#define CARD_VCC_3V 0x0001 +#define CARD_VCC_XV 0x0002 +#define CARD_VCC_YV 0x0003 +#define CARD_VCC_0V 0x0004 +#define CARD_VCC_5V 0x0005 +#define CARD_VCCMASK 0x000f +#define CARD_VPP_UC 0x0000 +#define CARD_VPP_VCC 0x0010 +#define CARD_VPP_12V 0x0030 +#define CARD_VPP_0V 0x0040 +#define CARD_VPPMASK 0x00f0 + /* XXX: rman is dumb */ #define CARDBUS_SYS_RES_MEMORY_START 0x18020000 #define CARDBUS_SYS_RES_MEMORY_END 0xEFFFFFFF -#define CARDBUS_SYS_RES_IOPORT_START 0x2000 +#define CARDBUS_SYS_RES_IOPORT_START 0x3000 #define CARDBUS_SYS_RES_IOPORT_END 0xEFFF diff --git a/sys/modules/cardbus/Makefile b/sys/modules/cardbus/Makefile index 5ac7d33ea465..3491ad4b6184 100644 --- a/sys/modules/cardbus/Makefile +++ b/sys/modules/cardbus/Makefile @@ -1,9 +1,9 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../dev/cardbus -KMOD= cardbus -SRCS= cardbus.c \ - device_if.h bus_if.h +.PATH: ${.CURDIR}/../../dev/cardbus +KMOD= cardbus +SRCS= cardbus.c cardbus_cis.c \ + device_if.h bus_if.h card_if.h power_if.h pci_if.h pcib_if.h NOMAN= .include diff --git a/sys/modules/pccbb/Makefile b/sys/modules/pccbb/Makefile new file mode 100644 index 000000000000..7d0218ca4130 --- /dev/null +++ b/sys/modules/pccbb/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/pccbb +KMOD= pccbb +SRCS= pccbb.c \ + device_if.h bus_if.h power_if.h card_if.h pci_if.h pcib_if.h + +.include