diff --git a/sys/conf/files b/sys/conf/files index 22a25377d038..baec5aa506e7 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -146,6 +146,9 @@ dev/buslogic/bt_isa.c optional bt isa 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 @@ -240,10 +243,12 @@ dev/mly/mly_pci.c optional mly dev/musycc/musycc.c optional musycc dev/null/null.c standard dev/pccard/card_if.m optional card +dev/pccard/card_if.m optional cardbus dev/pccard/card_if.m optional pccard dev/pccard/pccard.c optional pccard dev/pccard/pccard_cis.c optional pccard dev/pccard/pccard_cis_quirks.c optional pccard +dev/pccard/power_if.m optional pccbb dev/pccard/power_if.m optional pccard dev/pcic/i82365.c optional pcic pccard dev/pcic/i82365_isa.c optional pcic pccard @@ -958,7 +963,7 @@ pci/isp_pci.c optional isp pci/meteor.c count meteor pci pci/ncr.c optional ncr pci/ohci_pci.c optional ohci -pci/pccbb.c optional pccbb cardbus +dev/pccbb/pccbb.c optional pccbb pci/pci.c count pci pci/pci_compat.c optional pci compat_oldpci \ warning "Old PCI driver compatability shims present." diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index 394f1c965a04..2d68310f7e7a 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -1,420 +1,990 @@ -/* $Id: cardbus.c,v 1.1.2.1 1999/02/16 16:44:35 haya Exp $ */ - /* - * Copyright (c) 1997 and 1998 HAYAKAWA Koichi. All rights reserved. + * 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. + * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HAYAKAWA Koichi. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 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. * - * 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. + * $FreeBSD$ */ -/* FreeBSD/newconfig version. UCHIYAMA Yasushi 1999 */ -/* $FreeBSD$ */ + +/* + * Cardbus Bus Driver + * + * much of the bus code was stolen directly from sys/pci/pci.c + * (Copyright (c) 1997, Stefan Esser ) + * + * Written by Jonathan Chen + */ + #define CARDBUS_DEBUG -#include #include #include -#include #include #include -#include +#include #include +#include +#include -#include +#include +#include +#include #include #include +#include -#include -#include +#include "pccbb_if.h" +#include "card_if.h" +#include "pcib_if.h" -#include -#include - -#include -#include #if defined CARDBUS_DEBUG #define STATIC #define DPRINTF(a) printf a -#define DDELAY(x) delay((x)*1000*1000) +#define DEVPRINTF(x) device_printf x #else #define STATIC static #define DPRINTF(a) +#define DEVPRINTF(x) #endif -STATIC void cardbusattach __P((struct device *, struct device *, void *)); -STATIC int cardbusmatch __P((struct device *, struct cfdata *, void *)); -static int cardbussubmatch __P((struct device *, struct cfdata *, void *)); -static int cardbusprint __P((void *, const char *)); +#if !defined(lint) +static const char rcsid[] = + "$FreeBSD $"; +#endif -static u_int8_t *decode_tuple __P((u_int8_t *)); -static int decode_tuples __P((u_int8_t *, int)); -static char *tuple_name __P((int)); -struct cfattach cardbus_ca = { - sizeof(struct cardbus_softc), cardbusmatch, cardbusattach +struct cardbus_quirk { + u_int32_t devid; /* Vendor/device of the card */ + int type; +#define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in wierd place */ + int arg1; + int arg2; }; -STATIC int -cardbusmatch(parent, cf, aux) - struct device *parent; - struct cfdata *cf; - void *aux; +struct cardbus_quirk cardbus_quirks[] = { + { 0 } +}; + +static int cardbus_probe(device_t dev); +static int cardbus_attach(device_t dev); +static void device_setup_regs(device_t cbdev, int b, int s, int f, + pcicfgregs *cfg); +static int cardbus_attach_card(device_t dev); +static int cardbus_detach_card(device_t dev, int flags); +static struct cardbus_devinfo *cardbus_read_device(device_t pcib, + int b, int s, int f); +static void *cardbus_readppb(device_t pcib, int b, int s, int f); +static void *cardbus_readpcb(device_t pcib, int b, int s, int f); +static void cardbus_hdrtypedata(device_t pcib, int b, int s, int f, + pcicfgregs *cfg); +static int cardbus_freecfg(struct cardbus_devinfo *dinfo); +static void cardbus_print_verbose(struct cardbus_devinfo *dinfo); +static int cardbus_set_resource(device_t dev, device_t child, int type, + int rid, u_long start, u_long count); +static int cardbus_get_resource(device_t dev, device_t child, int type, + int rid, u_long *startp, u_long *countp); +static void cardbus_delete_resource(device_t dev, device_t child, int type, + int rid); +static int cardbus_set_resource_method(device_t dev, device_t child, int type, + int rid, u_long start, u_long count); +static int cardbus_get_resource_method(device_t dev, device_t child, int type, + int rid, u_long *startp, u_long *countp); +static void cardbus_add_map(device_t bdev, device_t dev, + pcicfgregs *cfg, int reg); +static void cardbus_add_resources(device_t dev, pcicfgregs* cfg); +static void 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, int* rid,u_long start, + u_long end, u_long count, + u_int flags); +static int cardbus_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r); +static int cardbus_print_resources(struct resource_list *rl, const char *name, + int type, const char *format); +static int cardbus_print_child(device_t dev, device_t child); +static void cardbus_probe_nomatch(device_t dev, device_t child); +static int cardbus_read_ivar(device_t dev, device_t child, int which, + u_long *result); +static int cardbus_write_ivar(device_t dev, device_t child, int which, + uintptr_t value); +static u_int32_t cardbus_read_config_method(device_t dev, device_t child, + int reg, int width); +static void cardbus_write_config_method(device_t dev, device_t child, int reg, + u_int32_t val, int width); + +/************************************************************************/ +/* Probe/Attach */ +/************************************************************************/ + +static int +cardbus_probe(device_t dev) { - struct cbslot_attach_args *cba = aux; - - /* which slot? */ - if (cf->cbslotcf_slot != CBSLOT_UNK_SLOT && - cf->cbslotcf_slot != cba->cba_function) { - - DPRINTF(("cardbusmatch: function differs %d <=> %d\n", - cf->cbslotcf_slot, cba->cba_function)); - + device_set_desc(dev, "Cardbus bus (newcard)"); return 0; - } - - if (cba->cba_function < 0 || cba->cba_function > 255) { - return 0; - } - - return 1; } -void -cardslot_if_setup (struct cardbus_softc *csc) +static int +cardbus_attach(device_t dev) { - csc->sc_if.if_card_attach = cardbus_attach_card; -} - -STATIC void -cardbusattach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; -{ - struct pccbb_softc *psc = (struct pccbb_softc *)parent; - struct cardbus_softc *sc = (void *)self; - struct cbslot_attach_args *cba = aux; - int cdstatus; - - sc->sc_bus = cba->cba_bus; - sc->sc_device = cba->cba_function; - sc->sc_intrline = cba->cba_intrline; - - printf(" bus %d device %d\n", sc->sc_bus, sc->sc_device); - - sc->sc_iot = cba->cba_iot; /* CardBus I/O space tag */ - sc->sc_memt = cba->cba_memt; /* CardBus MEM space tag */ - sc->sc_dmat = cba->cba_dmat; /* DMA tag */ - - sc->sc_cc = cba->cba_cc; - sc->sc_cf = cba->cba_cf; - cardslot_if_setup (sc); - cdstatus = 0; - - if ((cdstatus = (sc->sc_cf->cardbus_ctrl)(sc->sc_cc, CARDBUS_CD))) { - DPRINTF(("cardbusattach: CardBus card found [0x%x]\n", cdstatus)); - psc->sc_cbdev = cardbus_attach_card(sc); - } -} - -/********************************************************************** -* int cardbus_attach_card(struct cardbus_softc *sc) -* This functions attaches the card on the slot: turns on power, -* reads and analyses tuple, sets consifuration index. -***********************************************************************/ -struct device * -cardbus_attach_card(sc) - struct cardbus_softc *sc; -{ - struct device *attached_device = NULL; - cardbus_chipset_tag_t cc; - cardbus_function_tag_t cf; - int cdstatus; - cardbustag_t tag; - cardbusreg_t id, class, cis_ptr, bhlcr; - u_int8_t tuple[2048]; - int function, max_func, device; - - cc = sc->sc_cc; - cf = sc->sc_cf; - - DPRINTF(("cardbus_attach_card: cb%d start\n", sc->sc_dev.dv_unit)); - - /* inspect initial voltage */ - if (0 == (cdstatus = (cf->cardbus_ctrl)(cc, CARDBUS_CD))) { - DPRINTF(("cardbusattach: no CardBus card on cb%d\n", sc->sc_dev.dv_unit)); return 0; - } +} - if (cdstatus & CARDBUS_3V_CARD) { - cf->cardbus_power(cc, CARDBUS_VCC_3V); - } - (cf->cardbus_ctrl)(cc, CARDBUS_RESET); +/************************************************************************/ +/* Attach/Detach card */ +/************************************************************************/ - device = 0; /* Only one card can attach cardbus slot */ - function = 0; +static void +device_setup_regs(device_t bdev, int b, int s, int f, pcicfgregs *cfg) +{ + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_COMMAND, + PCIB_READ_CONFIG(bdev, b, s, f, PCIR_COMMAND, 2) | + PCIM_CMD_MEMEN|PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN, + 2); + + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_INTLINE, + pci_get_irq(device_get_parent(bdev)), 1); + cfg->intline = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_INTLINE, 1); + + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1); + cfg->cachelnsz = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_CACHELNSZ, 1); - tag = cardbus_make_tag (cc, cf, sc->sc_bus, device, function); + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 0xa8, 1); + cfg->lattimer = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 1); - bhlcr = (cf->cardbus_conf_read)(cc, tag, CARDBUS_BHLC_REG); - max_func = CARDBUS_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MINGNT, 0x14, 1); + cfg->mingnt = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MINGNT, 1); - for (function = 0; function < max_func; function++) { - if (function) - tag = cardbus_make_tag (cc, cf, sc->sc_bus, device, function); + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 0x14, 1); + cfg->maxlat = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 1); +} - id = (cf->cardbus_conf_read)(cc, tag, CARDBUS_ID_REG); - if (CARDBUS_VENDOR(id) == 0xffff || CARDBUS_VENDOR(id) == 0) { - cardbus_free_tag (cc, cf, tag); - continue; +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; } - class = (cf->cardbus_conf_read)(cc, tag, CARDBUS_CLASS_REG); - cis_ptr = (cf->cardbus_conf_read)(cc, tag, CARDBUS_CIS_REG); - - DPRINTF(("cardbus_attach_card: Vendor 0x%x, Product 0x%x, CIS 0x%x\n", - CARDBUS_VENDOR(id), CARDBUS_PRODUCT(id), cis_ptr)); - - bzero(tuple, 2048); - - if (0 == (cis_ptr & CARDBUS_CIS_ASIMASK)) { - int i = cis_ptr & CARDBUS_CIS_ADDRMASK; - int j = 0; - - for (; i < 0xff; i += 4) { - u_int32_t e = (cf->cardbus_conf_read)(cc, tag, i); - tuple[j] = 0xff & e; - e >>= 8; - tuple[j + 1] = 0xff & e; - e >>= 8; - tuple[j + 2] = 0xff & e; - e >>= 8; - tuple[j + 3] = 0xff & e; - j += 4; - } - } - - decode_tuples(tuple, 2048); - if (function == 0) { - struct cardbus_attach_args ca; - cardbusreg_t intr = cardbus_conf_read(cc, cf, tag, CARDBUS_INTERRUPT_REG); - - ca.ca_unit = sc->sc_dev.dv_unit; - ca.ca_cc = sc->sc_cc; - ca.ca_cf = sc->sc_cf; - - ca.ca_iot = sc->sc_iot; - ca.ca_memt = sc->sc_memt; - ca.ca_dmat = sc->sc_dmat; - - ca.ca_tag = tag; - ca.ca_device = device; - ca.ca_function = function; - ca.ca_id = id; - ca.ca_class = class; - - ca.ca_intrline = sc->sc_intrline; - - attached_device = config_found_sm((void *)sc, &ca, cardbusprint, cardbussubmatch); + if (cdstatus & CARD_3V_CARD) { + PCCBB_POWER_SOCKET(bdev, CARD_VCC_3V); } else { - printf ("cardbus_attach_card: XXX Multi-function can't handle. function 0 only.\n"); + device_printf(dev, "unsupported power: %d\n", cdstatus); + return EINVAL; } - cardbus_free_tag (cc, cf, tag); - } - if (!attached_device) - cf->cardbus_power(cc, CARDBUS_VCC_0V); - return attached_device; + PCCBB_RESET(bdev); + + bus = pci_get_secondarybus(bdev); + if (bus == 0) { + /* + * XXX EVILE BAD XXX + * Not all BIOSes initialize the secondary bus number properly, + * so if the default is bad, we just put one in and hope it + * works. + */ + bus = curr_bus_number; + pci_write_config (bdev, PCIR_SECBUS_2, curr_bus_number, 1); + pci_write_config (bdev, PCIR_SUBBUS_2, curr_bus_number+2, 1); + curr_bus_number += 3; + } + + for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) { + int cardbusfunchigh = 0; + for (func = 0; func <= cardbusfunchigh; func++) { + struct cardbus_devinfo *dinfo = + cardbus_read_device(bdev, bus, slot, func); + + if (dinfo == NULL) continue; + if (dinfo->cfg.mfdev) + cardbusfunchigh = CARDBUS_FUNCMAX; + device_setup_regs(bdev, bus, slot, func, &dinfo->cfg); + cardbus_print_verbose(dinfo); + dinfo->cfg.dev = device_add_child(dev, NULL, -1); + if (!dinfo->cfg.dev) { + DEVPRINTF((dev, "Cannot add child!\n")); + cardbus_freecfg(dinfo); + continue; + } + resource_list_init(&dinfo->resources); + device_set_ivars(dinfo->cfg.dev, dinfo); + cardbus_add_resources(dinfo->cfg.dev, &dinfo->cfg); + cardbus_do_cis(dev, dinfo->cfg.dev); + if (device_probe_and_attach(dinfo->cfg.dev) != 0) { + cardbus_release_all_resources(dinfo->cfg.dev, + &dinfo->resources); + device_delete_child(dev, dinfo->cfg.dev); + cardbus_freecfg(dinfo); + } else + cardattached++; + } + } + + if (cardattached > 0) return 0; + return ENOENT; } static int -cardbussubmatch(parent, cf, aux) - struct device *parent; - struct cfdata *cf; - void *aux; +cardbus_detach_card(device_t dev, int flags) { - struct cardbus_attach_args *ca = aux; + int numdevs; + device_t *devlist; + int tmp; + int err=0; - if (cf->cardbuscf_dev != CARDBUS_UNK_DEV && - cf->cardbuscf_dev != ca->ca_unit) { - return 0; - } - if (cf->cardbuscf_function != CARDBUS_UNK_FUNCTION && - cf->cardbuscf_function != ca->ca_function) { - return 0; - } + device_get_children(dev, &devlist, &numdevs); - return ((*cf->cf_attach->ca_match)(parent, cf, aux)); + if (numdevs == 0) { + DEVPRINTF((dev, "Detaching card: no cards to detach!\n")); + 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]); + cardbus_freecfg(dinfo); + } + return err; +} + +/************************************************************************/ +/* PCI-Like config reading (copied from pci.c */ +/************************************************************************/ + +/* read configuration header into pcicfgrect structure */ + +static struct cardbus_devinfo * +cardbus_read_device(device_t pcib, int b, int s, int f) +{ +#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) + pcicfgregs *cfg = NULL; + struct cardbus_devinfo *devlist_entry = NULL; + + if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != -1) { + devlist_entry = malloc(sizeof(struct cardbus_devinfo), + M_DEVBUF, M_WAITOK); + if (devlist_entry == NULL) + return (NULL); + bzero(devlist_entry, sizeof *devlist_entry); + + cfg = &devlist_entry->cfg; + + cfg->bus = b; + cfg->slot = s; + cfg->func = f; + cfg->vendor = REG(PCIR_VENDOR, 2); + cfg->device = REG(PCIR_DEVICE, 2); + cfg->cmdreg = REG(PCIR_COMMAND, 2); + cfg->statreg = REG(PCIR_STATUS, 2); + cfg->baseclass = REG(PCIR_CLASS, 1); + cfg->subclass = REG(PCIR_SUBCLASS, 1); + cfg->progif = REG(PCIR_PROGIF, 1); + cfg->revid = REG(PCIR_REVID, 1); + cfg->hdrtype = REG(PCIR_HEADERTYPE, 1); + cfg->cachelnsz = REG(PCIR_CACHELNSZ, 1); + cfg->lattimer = REG(PCIR_LATTIMER, 1); + cfg->intpin = REG(PCIR_INTPIN, 1); + cfg->intline = REG(PCIR_INTLINE, 1); +#ifdef __alpha__ + alpha_platform_assign_pciintr(cfg); +#endif + +#ifdef APIC_IO + if (cfg->intpin != 0) { + int airq; + + airq = pci_apic_irq(cfg->bus, cfg->slot, cfg->intpin); + if (airq >= 0) { + /* PCI specific entry found in MP table */ + if (airq != cfg->intline) { + undirect_pci_irq(cfg->intline); + cfg->intline = airq; + } + } else { + /* + * PCI interrupts might be redirected to the + * ISA bus according to some MP tables. Use the + * same methods as used by the ISA devices + * devices to find the proper IOAPIC int pin. + */ + airq = isa_apic_irq(cfg->intline); + if ((airq >= 0) && (airq != cfg->intline)) { + /* XXX: undirect_pci_irq() ? */ + undirect_isa_irq(cfg->intline); + cfg->intline = airq; + } + } + } +#endif /* APIC_IO */ + + cfg->mingnt = REG(PCIR_MINGNT, 1); + cfg->maxlat = REG(PCIR_MAXLAT, 1); + + cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; + cfg->hdrtype &= ~PCIM_MFDEV; + + cardbus_hdrtypedata(pcib, b, s, f, cfg); + + devlist_entry->conf.pc_sel.pc_bus = cfg->bus; + devlist_entry->conf.pc_sel.pc_dev = cfg->slot; + devlist_entry->conf.pc_sel.pc_func = cfg->func; + devlist_entry->conf.pc_hdr = cfg->hdrtype; + + devlist_entry->conf.pc_subvendor = cfg->subvendor; + devlist_entry->conf.pc_subdevice = cfg->subdevice; + devlist_entry->conf.pc_vendor = cfg->vendor; + devlist_entry->conf.pc_device = cfg->device; + + devlist_entry->conf.pc_class = cfg->baseclass; + devlist_entry->conf.pc_subclass = cfg->subclass; + devlist_entry->conf.pc_progif = cfg->progif; + devlist_entry->conf.pc_revid = cfg->revid; + } + return (devlist_entry); +#undef REG +} + +/* read config data specific to header type 1 device (PCI to PCI bridge) */ + +static void * +cardbus_readppb(device_t pcib, int b, int s, int f) +{ + pcih1cfgregs *p; + + p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); + + bzero(p, sizeof *p); + + p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_1, 2); + p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_1, 2); + + p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_1, 1); + + p->iobase = PCI_PPBIOBASE (PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_IOBASEH_1, 2), + PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_IOBASEL_1, 1)); + p->iolimit = PCI_PPBIOLIMIT (PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_IOLIMITH_1, 2), + PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_IOLIMITL_1, 1)); + + p->membase = PCI_PPBMEMBASE (0, + PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_MEMBASE_1, 2)); + p->memlimit = PCI_PPBMEMLIMIT (0, + PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_MEMLIMIT_1, 2)); + + p->pmembase = PCI_PPBMEMBASE ( + (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEH_1, 4), + PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEL_1, 2)); + + p->pmemlimit = PCI_PPBMEMLIMIT ( + (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f, + PCIR_PMLIMITH_1, 4), + PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMLIMITL_1, 2)); + + return (p); +} + +/* read config data specific to header type 2 device (PCI to CardBus bridge) */ + +static void * +cardbus_readpcb(device_t pcib, int b, int s, int f) +{ + pcih2cfgregs *p; + + p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); + + bzero(p, sizeof *p); + + p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_2, 2); + p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_2, 2); + + p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_2, 1); + + p->membase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE0_2, 4); + p->memlimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT0_2, 4); + p->membase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE1_2, 4); + p->memlimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT1_2, 4); + + p->iobase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE0_2, 4); + p->iolimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT0_2, 4); + p->iobase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE1_2, 4); + p->iolimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT1_2, 4); + + p->pccardif = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PCCARDIF_2, 4); + return p; +} + +/* extract header type specific config data */ + +static void +cardbus_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg) +{ +#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) + switch (cfg->hdrtype) { + case 0: + cfg->subvendor = REG(PCIR_SUBVEND_0, 2); + cfg->subdevice = REG(PCIR_SUBDEV_0, 2); + cfg->nummaps = PCI_MAXMAPS_0; + break; + case 1: + cfg->subvendor = REG(PCIR_SUBVEND_1, 2); + cfg->subdevice = REG(PCIR_SUBDEV_1, 2); + cfg->secondarybus = REG(PCIR_SECBUS_1, 1); + cfg->subordinatebus = REG(PCIR_SUBBUS_1, 1); + cfg->nummaps = PCI_MAXMAPS_1; + cfg->hdrspec = cardbus_readppb(pcib, b, s, f); + break; + case 2: + cfg->subvendor = REG(PCIR_SUBVEND_2, 2); + cfg->subdevice = REG(PCIR_SUBDEV_2, 2); + cfg->secondarybus = REG(PCIR_SECBUS_2, 1); + cfg->subordinatebus = REG(PCIR_SUBBUS_2, 1); + cfg->nummaps = PCI_MAXMAPS_2; + cfg->hdrspec = cardbus_readpcb(pcib, b, s, f); + break; + } +#undef REG +} + +/* free pcicfgregs structure and all depending data structures */ + +static int +cardbus_freecfg(struct cardbus_devinfo *dinfo) +{ + if (dinfo->cfg.hdrspec != NULL) + free(dinfo->cfg.hdrspec, M_DEVBUF); + free(dinfo, M_DEVBUF); + + return (0); +} + +static void +cardbus_print_verbose(struct cardbus_devinfo *dinfo) +{ + if (bootverbose) { + pcicfgregs *cfg = &dinfo->cfg; + + printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", + cfg->vendor, cfg->device, cfg->revid); + printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", + cfg->baseclass, cfg->subclass, cfg->progif, + cfg->hdrtype, cfg->mfdev); + printf("\tsubordinatebus=%x \tsecondarybus=%x\n", + cfg->subordinatebus, cfg->secondarybus); +#ifdef CARDBUS_DEBUG + printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", + cfg->lattimer, cfg->lattimer * 30, + cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); +#endif /* CARDBUS_DEBUG */ + if (cfg->intpin > 0) + printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + } +} + +/************************************************************************/ +/* Resources */ +/************************************************************************/ + +static int +cardbus_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + resource_list_add(rl, type, rid, start, start + count - 1, count); + if (rid == CARDBUS_ROM_REG) start |= 1; + if (device_get_parent(child) == dev) + pci_write_config(child, rid, start, 4); + return 0; } static int -cardbusprint(aux, pnp) - void *aux; - const char *pnp; +cardbus_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - register struct cardbus_attach_args *ca = aux; - char devinfo[256]; - - if (pnp) { - printf("vendor 0x%04x id 0x%04x at %s", - CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id), pnp); - } - printf(" dev %d function %d", ca->ca_device, ca->ca_function); - return UNCONF; -} - -/********************************************************************** -* void *cardbus_intr_establish(cc, cf, irq, level, func, arg) -* Interrupt handler of pccard. -* args: -* cardbus_chipset_tag_t *cc -* int irq: -**********************************************************************/ -void * -cardbus_intr_establish(cc, cf, irq, level, func, arg) - cardbus_chipset_tag_t cc; - cardbus_function_tag_t cf; - cardbus_intr_handle_t irq; - int level; - int (*func) __P((void *)); - void *arg; -{ - DPRINTF(("- cardbus_intr_establish: irq %d\n", irq)); - - return (*cf->cardbus_intr_establish)(cc, irq, level, func, arg); -} - -/********************************************************************** -* void cardbus_intr_disestablish(cc, cf, handler) -* Interrupt handler of pccard. -* args: -* cardbus_chipset_tag_t *cc -**********************************************************************/ -void -cardbus_intr_disestablish(cc, cf, handler) - cardbus_chipset_tag_t cc; - cardbus_function_tag_t cf; - void *handler; -{ - DPRINTF(("- cardbus_intr_disestablish\n")); - - (*cf->cardbus_intr_disestablish)(cc, handler); - return; -} - -/********************************************************************** -* below this line, there are some functions for decoding tuples. -* They should go out from this file. -**********************************************************************/ -static int -decode_tuples(tuple, buflen) - u_int8_t *tuple; - int buflen; -{ - u_int8_t *tp = tuple; - - if (CISTPL_LINKTARGET != *tuple) { - DPRINTF(("WRONG TUPLE\n")); + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; + rle = resource_list_find(rl, type, rid); + if (!rle) + return ENOENT; + if (startp) + *startp = rle->start; + if (countp) + *countp = rle->count; return 0; - } - - while (NULL != (tp = decode_tuple(tp))) { - if (tuple + buflen < tp) { - break; - } - } - - return 1; } -static u_int8_t * -decode_tuple(tuple) - u_int8_t *tuple; +static void +cardbus_delete_resource(device_t dev, device_t child, int type, int rid) { - u_int8_t type; - u_int8_t len; - int i; - - type = tuple[0]; - len = tuple[1] + 2; - - printf("tuple: %s len %d\n", tuple_name(type), len); - if (CISTPL_END == type) { - return NULL; - } - - for (i = 0; i < len; ++i) { - if (i % 16 == 0) { - printf(" 0x%2x:", i); + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; + rle = resource_list_find(rl, type, rid); + if (rle) { + if (rle->res) + bus_generic_release_resource(dev, child, type, rid, + rle->res); + resource_list_delete(rl, type, rid); } - printf(" %x",tuple[i]); - if (i % 16 == 15) { - printf("\n"); + if (device_get_parent(child) == dev) + pci_write_config(child, rid, 0, 4); +} + +static int +cardbus_set_resource_method(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) +{ + int ret; + ret = cardbus_set_resource(dev, child, type, rid, start, count); + if (ret != 0) return ret; + return BUS_SET_RESOURCE(device_get_parent(dev), child, type, rid, + start, count); +} + +static int +cardbus_get_resource_method(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) +{ + int ret; + ret = cardbus_get_resource(dev, child, type, rid, startp, countp); + if (ret != 0) return ret; + return BUS_GET_RESOURCE(device_get_parent(dev), child, type, rid, + startp, countp); +} + +static void +cardbus_delete_resource_method(device_t dev, device_t child, + int type, int rid) +{ + cardbus_delete_resource(dev, child, type, rid); + BUS_DELETE_RESOURCE(device_get_parent(dev), child, type, rid); +} + +static void +cardbus_add_map(device_t cbdev, device_t dev, pcicfgregs *cfg, int reg) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(dev); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; + device_t bdev = device_get_parent(cbdev); + u_int32_t size; + u_int32_t testval; + int type; + struct resource *res; + + PCIB_WRITE_CONFIG(bdev, cfg->bus, cfg->slot, cfg->func, + reg, 0xfffffff0, 4); + + testval = PCIB_READ_CONFIG(bdev, cfg->bus, cfg->slot, cfg->func, + reg, 4); + if (testval == 0xfffffff0 || testval == 0) return; + + if ((testval&1) == 0) + type = SYS_RES_MEMORY; + else + type = SYS_RES_IOPORT; + + size = CARDBUS_MAPREG_MEM_SIZE(testval); + res = bus_generic_alloc_resource(cbdev, dev, type, ®, 0, ~0, size, + rman_make_alignment_flags(size)); + if (res) { + u_int32_t start = rman_get_start(res); + u_int32_t end = rman_get_end(res); + cardbus_set_resource(cbdev, dev, type, reg, start,end-start+1); + rle = resource_list_find(rl, type, reg); + rle->res = res; + } else { + device_printf(dev, "Unable to add map %02x\n", reg); + } +} + +static void +cardbus_add_resources(device_t dev, pcicfgregs* cfg) +{ + device_t cbdev = device_get_parent(dev); + struct cardbus_devinfo *dinfo = device_get_ivars(dev); + struct resource_list *rl = &dinfo->resources; + struct cardbus_quirk *q; + struct resource_list_entry *rle; + struct resource *res; + int i; + + for (i = 0; i < cfg->nummaps; i++) { + cardbus_add_map(cbdev, dev, cfg, PCIR_MAPS + i*4); + } + cardbus_add_map(cbdev, dev, cfg, CARDBUS_ROM_REG); + + for (q = &cardbus_quirks[0]; q->devid; q++) { + if (q->devid == ((cfg->device << 16) | cfg->vendor) + && q->type == CARDBUS_QUIRK_MAP_REG) + cardbus_add_map(cbdev, dev, cfg, q->arg1); + } + + res = bus_generic_alloc_resource(cbdev, dev, SYS_RES_IRQ, + 0, 0, ~0, 1, RF_SHAREABLE); + + if (res == NULL) + panic("Cannot allocate IRQ for card\n"); + + resource_list_add(rl, SYS_RES_IRQ, 0, + rman_get_start(res), rman_get_start(res), 1); + rle = resource_list_find(rl, SYS_RES_IRQ, 0); + rle->res = res; +} + +static void +cardbus_release_all_resources(device_t dev, struct resource_list *rl) +{ + struct resource_list_entry *rle; + + SLIST_FOREACH(rle, rl, link) { + if (rle->res) { + bus_generic_release_resource(device_get_parent(dev), + dev, rle->type, rle->rid, + rle->res); + } + } +} + +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) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle = NULL; + struct resource *res; + + if (device_get_parent(child) == self || child == self) + rle = resource_list_find(rl, type, *rid); + if (rle) { + if (flags & RF_ACTIVE) + if (bus_activate_resource(child, type, *rid, + rle->res)) { + return NULL; + } + return rle->res; /* XXX: check if range within start/end */ + } else { + res = bus_generic_alloc_resource(self, child, type, rid, + start, end, count, flags); + if (res) { + start = rman_get_start(res); + end = rman_get_end(res); + cardbus_set_resource(self, child, type, *rid, start, + end-start+1); + rle = resource_list_find(rl, type, *rid); + rle->res = res; + return res; + } else { + device_printf(self, "Resource Allocation Failed!\n"); + return NULL; + } + } +} + +static int +cardbus_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + return bus_deactivate_resource(child, type, rid, r); +} + +/************************************************************************/ +/* Other Bus Methods */ +/************************************************************************/ + +static int +cardbus_print_resources(struct resource_list *rl, const char *name, + int type, const char *format) +{ + struct resource_list_entry *rle; + int printed, retval; + + printed = 0; + retval = 0; + /* Yes, this is kinda cheating */ + SLIST_FOREACH(rle, rl, link) { + if (rle->type == type) { + if (printed == 0) + retval += printf(" %s ", name); + else if (printed > 0) + retval += printf(","); + printed++; + retval += printf(format, rle->start); + if (rle->count > 1) { + retval += printf("-"); + retval += printf(format, rle->start + + rle->count - 1); + } + } + } + return retval; +} + +static int +cardbus_print_child(device_t dev, device_t child) +{ + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + pcicfgregs *cfg; + int retval = 0; + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + rl = &dinfo->resources; + + retval += bus_print_child_header(dev, child); + + retval += cardbus_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); + retval += cardbus_print_resources(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += cardbus_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); + if (device_get_flags(dev)) + retval += printf(" flags %#x", device_get_flags(dev)); + + retval += printf(" at device %d.%d", pci_get_slot(child), + pci_get_function(child)); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static void cardbus_probe_nomatch(device_t dev, device_t child) { + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + device_printf(dev, ""); + printf(" (vendor=0x%04x, dev=0x%04x)", cfg->vendor, cfg->device); + printf(" at %d.%d", pci_get_slot(child), pci_get_function(child)); + if (cfg->intpin > 0 && cfg->intline != 255) { + printf(" irq %d", cfg->intline); } - } - if (i % 16 != 0) { printf("\n"); - } - return tuple + len; + return; } -static char * -tuple_name(type) - int type; +static int +cardbus_read_ivar(device_t dev, device_t child, int which, u_long *result) { - static char *tuple_name_s [] = { - "TPL_NULL", "TPL_DEVICE", "Reserved", "Reserved", /* 0-3 */ - "CONFIG_CB", "CFTABLE_ENTRY_CB", "Reserved", "BAR", /* 4-7 */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 8-B */ - "Reserved", "Reserved", "Reserved", "Reserved", /* C-F */ - "CHECKSUM", "LONGLINK_A", "LONGLINK_C", "LINKTARGET", /* 10-13 */ - "NO_LINK", "VERS_1", "ALTSTR", "DEVICE_A", - "JEDEC_C", "JEDEC_A", "CONFIG", "CFTABLE_ENTRY", - "DEVICE_OC", "DEVICE_OA", "DEVICE_GEO", "DEVICE_GEO_A", - "MANFID", "FUNCID", "FUNCE", "SWIL", /* 20-23 */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 24-27 */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 28-2B */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 2C-2F */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 30-33 */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 34-37 */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 38-3B */ - "Reserved", "Reserved", "Reserved", "Reserved", /* 3C-3F */ - "VERS_2", "FORMAT", "GEOMETRY", "BYTEORDER", - "DATE", "BATTERY", "ORG" - }; -#define NAME_LEN(x) (sizeof x / sizeof(x[0])) + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; - if (type > 0 && type < NAME_LEN(tuple_name_s)) { - return tuple_name_s[type]; - } else if (0xff == type) { - return "END"; - } else { - return "Reserved"; - } + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + + switch (which) { + case PCI_IVAR_SUBVENDOR: + *result = cfg->subvendor; + break; + case PCI_IVAR_SUBDEVICE: + *result = cfg->subdevice; + break; + case PCI_IVAR_VENDOR: + *result = cfg->vendor; + break; + case PCI_IVAR_DEVICE: + *result = cfg->device; + break; + case PCI_IVAR_DEVID: + *result = (cfg->device << 16) | cfg->vendor; + break; + case PCI_IVAR_CLASS: + *result = cfg->baseclass; + break; + case PCI_IVAR_SUBCLASS: + *result = cfg->subclass; + break; + case PCI_IVAR_PROGIF: + *result = cfg->progif; + break; + case PCI_IVAR_REVID: + *result = cfg->revid; + break; + case PCI_IVAR_INTPIN: + *result = cfg->intpin; + break; + case PCI_IVAR_IRQ: + *result = cfg->intline; + break; + case PCI_IVAR_BUS: + *result = cfg->bus; + break; + case PCI_IVAR_SLOT: + *result = cfg->slot; + break; + case PCI_IVAR_FUNCTION: + *result = cfg->func; + break; + case PCI_IVAR_SECONDARYBUS: + *result = cfg->secondarybus; + break; + case PCI_IVAR_SUBORDINATEBUS: + *result = cfg->subordinatebus; + break; + default: + return ENOENT; + } + return 0; } + +static int +cardbus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + + switch (which) { + case PCI_IVAR_SUBVENDOR: + case PCI_IVAR_SUBDEVICE: + case PCI_IVAR_VENDOR: + case PCI_IVAR_DEVICE: + case PCI_IVAR_DEVID: + case PCI_IVAR_CLASS: + case PCI_IVAR_SUBCLASS: + case PCI_IVAR_PROGIF: + case PCI_IVAR_REVID: + case PCI_IVAR_INTPIN: + case PCI_IVAR_IRQ: + case PCI_IVAR_BUS: + case PCI_IVAR_SLOT: + case PCI_IVAR_FUNCTION: + return EINVAL; /* disallow for now */ + case PCI_IVAR_SECONDARYBUS: + cfg->secondarybus = value; + break; + case PCI_IVAR_SUBORDINATEBUS: + cfg->subordinatebus = value; + break; + default: + return ENOENT; + } + return 0; +} + +/************************************************************************/ +/* Compatibility with PCI bus (XXX: Do we need this?) */ +/************************************************************************/ + +static u_int32_t +cardbus_read_config_method(device_t dev, device_t child, int reg, int width) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + + return PCIB_READ_CONFIG(device_get_parent(dev), + cfg->bus, cfg->slot, cfg->func, + reg, width); +} + +static void +cardbus_write_config_method(device_t dev, device_t child, int reg, + u_int32_t val, int width) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + + PCIB_WRITE_CONFIG(device_get_parent(dev), + cfg->bus, cfg->slot, cfg->func, + reg, val, width); +} + +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_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, cardbus_print_child), + 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_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_set_resource, cardbus_set_resource_method), + DEVMETHOD(bus_get_resource, cardbus_get_resource_method), + DEVMETHOD(bus_delete_resource, cardbus_delete_resource_method), + + /* Card Interface */ + DEVMETHOD(card_attach_card, cardbus_attach_card), + DEVMETHOD(card_detach_card, cardbus_detach_card), + + /* Cardbus/PCI interface */ + DEVMETHOD(pci_read_config, cardbus_read_config_method), + DEVMETHOD(pci_write_config, cardbus_write_config_method), + + {0,0} +}; + +static driver_t cardbus_driver = { + "cardbus", + cardbus_methods, + 0 /* no softc */ +}; + +static devclass_t cardbus_devclass = {}; + +DRIVER_MODULE(cardbus, pccbb, cardbus_driver, cardbus_devclass, 0, 0); diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c new file mode 100644 index 000000000000..f6565ec296bd --- /dev/null +++ b/sys/dev/cardbus/cardbus_cis.c @@ -0,0 +1,477 @@ +/* + * 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$ + */ + +/* + * CIS Handling for the Cardbus Bus + */ + +#define CARDBUS_DEBUG + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "pccbb_if.h" + +#if defined CARDBUS_DEBUG +#define STATIC +#define DPRINTF(a) printf a +#define DEVPRINTF(x) device_printf x +#else +#define STATIC static +#define DPRINTF(a) +#define DEVPRINTF(x) +#endif + +#if !defined(lint) +static const char rcsid[] = + "$FreeBSD$"; +#endif + +struct tupleinfo; + +static int decode_tuples(device_t dev, device_t child, + u_int8_t *tuples, int len); +static int cardbus_read_exrom_cis(device_t dev, struct resource *res, + int cis, u_int8_t* tuple, int len); +static int cardbus_read_tuples_conf(device_t dev, device_t child, + u_int32_t cis_ptr, u_int8_t *tuples, + int len); +static int cardbus_read_tuples_mem(device_t dev, device_t child, int space, + u_int32_t cis_ptr, u_int8_t *tuples, + int len); +static int cardbus_read_tuples(device_t dev, device_t child, u_int8_t *tuples, + int len); + +#define DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME \ + (device_t dev, device_t child, int id, int len, \ + u_int8_t *buff, struct tupleinfo *info) +DECODE_PROTOTYPE(generic); +DECODE_PROTOTYPE(bar); +DECODE_PROTOTYPE(linktarget); +DECODE_PROTOTYPE(vers_1); +DECODE_PROTOTYPE(manfid); +DECODE_PROTOTYPE(funcid); +DECODE_PROTOTYPE(funce); +DECODE_PROTOTYPE(end); +DECODE_PROTOTYPE(unhandled); + +static struct tupleinfo { + u_int8_t id; + char* name; + int (*func)(device_t dev, device_t child, int id, int len, + u_int8_t *buff, struct tupleinfo *info); +} tupleinfo[] = { +#define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC } + MAKETUPLE(NULL, generic), + MAKETUPLE(DEVICE, generic), + MAKETUPLE(LONG_LINK_CB, unhandled), + MAKETUPLE(INDIRECT, unhandled), + MAKETUPLE(CONFIG_CB, generic), + MAKETUPLE(CFTABLE_ENTRY_CB, generic), + MAKETUPLE(LONGLINK_MFC, unhandled), + MAKETUPLE(BAR, bar), + MAKETUPLE(PWR_MGMNT, generic), + MAKETUPLE(EXTDEVICE, generic), + MAKETUPLE(CHECKSUM, generic), + MAKETUPLE(LONGLINK_A, unhandled), + MAKETUPLE(LONGLINK_C, unhandled), + MAKETUPLE(LINKTARGET, linktarget), + MAKETUPLE(NO_LINK, generic), + MAKETUPLE(VERS_1, vers_1), + MAKETUPLE(ALTSTR, generic), + MAKETUPLE(DEVICE_A, generic), + MAKETUPLE(JEDEC_C, generic), + MAKETUPLE(JEDEC_A, generic), + MAKETUPLE(CONFIG, generic), + MAKETUPLE(CFTABLE_ENTRY, generic), + MAKETUPLE(DEVICE_OC, generic), + MAKETUPLE(DEVICE_OA, generic), + MAKETUPLE(DEVICE_GEO, generic), + MAKETUPLE(DEVICE_GEO_A, generic), + MAKETUPLE(MANFID, manfid), + MAKETUPLE(FUNCID, funcid), + MAKETUPLE(FUNCE, funce), + MAKETUPLE(SWIL, generic), + MAKETUPLE(VERS_2, generic), + MAKETUPLE(FORMAT, generic), + MAKETUPLE(GEOMETRY, generic), + MAKETUPLE(BYTEORDER, generic), + MAKETUPLE(DATE, generic), + MAKETUPLE(BATTERY, generic), + MAKETUPLE(ORG, generic), + MAKETUPLE(END, end), +#undef MAKETUPLE +}; + +static char* funcnames[] = { + "Multi-Functioned", + "Memory", + "Serial Port", + "Parallel Port", + "Fixed Disk", + "Video Adaptor", + "Network Adaptor", + "AIMS", + "SCSI", + "Security" +}; + +DECODE_PROTOTYPE(generic) +{ +#ifdef CARDBUS_DEBUG + int i; + + if (info) + printf ("TUPLE: %s [%d]:", info->name, len); + else + printf ("TUPLE: Unknown(0x%02x) [%d]:", id, len); + + for (i = 0; i < len; i++) { + if (i % 0x10 == 0 && len > 0x10) + printf ("\n 0x%02x:", i); + printf (" %02x", buff[i]); + } + printf ("\n"); +#endif + return 0; +} + +DECODE_PROTOTYPE(linktarget) +{ + if (len != 3 || buff[0] != 'C' || buff[1] != 'I' || buff[2] != 'S') { + printf("Invalid data for CIS Link Target!\n"); + decode_tuple_generic(dev, child, id, len, buff, info); + return EINVAL; + } + return 0; +} + +DECODE_PROTOTYPE(vers_1) +{ + int i; + printf("Product version: %d.%d\n", buff[0], buff[1]); + printf("Product name: "); + for (i = 2; i < len; i++) { + if (buff[i] == '\0') + printf (" | "); + else if (buff[i] == 0xff) + break; + else + printf("%c", buff[i]); + } + printf("\n"); + return 0; +} + +DECODE_PROTOTYPE(funcid) +{ + int i; + int numnames = sizeof(funcnames)/sizeof(funcnames[0]); + + printf("Functions: "); + for(i = 0; i < len; i++) { + if (buff[i] < numnames) + printf ("%s", funcnames[buff[i]]); + else + printf ("Unknown(%d)", buff[i]); + if (i < len-1) printf(", "); + } + printf ("\n"); + return 0; +} + +DECODE_PROTOTYPE(manfid) +{ + int i; + printf ("Manufacturer ID: "); + for (i = 0; i < len; i++) + printf("%02x", buff[i]); + printf("\n"); + return 0; +} + +DECODE_PROTOTYPE(funce) +{ + int i; + printf ("Function Extension: "); + for (i = 0; i < len; i++) + printf("%02x", buff[i]); + printf("\n"); + return 0; +} + +DECODE_PROTOTYPE(bar) +{ + if (len != 6) { + printf ("*** ERROR *** BAR length not 6 (%d)\n", len); + return EINVAL; + } else { + int type; + int reg; + u_int32_t bar; + u_int32_t start, len; + struct resource *res; + + reg = *(u_int16_t*)buff; + len = *(u_int32_t*)(buff+2); + if (reg & TPL_BAR_REG_AS) { + type = SYS_RES_IOPORT; + } else { + type = SYS_RES_MEMORY; + } + bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; + if (bar < 0 || bar > 6) { + device_printf(dev, "Invalid BAR number: %02x(%02x)\n", + reg, bar); + return EINVAL; + } + bar = CARDBUS_BASE0_REG + bar * 4; + DEVPRINTF((dev, "Opening BAR: type=%s, bar=%02x, len=%04x\n", + (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len)); + res = bus_generic_alloc_resource(child, child, type, ®, 0, + ~0, len, rman_make_alignment_flags(len) | RF_ACTIVE); + if (res == NULL) { + device_printf(dev, "Cannot allocate BAR %02x\n", reg); + } else { + start = rman_get_start(res); + if (reg == CARDBUS_ROM_REG) start |= 1; + pci_write_config(child, reg, start, 4); + } + } + return 0; +} + +DECODE_PROTOTYPE(unhandled) +{ + printf ("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len); + return -1; +} + +DECODE_PROTOTYPE(end) +{ + return -1; +} + +static int decode_tuples(device_t dev, device_t child, + u_int8_t *tuples, int len) +{ + int ret = 0; + if (CISTPL_LINKTARGET != *tuples) { + device_printf(dev, "CIS does not start with link target\n"); + return EINVAL; + } + do { + int i; + int numtupleids = sizeof(tupleinfo)/sizeof(tupleinfo[0]); + for (i = 0; i < numtupleids; i++) { + if (tuples[0] == tupleinfo[i].id) { + ret = tupleinfo[i].func(dev, child, tuples[0], + tuples[1], tuples+2, + &tupleinfo[i]); + break; + } + } + if (i == numtupleids) + ret = decode_tuple_generic(dev, child, tuples[0], + tuples[1], tuples+2, NULL); + + len -= (tuples[1]+2); + tuples += tuples[1]+2; + } while (len > 0 && ret == 0); + + if (ret < 0) return 0; + else if (ret != 0) return ret; + else { + device_printf(dev, "CIS too long or END not encountered!\n"); + return EFBIG; + } +} + +static int +cardbus_read_exrom_cis(device_t dev, struct resource *res, int cis, + u_int8_t* tuple, int len) +{ +#define READROM(rom, type, offset) \ + (*((u_int ## type ##_t *)(((unsigned char*)rom) + offset))) + + u_int32_t addr = 0; /* offset of current rom image */ + int romnum = 0; + unsigned char *data; + u_int32_t imagesize; + unsigned char *image; + int imagenum; + + image = (unsigned char*)rman_get_virtual(res); + imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(cis); + do { + if (READROM(image, 16, CARDBUS_EXROM_SIGNATURE) != 0xaa55) { + device_printf (dev, "Bad header in rom %d: %04x\n", + romnum, *(u_int16_t*)(image + + CARDBUS_EXROM_SIGNATURE)); + return ENXIO; + } + data = image + READROM(image, 16, CARDBUS_EXROM_DATA_PTR); + imagesize = READROM(data, 16, CARDBUS_EXROM_DATA_IMAGE_LENGTH); + + if(imagesize == 0) + /* + * XXX some ROMs seem to have this as zero, + * can we assume this means 1 block? + */ + imagesize = 1; + imagesize <<= 9; + + if (imagenum == romnum) { + romnum = -1; + memcpy(tuple, image+CARDBUS_CIS_ADDR(cis), len); + return 0; + } + + addr += imagesize; + romnum++; + } while ((READROM(data, 8, CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0); + device_printf(dev, "Cannot read CIS: Not enough images of rom\n"); + return ENOENT; +#undef READROM +} + +static int +cardbus_read_tuples_conf(device_t dev, device_t child, u_int32_t cis_ptr, + u_int8_t *tuples, int len) +{ + int i, j; + + DEVPRINTF((dev, "reading CIS data from configuration space\n")); + for (i = cis_ptr, j = 0; i < len; i += 4) { + u_int32_t e = pci_read_config(child, i, 4); + tuples[j] = 0xff & e; + e >>= 8; + tuples[j + 1] = 0xff & e; + e >>= 8; + tuples[j + 2] = 0xff & e; + e >>= 8; + tuples[j + 3] = 0xff & e; + j += 4; + } + return 0; +} + +static int +cardbus_read_tuples_mem(device_t dev, device_t child, int space, + u_int32_t cis_ptr, u_int8_t *tuples, int len) +{ + struct resource *mem; + int rid; + int ret; + + if(space == CARDBUS_CIS_ASI_ROM) { + rid = CARDBUS_ROM_REG; + DEVPRINTF((dev, "reading CIS data from ROM\n")); + } else { + rid = CARDBUS_BASE0_REG + (space - 1) * 4; + DEVPRINTF((dev, "reading CIS data from BAR%d\n", space - 1)); + } + mem = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, 0, ~0, + 1, RF_ACTIVE); + if (mem == NULL) { + device_printf(dev, "Failed to get memory for CIS reading\n"); + return ENOMEM; + } + + if(space == CARDBUS_CIS_ASI_ROM) { + int s; + s = splhigh(); + ret = cardbus_read_exrom_cis(dev, mem, cis_ptr, tuples, len); + splx(s); + } else { + /* XXX byte order? */ + memcpy(tuples, (unsigned char*)rman_get_virtual(mem)+cis_ptr, + len); + ret = 0; + } + bus_release_resource(child, SYS_RES_MEMORY, rid, mem); + return ret; +} + +static int +cardbus_read_tuples(device_t dev, device_t child, u_int8_t *tuples, int len) +{ + u_int32_t cis_ptr = pci_read_config(child, CARDBUS_CIS_REG, 4); + int cardbus_space = cis_ptr & CARDBUS_CIS_ASIMASK; + int ret = 0; + cis_ptr = cis_ptr & CARDBUS_CIS_ADDRMASK; + + switch(cardbus_space) { + case CARDBUS_CIS_ASI_TUPLE: + ret = cardbus_read_tuples_conf(dev, child, cis_ptr, tuples, + len); + break; + case CARDBUS_CIS_ASI_BAR0: + case CARDBUS_CIS_ASI_BAR1: + case CARDBUS_CIS_ASI_BAR2: + case CARDBUS_CIS_ASI_BAR3: + case CARDBUS_CIS_ASI_BAR4: + case CARDBUS_CIS_ASI_BAR5: + case CARDBUS_CIS_ASI_ROM: + ret = cardbus_read_tuples_mem(dev, child, cardbus_space, + cis_ptr, tuples, len); + break; + default: + device_printf(dev, "Unable to read CIS: Unknown space: %d\n", + cardbus_space); + ret = EINVAL; + } + return ret; +} + +int +cardbus_do_cis(device_t dev, device_t child) +{ + u_int8_t tupledata[MAXTUPLESIZE]; + int ret; + + bzero(tupledata, MAXTUPLESIZE); + + ret = cardbus_read_tuples(dev, child, tupledata, MAXTUPLESIZE); + if (ret != 0) return ret; + return decode_tuples(dev, child, tupledata, MAXTUPLESIZE); +} + diff --git a/sys/dev/cardbus/cardbus_cis.h b/sys/dev/cardbus/cardbus_cis.h new file mode 100644 index 000000000000..3edacc4c7fc9 --- /dev/null +++ b/sys/dev/cardbus/cardbus_cis.h @@ -0,0 +1,99 @@ +/* + * 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$ + */ + +/* + * Cardbus CIS definitions + */ + +int cardbus_do_cis(device_t dev, device_t child); + +#define MAXTUPLESIZE 0x400 + +/* CIS TUPLES */ + +#define CISTPL_NULL 0x00 +#define CISTPL_DEVICE 0x01 +#define CISTPL_LONG_LINK_CB 0x02 +#define CISTPL_INDIRECT 0x03 +#define CISTPL_CONFIG_CB 0x04 +#define CISTPL_CFTABLE_ENTRY_CB 0x05 +#define CISTPL_LONGLINK_MFC 0x06 +#define CISTPL_BAR 0x07 +#define CISTPL_PWR_MGMNT 0x08 +#define CISTPL_EXTDEVICE 0x09 +#define CISTPL_CHECKSUM 0x10 +#define CISTPL_LONGLINK_A 0x11 +#define CISTPL_LONGLINK_C 0x12 +#define CISTPL_LINKTARGET 0x13 +#define CISTPL_NO_LINK 0x14 +#define CISTPL_VERS_1 0x15 +#define CISTPL_ALTSTR 0x16 +#define CISTPL_DEVICE_A 0x17 +#define CISTPL_JEDEC_C 0x18 +#define CISTPL_JEDEC_A 0x19 +#define CISTPL_CONFIG 0x1A +#define CISTPL_CFTABLE_ENTRY 0x1B +#define CISTPL_DEVICE_OC 0x1C +#define CISTPL_DEVICE_OA 0x1D +#define CISTPL_DEVICE_GEO 0x1E +#define CISTPL_DEVICE_GEO_A 0x1F +#define CISTPL_MANFID 0x20 +#define CISTPL_FUNCID 0x21 +#define CISTPL_FUNCE 0x22 +#define CISTPL_SWIL 0x23 +#define CISTPL_VERS_2 0x40 +#define CISTPL_FORMAT 0x41 +#define CISTPL_GEOMETRY 0x42 +#define CISTPL_BYTEORDER 0x43 +#define CISTPL_DATE 0x44 +#define CISTPL_BATTERY 0x45 +#define CISTPL_ORG 0x46 +#define CISTPL_END 0xFF + +/* BAR */ +#define TPL_BAR_REG_ASI_MASK 0x07 +#define TPL_BAR_REG_AS 0x08 + +/* CISTPL_FUNC */ +#define TPL_FUNC_MF 0 /* multi function tuple */ +#define TPL_FUNC_MEM 1 /* memory */ +#define TPL_FUNC_SERIAL 2 /* serial, including modem and fax */ +#define TPL_FUNC_PARALLEL 3 /* parallel, including printer and SCSI */ +#define TPL_FUNC_DISK 4 /* Disk */ +#define TPL_FUNC_VIDEO 5 /* Video Adaptor */ +#define TPL_FUNC_LAN 6 /* LAN Adaptor */ +#define TPL_FUNC_AIMS 7 /* Auto Inclement Mass Strages */ + +/* TPL_FUNC_LAN */ +#define TPL_FUNCE_LAN_TECH 1 /* technology */ +#define TPL_FUNCE_LAN_SPEED 2 /* speed */ +#define TPL_FUNCE_LAN_MEDIA 2 /* which media do you use? */ +#define TPL_FUNCE_LAN_NID 4 /* node id (address) */ +#define TPL_FUNCE_LAN_CONN 5 /* connector type (shape) */ diff --git a/sys/dev/cardbus/cardbusreg.h b/sys/dev/cardbus/cardbusreg.h index 56e2e56ec67d..df5bb18fe68f 100644 --- a/sys/dev/cardbus/cardbusreg.h +++ b/sys/dev/cardbus/cardbusreg.h @@ -1,105 +1,87 @@ /* - * Copyright (c) 1998 HAYAKAWA Koichi. All rights reserved. + * 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. + * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the author. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 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. * - * 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. + * $FreeBSD$ */ -/* $FreeBSD$ */ -typedef u_int32_t cardbusreg_t; -typedef int cardbus_intr_line_t; - -typedef void *cardbus_chipset_tag_t; -typedef int cardbus_intr_handle_t; - -typedef u_int16_t cardbus_vendor_id_t; -typedef u_int16_t cardbus_product_id_t; - -#define CARDBUS_ID_REG 0x00 - -# define CARDBUS_VENDOR_SHIFT 0 -# define CARDBUS_VENDOR_MASK 0xffff -# define CARDBUS_VENDOR(id) \ - (((id) >> CARDBUS_VENDOR_SHIFT) & CARDBUS_VENDOR_MASK) - -# define CARDBUS_PRODUCT_SHIFT 16 -# define CARDBUS_PRODUCT_MASK 0xffff -# define CARDBUS_PRODUCT(id) \ - (((id) >> CARDBUS_PRODUCT_SHIFT) & CARDBUS_PRODUCT_MASK) +/* + * Register definitions for the Cardbus Bus + */ -#define CARDBUS_COMMAND_STATUS_REG 0x04 +/* Cardbus bus constants */ +#define CARDBUS_SLOTMAX 0 +#define CARDBUS_FUNCMAX 7 -# define CARDBUS_COMMAND_IO_ENABLE 0x00000001 -# define CARDBUS_COMMAND_MEM_ENABLE 0x00000002 -# define CARDBUS_COMMAND_MASTER_ENABLE 0x00000004 +/* Cardbus configuration header registers */ +#define CARDBUS_BASE0_REG 0x10 +#define CARDBUS_BASE1_REG 0x14 +#define CARDBUS_BASE2_REG 0x18 +#define CARDBUS_BASE3_REG 0x1C +#define CARDBUS_BASE4_REG 0x20 +#define CARDBUS_BASE5_REG 0x24 +#define CARDBUS_CIS_REG 0x28 +# define CARDBUS_CIS_ASIMASK 0x07 +# define CARDBUS_CIS_ADDRMASK 0x0ffffff8 +# define CARDBUS_CIS_ASI_TUPLE 0x00 +# define CARDBUS_CIS_ASI_BAR0 0x01 +# define CARDBUS_CIS_ASI_BAR1 0x02 +# define CARDBUS_CIS_ASI_BAR2 0x03 +# define CARDBUS_CIS_ASI_BAR3 0x04 +# define CARDBUS_CIS_ASI_BAR4 0x05 +# define CARDBUS_CIS_ASI_BAR5 0x06 +# define CARDBUS_CIS_ASI_ROM 0x07 +#define CARDBUS_ROM_REG 0x30 +/* EXROM offsets for reading CIS */ +#define CARDBUS_EXROM_SIGNATURE 0x00 +#define CARDBUS_EXROM_DATA_PTR 0x18 -#define CARDBUS_CLASS_REG 0x08 +#define CARDBUS_EXROM_DATA_SIGNATURE 0x00 /* Signature ("PCIR") */ +#define CARDBUS_EXROM_DATA_VENDOR_ID 0x04 /* Vendor Identification */ +#define CARDBUS_EXROM_DATA_DEVICE_ID 0x06 /* Device Identification */ +#define CARDBUS_EXROM_DATA_LENGTH 0x0a /* PCI Data Structure Length */ +#define CARDBUS_EXROM_DATA_REV 0x0c /* PCI Data Structure Revision */ +#define CARDBUS_EXROM_DATA_CLASS_CODE 0x0d /* Class Code */ +#define CARDBUS_EXROM_DATA_IMAGE_LENGTH 0x10 /* Image Length */ +#define CARDBUS_EXROM_DATA_DATA_REV 0x12 /* Revision Level of Code/Data */ +#define CARDBUS_EXROM_DATA_CODE_TYPE 0x14 /* Code Type */ +#define CARDBUS_EXROM_DATA_INDICATOR 0x15 /* Indicator */ -/* BIST, Header Type, Latency Timer, Cache Line Size */ -#define CARDBUS_BHLC_REG 0x0c - -#define CARDBUS_BIST_SHIFT 24 -#define CARDBUS_BIST_MASK 0xff -#define CARDBUS_BIST(bhlcr) \ - (((bhlcr) >> CARDBUS_BIST_SHIFT) & CARDBUS_BIST_MASK) - -#define CARDBUS_HDRTYPE_SHIFT 16 -#define CARDBUS_HDRTYPE_MASK 0xff -#define CARDBUS_HDRTYPE(bhlcr) \ - (((bhlcr) >> CARDBUS_HDRTYPE_SHIFT) & CARDBUS_HDRTYPE_MASK) - -#define CARDBUS_HDRTYPE_TYPE(bhlcr) \ - (CARDBUS_HDRTYPE(bhlcr) & 0x7f) -#define CARDBUS_HDRTYPE_MULTIFN(bhlcr) \ - ((CARDBUS_HDRTYPE(bhlcr) & 0x80) != 0) - -#define CARDBUS_LATTIMER_SHIFT 8 -#define CARDBUS_LATTIMER_MASK 0xff -#define CARDBUS_LATTIMER(bhlcr) \ - (((bhlcr) >> CARDBUS_LATTIMER_SHIFT) & CARDBUS_LATTIMER_MASK) - -#define CARDBUS_CACHELINE_SHIFT 0 -#define CARDBUS_CACHELINE_MASK 0xff -#define CARDBUS_CACHELINE(bhlcr) \ - (((bhlcr) >> CARDBUS_CACHELINE_SHIFT) & CARDBUS_CACHELINE_MASK) - - -/* Base Resisters */ -#define CARDBUS_BASE0_REG 0x10 -#define CARDBUS_BASE1_REG 0x14 -#define CARDBUS_BASE2_REG 0x18 -#define CARDBUS_BASE3_REG 0x1C -#define CARDBUS_BASE4_REG 0x20 -#define CARDBUS_BASE5_REG 0x24 -#define CARDBUS_CIS_REG 0x28 -# define CARDBUS_CIS_ASIMASK 0x07 -# define CARDBUS_CIS_ADDRMASK 0x0ffffff8 - -#define CARDBUS_INTERRUPT_REG 0x3c +/* useful macros */ +#define CARDBUS_CIS_ADDR(x) \ + (CARDBUS_CIS_ADDRMASK & (x)) +#define CARDBUS_CIS_ASI_BAR(x) \ + (((CARDBUS_CIS_ASIMASK & (x))-1)*4+0x10) +#define CARDBUS_CIS_ASI_ROM_IMAGE(x) \ + (((x) >> 28) & 0xf) +#define CARDBUS_MAPREG_MEM_ADDR_MASK 0x0ffffff0 +#define CARDBUS_MAPREG_MEM_ADDR(mr) \ + ((mr) & CARDBUS_MAPREG_MEM_ADDR_MASK) +#define CARDBUS_MAPREG_MEM_SIZE(mr) \ + (CARDBUS_MAPREG_MEM_ADDR(mr) & -CARDBUS_MAPREG_MEM_ADDR(mr)) diff --git a/sys/dev/cardbus/cardbusvar.h b/sys/dev/cardbus/cardbusvar.h index 2f911411c477..a94cd99cc21b 100644 --- a/sys/dev/cardbus/cardbusvar.h +++ b/sys/dev/cardbus/cardbusvar.h @@ -1,180 +1,39 @@ -/* $Id: cardbusvar.h,v 1.1.2.1 1999/02/16 16:46:08 haya Exp $ */ - /* - * Copyright (c) 1998 HAYAKAWA Koichi. All rights reserved. + * 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. + * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the author. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 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. * - * 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. + * $FreeBSD$ */ -/* $FreeBSD$ */ -#if !defined SYS_DEV_PCCARD_CARDBUSVAR_H -#define SYS_DEV_PCCARD_CARDBUSVAR_H -#include /* XXX */ -typedef pcitag_t cardbustag_t; /* XXX */ +/* + * Structure definitions for the Cardbus Bus driver + */ -typedef struct cardbus_functions { - int (*cardbus_ctrl) __P((cardbus_chipset_tag_t, int)); - int (*cardbus_power) __P((cardbus_chipset_tag_t, int)); - int (*cardbus_mem_open) __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)); - int (*cardbus_mem_close) __P((cardbus_chipset_tag_t, int)); - int (*cardbus_io_open) __P((cardbus_chipset_tag_t, int, u_int32_t, u_int32_t)); - int (*cardbus_io_close) __P((cardbus_chipset_tag_t, int)); - void *(*cardbus_intr_establish) __P((cardbus_chipset_tag_t, int irq, int level, int (*ih)(void *), void *sc)); - void (*cardbus_intr_disestablish) __P((cardbus_chipset_tag_t ct, void *ih)); - cardbustag_t (*cardbus_make_tag) __P((cardbus_chipset_tag_t, int, int, int)); - void (*cardbus_free_tag) __P((cardbus_chipset_tag_t, cardbustag_t)); - cardbusreg_t (*cardbus_conf_read) __P((cardbus_chipset_tag_t, cardbustag_t, int)); - void (*cardbus_conf_write) __P((cardbus_chipset_tag_t, cardbustag_t, int, cardbusreg_t)); -} cardbus_function_t, *cardbus_function_tag_t; - -/********************************************************************** -* struct cbslot_attach_args is the attach argument for cardbus slot. -**********************************************************************/ -struct cbslot_attach_args { - char *cba_busname; - bus_space_tag_t cba_iot; /* cardbus i/o space tag */ - bus_space_tag_t cba_memt; /* cardbus mem space tag */ - bus_dma_tag_t cba_dmat; /* DMA tag */ - - int cba_bus; /* cardbus bus number */ - int cba_function; /* slot number on this Host Bus Adaptor */ - - cardbus_chipset_tag_t cba_cc; /* cardbus chipset */ - cardbus_function_tag_t cba_cf; /* cardbus functions */ - int cba_intrline; /* interrupt line */ +struct cardbus_devinfo { + struct resource_list resources; + pcicfgregs cfg; + struct pci_conf conf; }; - -#define cbslotcf_slot cf_loc[0] -#define CBSLOT_UNK_SLOT -1 - -/********************************************************************** -* struct cardslot_if is the interface for cardslot. -**********************************************************************/ -struct cardslot_if { - struct device *(*if_card_attach) __P((struct cardbus_softc*)); -}; -/********************************************************************** -* struct cardbus_softc is the softc for cardbus card. -**********************************************************************/ -struct cardbus_softc { - struct device sc_dev; /* fundamental device structure */ - - int sc_bus; /* cardbus bus number */ - int sc_device; /* cardbus device number */ - int sc_intrline; /* CardBus intrline */ - - bus_space_tag_t sc_iot; /* CardBus I/O space tag */ - bus_space_tag_t sc_memt; /* CardBus MEM space tag */ - bus_dma_tag_t sc_dmat; /* DMA tag */ - cardbus_chipset_tag_t sc_cc; /* CardBus chipset */ - cardbus_function_tag_t sc_cf; /* CardBus function */ - - int sc_volt; /* applied Vcc voltage */ -#define PCCARD_33V 0x02 -#define PCCARD_XXV 0x04 -#define PCCARD_YYV 0x08 - struct cardslot_if sc_if; -}; -void -cardslot_if_setup __P((struct cardbus_softc*)); - -/********************************************************************** -* struct cbslot_attach_args is the attach argument for cardbus card. -**********************************************************************/ -struct cardbus_attach_args { - int ca_unit; - cardbus_chipset_tag_t ca_cc; - cardbus_function_tag_t ca_cf; - - bus_space_tag_t ca_iot; /* CardBus I/O space tag */ - bus_space_tag_t ca_memt; /* CardBus MEM space tag */ - bus_dma_tag_t ca_dmat; /* DMA tag */ - - u_int ca_device; - u_int ca_function; - cardbustag_t ca_tag; - cardbusreg_t ca_id; - cardbusreg_t ca_class; - - /* interrupt information */ - cardbus_intr_line_t ca_intrline; -}; - - -#define CARDBUS_ENABLE 1 /* enable the channel */ -#define CARDBUS_DISABLE 2 /* disable the channel */ -#define CARDBUS_RESET 4 -#define CARDBUS_CD 7 -# define CARDBUS_NOCARD 0 -# define CARDBUS_5V_CARD 0x01 /* XXX: It must not exist */ -# define CARDBUS_3V_CARD 0x02 -# define CARDBUS_XV_CARD 0x04 -# define CARDBUS_YV_CARD 0x08 -#define CARDBUS_IO_ENABLE 100 -#define CARDBUS_IO_DISABLE 101 -#define CARDBUS_MEM_ENABLE 102 -#define CARDBUS_MEM_DISABLE 103 -#define CARDBUS_BM_ENABLE 104 /* bus master */ -#define CARDBUS_BM_DISABLE 105 - -#define CARDBUS_VCC_UC 0x0000 -#define CARDBUS_VCC_3V 0x0001 -#define CARDBUS_VCC_XV 0x0002 -#define CARDBUS_VCC_YV 0x0003 -#define CARDBUS_VCC_0V 0x0004 -#define CARDBUS_VCC_5V 0x0005 /* ??? */ -#define CARDBUS_VCCMASK 0x000f -#define CARDBUS_VPP_UC 0x0000 -#define CARDBUS_VPP_VCC 0x0010 -#define CARDBUS_VPP_12V 0x0030 -#define CARDBUS_VPP_0V 0x0040 -#define CARDBUS_VPPMASK 0x00f0 - - -/********************************************************************** -* Locators devies that attach to 'cardbus', as specified to config. -**********************************************************************/ -#include "locators.h" - -#define cardbuscf_dev cf_loc[CARDBUSCF_DEV] -#define CARDBUS_UNK_DEV CARDBUSCF_DEV_DEFAULT - -#define cardbuscf_function cf_loc[CARDBUSCF_FUNC] -#define CARDBUS_UNK_FUNCTION CARDBUSCF_FUNC_DEFAULT - -struct device *cardbus_attach_card __P((struct cardbus_softc *)); -void *cardbus_intr_establish __P((cardbus_chipset_tag_t, cardbus_function_tag_t, cardbus_intr_handle_t irq, int level, int (*func) (void *), void *arg)); -void cardbus_intr_disestablish __P((cardbus_chipset_tag_t, cardbus_function_tag_t, void *handler)); - -#define cardbus_conf_read(cc, cf, tag, offs) ((cf)->cardbus_conf_read)((cc), (tag), (offs)) -#define cardbus_conf_write(cc, cf, tag, offs, val) ((cf)->cardbus_conf_write)((cc), (tag), (offs), (val)) -#define cardbus_make_tag(cc, cf, bus, device, function) ((cf)->cardbus_make_tag)((cc), (bus), (device), (function)) -#define cardbus_free_tag(cc, cf, tag) ((cf)->cardbus_free_tag)((cc), (tag)) - -#endif /* SYS_DEV_PCCARD_CARDBUSVAR_H */ - diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c new file mode 100644 index 000000000000..8f9e7ed59012 --- /dev/null +++ b/sys/dev/pccbb/pccbb.c @@ -0,0 +1,1713 @@ +/* + * 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$ + */ + +/* + * Driver for PCI to Cardbus Bridge chips + * + * References: + * TI Datasheets: + * http://www-s.ti.com/cgi-bin/sc/generic2.cgi?family=PCI+CARDBUS+CONTROLLERS + * Much of the 16-bit PC Card compatibility code stolen from dev/pcic/i82365.c + * + * Written by Jonathan Chen + * The author would like to acknowledge: + * * HAYAKAWA Koichi: Author of the NetBSD code for the same thing + * * Warner Losh: Newbus/newcard guru and author of the pccard side of things + * * YAMAMOTO Shigeru: Author of another FreeBSD cardbus driver + * * David Cross: Author of the initial ugly hack for a specific cardbus card + */ + +#define CBB_DEBUG + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "power_if.h" +#include "card_if.h" +#include "pccbb_if.h" +#include "pcib_if.h" + +#if defined CBB_DEBUG +#define DPRINTF(x) printf x +#define DEVPRINTF(x) device_printf x +#else +#define DPRINTF(x) +#define DEVPRINTF(x) +#endif + +#define PCI_MASK_CONFIG(DEV,REG,MASK,SIZE) \ + pci_write_config(DEV, REG, pci_read_config(DEV, REG, SIZE) MASK, SIZE) +#define PCI_MASK2_CONFIG(DEV,REG,MASK1,MASK2,SIZE) \ + pci_write_config(DEV, REG, ( \ + pci_read_config(DEV, REG, SIZE) MASK1) MASK2, SIZE) + +#define PCIC_READ(SC,REG) \ + (((u_int8_t*)((SC)->sc_socketreg))[0x800+(REG)]) +#define PCIC_WRITE(SC,REG,val) \ + (((u_int8_t*)((SC)->sc_socketreg))[0x800+(REG)]) = (val) +#define PCIC_MASK(SC,REG,MASK) \ + PCIC_WRITE(SC,REG,PCIC_READ(SC,REG) MASK) +#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; + STAILQ_ENTRY(pccbb_sclist) entries; +}; + +static STAILQ_HEAD(, pccbb_sclist) softcs; +static int softcs_init = 0; + + +struct yenta_chipinfo { + u_int32_t yc_id; + const char *yc_name; + int yc_chiptype; + int yc_flags; +} yc_chipsets[] = { + /* Texas Instruments chips */ + {PCI_DEVICE_ID_PCIC_TI1130, "TI1130 PCI-CardBus Bridge", CB_TI113X, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1131, "TI1131 PCI-CardBus Bridge", CB_TI113X, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + + {PCI_DEVICE_ID_PCIC_TI1211, "TI1211 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1220, "TI1220 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1221, "TI1221 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1225, "TI1225 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1250, "TI1250 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1251, "TI1251 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1251B,"TI1251B PCI-CardBus Bridge",CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1410, "TI1410 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1420, "TI1420 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1450, "TI1450 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_TI1451, "TI1451 PCI-CardBus Bridge", CB_TI12XX, + PCCBB_PCIC_IO_RELOC | PCCBB_PCIC_MEM_32}, + + /* Ricoh chips */ + {PCI_DEVICE_ID_RICOH_RL5C465, "RF5C465 PCI-CardBus Bridge", + CB_RF5C46X, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_RICOH_RL5C466, "RF5C466 PCI-CardBus Bridge", + CB_RF5C46X, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_RICOH_RL5C475, "RF5C475 PCI-CardBus Bridge", + CB_RF5C47X, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_RICOH_RL5C476, "RF5C476 PCI-CardBus Bridge", + CB_RF5C47X, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_RICOH_RL5C478, "RF5C478 PCI-CardBus Bridge", + CB_RF5C47X, PCCBB_PCIC_MEM_32}, + + /* Toshiba products */ + {PCI_DEVICE_ID_TOSHIBA_TOPIC95, "ToPIC95 PCI-CardBus Bridge", + CB_TOPIC95, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_TOSHIBA_TOPIC95B, "ToPIC95B PCI-CardBus Bridge", + CB_TOPIC95B, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_TOSHIBA_TOPIC97, "ToPIC97 PCI-CardBus Bridge", + CB_TOPIC97, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_TOSHIBA_TOPIC100, "ToPIC100 PCI-CardBus Bridge", + CB_TOPIC97, PCCBB_PCIC_MEM_32}, + + /* Cirrus Logic */ + {PCI_DEVICE_ID_PCIC_CLPD6832, "CLPD6832 PCI-CardBus Bridge", + CB_CIRRUS, PCCBB_PCIC_MEM_32}, + {PCI_DEVICE_ID_PCIC_CLPD6833, "CLPD6833 PCI-CardBus Bridge", + CB_CIRRUS, PCCBB_PCIC_MEM_32}, + + /* sentinel */ + {0 /* null id */, "unknown", + CB_UNKNOWN, 0}, +}; + + +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 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_power(device_t dev, int volts); +static int pccbb_cardbus_detect_card(device_t dev); +static int pccbb_cardbus_reset(device_t dev); +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, + u_int32_t start, u_int32_t end); +static void pccbb_cardbus_auto_open(struct pccbb_softc *sc, int type); +static int pccbb_cardbus_activate_resource(device_t self, device_t child, + int type, int rid, + struct resource *r); +static int pccbb_cardbus_deactivate_resource(device_t self, device_t child, + int type, int rid, + struct resource *r); +static struct resource* pccbb_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); +static int pccbb_cardbus_release_resource(device_t self, device_t child, + int type,int rid, + struct resource *r); +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, + struct resource *r, bus_addr_t card_addr, + int *win); +static void pccbb_pcic_mem_unmap(struct pccbb_softc *sc, int window); +static void pccbb_pcic_do_io_map(struct pccbb_softc *sc, int win); +static int pccbb_pcic_io_map(struct pccbb_softc *sc, int width, + struct resource *r, bus_addr_t card_addr, + int *win); +static void pccbb_pcic_io_unmap(struct pccbb_softc *sc, int window); +static int pccbb_pcic_activate_resource(device_t self, device_t child, + int type, int rid, struct resource *r); +static int pccbb_pcic_deactivate_resource(device_t self, device_t child, + int type,int rid, struct resource *r); +static struct resource* pccbb_pcic_alloc_resource(device_t self,device_t child, + int type, int* rid, u_long start, + u_long end, u_long count, u_int flags); +static int pccbb_pcic_release_resource(device_t self, device_t child, int type, + int rid, struct resource *res); +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_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, + int rid, struct resource *r); +static struct resource* pccbb_alloc_resource(device_t self, device_t child, + int type, int* rid, u_long start, + u_long end, u_long count, + u_int flags); +static int pccbb_release_resource(device_t self, device_t child, + int type, int rid, struct resource *r); + + +/************************************************************************/ +/* Probe/Attach */ +/************************************************************************/ + +static int +cb_chipset(u_int32_t pci_id, const char** namep, int* flagp) +{ + int loopend = sizeof(yc_chipsets)/sizeof(yc_chipsets[0]); + struct yenta_chipinfo *ycp, *ycend; + ycend = yc_chipsets + loopend; + + for (ycp = yc_chipsets; ycp < ycend && pci_id != ycp->yc_id; ++ycp); + if (ycp == ycend) { + /* not found */ + ycp = yc_chipsets + loopend - 1; /* to point the sentinel */ + } + if (namep != NULL) { + *namep = ycp->yc_name; + } + if (flagp != NULL) { + *flagp = ycp->yc_flags; + } + return ycp->yc_chiptype; +} + +static int +pccbb_probe(device_t dev) +{ + const char *name; + + if (cb_chipset(pci_get_devid(dev), &name, NULL) == CB_UNKNOWN) + return ENXIO; + device_set_desc(dev, name); + return 0; +} + +static void +pccbb_chipinit(struct pccbb_softc* sc) +{ + /* Set CardBus latency timer */ + if (pci_read_config(sc->sc_dev, PCIR_SECLAT_1, 1) < 0x20) + pci_write_config(sc->sc_dev, PCIR_SECLAT_1, 0x20, 1); + + /* Set PCI latency timer */ + if (pci_read_config(sc->sc_dev, PCIR_LATTIMER, 1) < 0x20) + pci_write_config(sc->sc_dev, PCIR_LATTIMER, 0x20, 1); + + /* Enable memory access */ + PCI_MASK_CONFIG(sc->sc_dev, PCIR_COMMAND, + | PCIM_CMD_MEMEN + | PCIM_CMD_PORTEN + | PCIM_CMD_BUSMASTEREN, 2); + + /* disable Legacy IO */ + + switch (sc->sc_chipset) { + case CB_RF5C46X: + PCI_MASK_CONFIG(sc->sc_dev, PCCBBR_BRIDGECTRL, + & ~(PCCBBM_BRIDGECTRL_RL_3E0_EN| + PCCBBM_BRIDGECTRL_RL_3E2_EN), 2); + break; + default: + pci_write_config(sc->sc_dev, PCCBBR_LEGACY, 0x0, 4); + break; + } + + /* Use PCI interrupt for interrupt routing */ + PCI_MASK2_CONFIG(sc->sc_dev, PCCBBR_BRIDGECTRL, + & ~(PCCBBM_BRIDGECTRL_MASTER_ABORT | + PCCBBM_BRIDGECTRL_INTR_IREQ_EN), + | PCCBBM_BRIDGECTRL_WRITE_POST_EN, + 2); + + switch (sc->sc_chipset) { + case CB_TI113X: + PCI_MASK2_CONFIG(sc->sc_dev, PCCBBR_CBCTRL, + & ~PCCBBM_CBCTRL_113X_PCI_INTR, + | PCCBBM_CBCTRL_113X_PCI_CSC + | PCCBBM_CBCTRL_113X_PCI_IRQ_EN, 1); + PCI_MASK_CONFIG(sc->sc_dev, PCCBBR_DEVCTRL, + & ~(PCCBBM_DEVCTRL_INT_SERIAL| + PCCBBM_DEVCTRL_INT_PCI), 1); + PCIC_WRITE(sc, PCIC_INTR, PCIC_INTR_ENABLE); + PCIC_WRITE(sc, PCIC_CSC_INTR, 0); + break; + case CB_TI12XX: + PCIC_WRITE(sc, PCIC_INTR, PCIC_INTR_ENABLE); + PCIC_WRITE(sc, PCIC_CSC_INTR, 0); + break; + case CB_TOPIC95B: + PCI_MASK_CONFIG(sc->sc_dev, PCCBBR_TOPIC_SOCKETCTRL, + | PCCBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL, 4); + PCI_MASK2_CONFIG(sc->sc_dev, PCCBBR_TOPIC_SLOTCTRL, + | PCCBBM_TOPIC_SLOTCTRL_SLOTON + | PCCBBM_TOPIC_SLOTCTRL_SLOTEN + | PCCBBM_TOPIC_SLOTCTRL_ID_LOCK + | PCCBBM_TOPIC_SLOTCTRL_CARDBUS, + & ~PCCBBM_TOPIC_SLOTCTRL_SWDETECT, 4); + break; + } + + /* close all memory and io windows */ + pci_write_config(sc->sc_dev, PCCBBR_MEMBASE0, 0xffffffff, 4); + pci_write_config(sc->sc_dev, PCCBBR_MEMLIMIT0, 0, 4); + pci_write_config(sc->sc_dev, PCCBBR_MEMBASE1, 0xffffffff, 4); + pci_write_config(sc->sc_dev, PCCBBR_MEMLIMIT1, 0, 4); + pci_write_config(sc->sc_dev, PCCBBR_IOBASE0, 0xffffffff, 4); + pci_write_config(sc->sc_dev, PCCBBR_IOLIMIT0, 0, 4); + pci_write_config(sc->sc_dev, PCCBBR_IOBASE1, 0xffffffff, 4); + pci_write_config(sc->sc_dev, PCCBBR_IOLIMIT1, 0, 4); +} + +static int +pccbb_attach(device_t dev) +{ + struct pccbb_softc *sc = (struct pccbb_softc *)device_get_softc(dev); + int flags; + int rid; + u_int32_t tmp; + + if (!softcs_init) { + softcs_init = 1; + STAILQ_INIT(&softcs); + } + sc->sc_chipset = cb_chipset(pci_get_devid(dev), NULL, &flags); + sc->sc_dev = dev; + sc->sc_flags = 0; + sc->sc_cbdev = NULL; + sc->sc_pccarddev = NULL; + sc->memalloc = 0; + sc->ioalloc = 0; + SLIST_INIT(&sc->rl); + + /* Ths PCI bus should have given me memory... right? */ + rid=PCCBBR_SOCKBASE; + sc->sc_base_res=bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0,~0,1, RF_ACTIVE); + if (!sc->sc_base_res){ + /* + * XXX EVILE HACK BAD THING! XXX + * Some BIOSes doesn't assign a memory space properly. + * So we try to manually put one in... + */ + u_int32_t sockbase; + + sockbase = pci_read_config(dev, rid, 4); + if (sockbase < 0x100000 || sockbase >= 0xfffffff0) { + pci_write_config(dev, rid, 0xffffffff, 4); + sockbase = pci_read_config(dev, rid, 4); + sockbase = (sockbase & 0xfffffff0) & + -(sockbase & 0xfffffff0); + sc->sc_base_res = bus_generic_alloc_resource( + device_get_parent(dev), dev, SYS_RES_MEMORY, + &rid, CARDBUS_SYS_RES_MEMORY_START, + CARDBUS_SYS_RES_MEMORY_END, sockbase, + RF_ACTIVE|rman_make_alignment_flags(sockbase)); + if (!sc->sc_base_res){ + device_printf(dev, + "Could not grab register memory\n"); + return ENOMEM; + } + pci_write_config(dev, PCCBBR_SOCKBASE, + rman_get_start(sc->sc_base_res), 4); + DEVPRINTF((dev, "PCI Memory allocated: %08lx\n", + rman_get_start(sc->sc_base_res))); + } else { + device_printf(dev, "Could not map register memory\n"); + return ENOMEM; + } + } + + sc->sc_socketreg = + (struct pccbb_socketreg *)rman_get_virtual(sc->sc_base_res); + + pccbb_chipinit(sc); + + /* CSC Interrupt: Card detect interrupt on */ + sc->sc_socketreg->socket_mask |= PCCBB_SOCKET_MASK_CD; + + /* reset interrupt */ + tmp = sc->sc_socketreg->socket_event; + sc->sc_socketreg->socket_event = tmp; + + /* Map and establish the interrupt. */ + rid=0; + sc->sc_irq_res=bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + printf("pccbb: Unable to map IRQ...\n"); + return ENOMEM; + } + + if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO, pccbb_intr, sc, + &(sc->sc_intrhand))) { + device_printf(dev, "couldn't establish interrupt"); + 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); + 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")); + else if (device_probe_and_attach(sc->sc_cbdev) != 0) { + DEVPRINTF((dev, "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")); + else if (device_probe_and_attach(sc->sc_pccarddev) != 0) { + DEVPRINTF((dev, "Cannot attach pccard bus!\n")); + sc->sc_pccarddev = NULL; + } + + if (sc->sc_cbdev == NULL && sc->sc_pccarddev == NULL) { + device_printf(dev, "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); + return ENOMEM; + } + + { + struct pccbb_sclist *sclist; + sclist = malloc(sizeof(struct pccbb_sclist), M_DEVBUF, + M_WAITOK); + sclist->sc = sc; + STAILQ_INSERT_TAIL(&softcs, sclist, entries); + } + return 0; +} + +/************************************************************************/ +/* Kthreads */ +/************************************************************************/ + +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; + else { + splx (s); + tsleep (sc, PWAIT, "pccbbev", 0); + /* + * Delay some time, make sure the user is done with + * whatever he is doing. + */ + DELAY(1000*1000); + s = splhigh(); + } + + 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)) + pccbb_insert(sc); + else + device_printf(sc->sc_dev, + "duplicate card insert\n"); + } else { + if (!(sc->sc_flags & PCCBB_CARDATTACHED)) + DEVPRINTF((sc->sc_dev, + "removal of nonexistant card!\n")); + else + pccbb_removal(sc); + } + sc->sc_flags &= ~PCCBB_CARDSTATUS_BUSY; + splx (s); + } + /* NOTREACHED */ + kthread_exit(0); +} + +static void +pccbb_create_event_thread (struct pccbb_softc *sc) +{ + if (kthread_create(pccbb_event_thread, sc, &sc->event_thread, + 0, "%s%d", device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev))) { + device_printf (sc->sc_dev, "unable to create event thread.\n"); + panic ("pccbb_create_event_thread"); + } +} + +static void +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); + } +} + +/************************************************************************/ +/* Insert/removal */ +/************************************************************************/ + +static void +pccbb_insert (struct pccbb_softc *sc) +{ + u_int32_t sockevent, sockstate; + int timeout = 30; + + do { + sockevent = sc->sc_socketreg->socket_event; + sockstate = sc->sc_socketreg->socket_state; + } while (sockstate & PCCBB_SOCKET_STAT_CD && --timeout > 0); + + if (timeout < 0) { + device_printf (sc->sc_dev, "insert timeout"); + return; + } + + DEVPRINTF((sc->sc_dev, "card inserted: event=0x%08x, state=%08x\n", + sockevent, sockstate)); + + if (sockstate & PCCBB_SOCKET_STAT_16BIT && sc->sc_pccarddev != NULL) { + sc->sc_flags |= PCCBB_CARDATTACHED | PCCBB_16BIT_CARD; + if (CARD_ATTACH_CARD(sc->sc_pccarddev) != 0) { + device_printf(sc->sc_dev, "card activation failed\n"); + sc->sc_flags &= ~PCCBB_CARDATTACHED; + } + } else if (sockstate & PCCBB_SOCKET_STAT_CB && sc->sc_cbdev != NULL) { + sc->sc_flags |= PCCBB_CARDATTACHED; + sc->sc_flags &= ~PCCBB_16BIT_CARD; + if (CARD_ATTACH_CARD(sc->sc_cbdev) != 0) { + device_printf(sc->sc_dev, "card activation failed\n"); + sc->sc_flags &= ~PCCBB_CARDATTACHED; + } + } else { + device_printf (sc->sc_dev, "Unsupported card type detected\n"); + } +} + +static void +pccbb_removal (struct pccbb_softc *sc) +{ + u_int32_t sockstate; + struct pccbb_reslist *rle; + + sockstate = sc->sc_socketreg->socket_state; + + sc->sc_flags &= ~PCCBB_CARDATTACHED; + if (sockstate & PCCBB_16BIT_CARD) + CARD_DETACH_CARD(sc->sc_pccarddev, DETACH_FORCE); + else + CARD_DETACH_CARD(sc->sc_cbdev, DETACH_FORCE); + + while (NULL != (rle = SLIST_FIRST(&sc->rl))) { + device_printf(sc->sc_dev, "WARNING: Resource left allocated! " + "This is a bug... (rid=%x, type=%d, addr=%x)\n", + rle->rid, rle->type, rle->start); + SLIST_REMOVE_HEAD(&sc->rl, entries); + } +} + +/************************************************************************/ +/* Interrupt Handler */ +/************************************************************************/ + +static void +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. */ + return; + } + + /* reset bit */ + 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; + } + wakeup(sc); + } else { + if (sockevent & PCCBB_SOCKET_EVENT_CSTS) { + DPRINTF((" cstsevent occures, 0x%08x\n", + sc->sc_socketreg->socket_state)); + } + if (sockevent & PCCBB_SOCKET_EVENT_POWER) { + DPRINTF((" pwrevent occures, 0x%08x\n", + sc->sc_socketreg->socket_state)); + } + } + + return; +} + +/************************************************************************/ +/* Power functions */ +/************************************************************************/ + +static int +pccbb_detect_voltage(struct pccbb_softc *sc) +{ + u_int32_t psr; + int vol = CARD_UKN_CARD; + + psr = sc->sc_socketreg->socket_state; + + if (psr & PCCBB_SOCKET_STAT_5VCARD) { + vol |= CARD_5V_CARD; + } + if (psr & PCCBB_SOCKET_STAT_3VCARD) { + vol |= CARD_3V_CARD; + } + if (psr & PCCBB_SOCKET_STAT_XVCARD) { + vol |= CARD_XV_CARD; + } + if (psr & PCCBB_SOCKET_STAT_YVCARD) { + vol |= CARD_YV_CARD; + } + + return vol; +} + +static int +pccbb_power(device_t dev, int volts) +{ + u_int32_t status, sock_ctrl; + struct pccbb_softc *sc = device_get_softc(dev); + + DEVPRINTF((sc->sc_dev, "pccbb_power: %s and %s [%x]\n", + (volts & CARD_VCCMASK) == CARD_VCC_UC ? "CARD_VCC_UC" : + (volts & CARD_VCCMASK) == CARD_VCC_5V ? "CARD_VCC_5V" : + (volts & CARD_VCCMASK) == CARD_VCC_3V ? "CARD_VCC_3V" : + (volts & CARD_VCCMASK) == CARD_VCC_XV ? "CARD_VCC_XV" : + (volts & CARD_VCCMASK) == CARD_VCC_YV ? "CARD_VCC_YV" : + (volts & CARD_VCCMASK) == CARD_VCC_0V ? "CARD_VCC_0V" : + "VCC-UNKNOWN", + (volts & CARD_VPPMASK) == CARD_VPP_UC ? "CARD_VPP_UC" : + (volts & CARD_VPPMASK) == CARD_VPP_12V ? "CARD_VPP_12V" : + (volts & CARD_VPPMASK) == CARD_VPP_VCC ? "CARD_VPP_VCC" : + (volts & CARD_VPPMASK) == CARD_VPP_0V ? "CARD_VPP_0V" : + "VPP-UNKNOWN", + volts)); + + status = sc->sc_socketreg->socket_state; + sock_ctrl = sc->sc_socketreg->socket_control; + + switch (volts & CARD_VCCMASK) { + case CARD_VCC_UC: + break; + case CARD_VCC_5V: + if (PCCBB_SOCKET_STAT_5VCARD & status) { /* check 5 V card */ + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VCCMASK; + sock_ctrl |= PCCBB_SOCKET_CTRL_VCC_5V; + } else { + device_printf(sc->sc_dev, + "BAD voltage request: no 5 V card\n"); + } + break; + case CARD_VCC_3V: + if (PCCBB_SOCKET_STAT_3VCARD & status) { + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VCCMASK; + sock_ctrl |= PCCBB_SOCKET_CTRL_VCC_3V; + } else { + device_printf(sc->sc_dev, + "BAD voltage request: no 3.3 V card\n"); + } + break; + case CARD_VCC_0V: + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VCCMASK; + break; + default: + return 0; /* power NEVER changed */ + break; + } + + switch (volts & CARD_VPPMASK) { + case CARD_VPP_UC: + break; + case CARD_VPP_0V: + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VPPMASK; + break; + case CARD_VPP_VCC: + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VPPMASK; + sock_ctrl |= ((sock_ctrl >> 4) & 0x07); + break; + case CARD_VPP_12V: + sock_ctrl &= ~PCCBB_SOCKET_CTRL_VPPMASK; + sock_ctrl |= PCCBB_SOCKET_CTRL_VPP_12V; + break; + } + + sc->sc_socketreg->socket_control = sock_ctrl; + status = sc->sc_socketreg->socket_state; + + { + int timeout = 20; + u_int32_t sockevent; + do { + DELAY(20*1000); + sockevent = sc->sc_socketreg->socket_event; + } while (!(sockevent & PCCBB_SOCKET_EVENT_POWER) && + --timeout > 0); + /* reset event status */ + sc->sc_socketreg->socket_event = sockevent; + if ( timeout < 0 ) { + printf ("VCC supply failed.\n"); + return 0; + } + } + /* XXX + * delay 400 ms: thgough the standard defines that the Vcc set-up time + * is 20 ms, some PC-Card bridge requires longer duration. + */ + DELAY(400*1000); + + if (status & PCCBB_SOCKET_STAT_BADVCC) { + device_printf(sc->sc_dev, + "bad Vcc request. ctrl=0x%x, status=0x%x\n", + sock_ctrl ,status); + printf("pccbb_power: %s and %s [%x]\n", + (volts & CARD_VCCMASK) == CARD_VCC_UC ? "CARD_VCC_UC" : + (volts & CARD_VCCMASK) == CARD_VCC_5V ? "CARD_VCC_5V" : + (volts & CARD_VCCMASK) == CARD_VCC_3V ? "CARD_VCC_3V" : + (volts & CARD_VCCMASK) == CARD_VCC_XV ? "CARD_VCC_XV" : + (volts & CARD_VCCMASK) == CARD_VCC_YV ? "CARD_VCC_YV" : + (volts & CARD_VCCMASK) == CARD_VCC_0V ? "CARD_VCC_0V" : + "VCC-UNKNOWN", + (volts & CARD_VPPMASK) == CARD_VPP_UC ? "CARD_VPP_UC" : + (volts & CARD_VPPMASK) == CARD_VPP_12V ? "CARD_VPP_12V": + (volts & CARD_VPPMASK) == CARD_VPP_VCC ? "CARD_VPP_VCC": + (volts & CARD_VPPMASK) == CARD_VPP_0V ? "CARD_VPP_0V" : + "VPP-UNKNOWN", + volts); + return 0; + } + return 1; /* power changed correctly */ +} + +/************************************************************************/ +/* PCCBB methods */ +/************************************************************************/ + +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 +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); + + 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); + DELAY(delay_us); + } + return 1; +} + + +/************************************************************************/ +/* Cardbus Resource */ +/************************************************************************/ + +static int +pccbb_cardbus_io_open(device_t dev, int win, u_int32_t start, u_int32_t end) +{ + int basereg; + int limitreg; + + if ((win < 0) || (win > 1)) { + DEVPRINTF((dev, + "pccbb_cardbus_io_open: window out of range %d\n", + win)); + return EINVAL; + } + + basereg = win*8 + PCCBBR_IOBASE0; + limitreg = win*8 + PCCBBR_IOLIMIT0; + + pci_write_config(dev, basereg, start, 4); + pci_write_config(dev, limitreg, end, 4); + return 0; +} + +static int +pccbb_cardbus_mem_open(device_t dev, int win, u_int32_t start, u_int32_t end) +{ + int basereg; + int limitreg; + + if ((win < 0) || (win > 1)) { + DEVPRINTF((dev, + "pccbb_cardbus_mem_open: window out of range %d\n", + win)); + return EINVAL; + } + + basereg = win*8 + PCCBBR_MEMBASE0; + limitreg = win*8 + PCCBBR_MEMLIMIT0; + + pci_write_config(dev, basereg, start, 4); + pci_write_config(dev, limitreg, end, 4); + return 0; +} + +static void +pccbb_cardbus_auto_open(struct pccbb_softc *sc, int type) +{ + u_int32_t starts[2]; + u_int32_t ends[2]; + struct pccbb_reslist *rle; + int align; + + starts[0] = starts[1] = 0xffffffff; + ends[0] = ends[1] = 0; + + SLIST_FOREACH(rle, &sc->rl, entries) { + if (rle->type != type) + ; + else if (starts[0] == 0xffffffff) { + starts[0] = rle->start; + ends[0] = rle->end; + rle->win = 0; + } else if (rle->end > ends[0] && + rle->start - ends[0] < PCCBB_AUTO_OPEN_SMALLHOLE) { + ends[0] = rle->end; + rle->win = 0; + } else if (rle->start < starts[0] && + starts[0] - rle->end < PCCBB_AUTO_OPEN_SMALLHOLE) { + starts[0] = rle->start; + rle->win = 0; + } else if (starts[1] == 0xffffffff) { + starts[1] = rle->start; + ends[1] = rle->end; + rle->win = 1; + } else if (rle->end > ends[1] && + rle->start - ends[1] < PCCBB_AUTO_OPEN_SMALLHOLE) { + ends[1] = rle->end; + rle->win = 1; + } else if (rle->start < starts[1] && + starts[1] - rle->end < PCCBB_AUTO_OPEN_SMALLHOLE) { + starts[1] = rle->start; + rle->win = 1; + } else { + u_int32_t diffs[2]; + + diffs[0] = diffs[1] = 0xffffffff; + if (rle->start > ends[0]) + diffs[0] = rle->start - ends[0]; + else if (rle->end < starts[0]) + diffs[0] = starts[0] - rle->end; + if (rle->start > ends[1]) + diffs[1] = rle->start - ends[1]; + else if (rle->end < starts[1]) + diffs[1] = starts[1] - rle->end; + + rle->win = (diffs[0] <= diffs[1])?0:1; + if (rle->start > ends[rle->win]) + 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) + align = PCCBB_IOALIGN; + else + align = 1; + + if (starts[0] != 0xffffffff) + starts[0] -= starts[0] % align; + if (starts[1] != 0xffffffff) + starts[1] -= starts[1] % align; + if (ends[0] % align != 0) + ends[0] += align - ends[0]%align; + if (ends[1] % align != 0) + ends[1] += align - ends[1]%align; + + if (type == SYS_RES_MEMORY) { + pccbb_cardbus_mem_open(sc->sc_dev, 0, starts[0], ends[0]); + pccbb_cardbus_mem_open(sc->sc_dev, 1, starts[1], ends[1]); + } else if (type == SYS_RES_IOPORT) { + pccbb_cardbus_io_open(sc->sc_dev, 0, starts[0], ends[0]); + pccbb_cardbus_io_open(sc->sc_dev, 1, starts[1], ends[1]); + } +} + +static int +pccbb_cardbus_activate_resource(device_t self, device_t child, int type, + int rid, struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_reslist *rle; + + if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + SLIST_FOREACH(rle, &sc->rl, entries) { + if (type == rle->type && rid == rle->rid && + child == rle->odev) + return bus_generic_activate_resource( + self, child, type, rid, r); + } + rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_WAITOK); + rle->type = type; + rle->rid = rid; + rle->start = rman_get_start(r); + rle->end = rman_get_end(r); + rle->odev = child; + rle->win = -1; + SLIST_INSERT_HEAD(&sc->rl, rle, entries); + + pccbb_cardbus_auto_open(sc, type); + } + + return bus_generic_activate_resource(self, child, type, rid, r); +} + +static int +pccbb_cardbus_deactivate_resource(device_t self, device_t child, int type, + int rid, struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_reslist *rle; + + SLIST_FOREACH(rle, &sc->rl, entries) { + if (type == rle->type && rid == rle->rid && + child == rle->odev) { + SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, entries); + if (type == SYS_RES_IOPORT || + type == SYS_RES_MEMORY) + pccbb_cardbus_auto_open(sc, type); + free(rle, M_DEVBUF); + break; + } + } + return bus_generic_deactivate_resource(self, child, type, rid, r); +} + +static struct resource* +pccbb_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) +{ + if (type == SYS_RES_IRQ) { + struct pccbb_softc *sc = device_get_softc(self); + if (start == 0) { + start = end = rman_get_start(sc->sc_irq_res); + } + return bus_generic_alloc_resource(self, child, type, rid, + start, end, count, flags); + } else { + if (type == SYS_RES_MEMORY && start == 0 && end == ~0) { + start = CARDBUS_SYS_RES_MEMORY_START; + end = CARDBUS_SYS_RES_MEMORY_END; + } else if (type == SYS_RES_IOPORT && start == 0 && end == ~0) { + start = CARDBUS_SYS_RES_IOPORT_START; + end = CARDBUS_SYS_RES_IOPORT_END; + } + return bus_generic_alloc_resource(self, child, type, rid, + start, end, count, flags); + } +} + +static int +pccbb_cardbus_release_resource(device_t self, device_t child, int type, + int rid, struct resource *r) +{ + return bus_generic_release_resource(self, child, type, rid, r); +} + +/************************************************************************/ +/* PC Card Resources */ +/************************************************************************/ + +static void +pccbb_pcic_wait_ready(struct pccbb_softc *sc) +{ + int i; + DEVPRINTF((sc->sc_dev, "pccbb_pcic_wait_ready: status 0x%02x\n", + PCIC_READ(sc, PCIC_IF_STATUS))); + for (i = 0; i < 10000; i++) { + if (PCIC_READ(sc, PCIC_IF_STATUS) & PCIC_IF_STATUS_READY) { + return; + } + DELAY(500); + } + device_printf(sc->sc_dev, "ready never happened, status = %02x\n", + PCIC_READ(sc, PCIC_IF_STATUS)); +} + +#define PCIC_MEMINFO(NUM) { \ + PCIC_SYSMEM_ADDR ## NUM ## _START_LSB, \ + PCIC_SYSMEM_ADDR ## NUM ## _START_MSB, \ + PCIC_SYSMEM_ADDR ## NUM ## _STOP_LSB, \ + PCIC_SYSMEM_ADDR ## NUM ## _STOP_MSB, \ + PCIC_CARDMEM_ADDR ## NUM ## _LSB, \ + PCIC_CARDMEM_ADDR ## NUM ## _MSB, \ + PCIC_ADDRWIN_ENABLE_MEM ## NUM ## , \ +} + +static struct mem_map_index_st { + int sysmem_start_lsb; + int sysmem_start_msb; + int sysmem_stop_lsb; + int sysmem_stop_msb; + int cardmem_lsb; + int cardmem_msb; + int memenable; +} mem_map_index[] = { + PCIC_MEMINFO(0), + PCIC_MEMINFO(1), + PCIC_MEMINFO(2), + PCIC_MEMINFO(3), + PCIC_MEMINFO(4), +}; +#undef PCIC_MEMINFO + +static void +pccbb_pcic_do_mem_map(struct pccbb_softc *sc, int win) +{ + PCIC_WRITE(sc, mem_map_index[win].sysmem_start_lsb, + (sc->mem[win].addr >> PCIC_SYSMEM_ADDRX_SHIFT) & 0xff); + PCIC_WRITE(sc, mem_map_index[win].sysmem_start_msb, + ((sc->mem[win].addr >> (PCIC_SYSMEM_ADDRX_SHIFT + 8)) & + PCIC_SYSMEM_ADDRX_START_MSB_ADDR_MASK)); + + PCIC_WRITE(sc, mem_map_index[win].sysmem_stop_lsb, + ((sc->mem[win].addr + sc->mem[win].realsize - 1) >> + PCIC_SYSMEM_ADDRX_SHIFT) & 0xff); + PCIC_WRITE(sc, mem_map_index[win].sysmem_stop_msb, + (((sc->mem[win].addr + sc->mem[win].realsize - 1) >> + (PCIC_SYSMEM_ADDRX_SHIFT + 8)) & + PCIC_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) | + PCIC_SYSMEM_ADDRX_STOP_MSB_WAIT2); + + PCIC_WRITE(sc, mem_map_index[win].cardmem_lsb, + (sc->mem[win].offset >> PCIC_CARDMEM_ADDRX_SHIFT) & 0xff); + PCIC_WRITE(sc, mem_map_index[win].cardmem_msb, + ((sc->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8)) & + PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK) | + ((sc->mem[win].kind == PCCARD_MEM_ATTR) ? + PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0)); + + PCIC_MASK(sc, PCIC_ADDRWIN_ENABLE, | PCIC_ADDRWIN_ENABLE_MEMCS16 + | mem_map_index[win].memenable); + + DELAY(100); + +#ifdef CBB_DEBUG + { + int r1, r2, r3, r4, r5, r6; + r1 = PCIC_READ(sc, mem_map_index[win].sysmem_start_msb); + r2 = PCIC_READ(sc, mem_map_index[win].sysmem_start_lsb); + r3 = PCIC_READ(sc, mem_map_index[win].sysmem_stop_msb); + r4 = PCIC_READ(sc, mem_map_index[win].sysmem_stop_lsb); + r5 = PCIC_READ(sc, mem_map_index[win].cardmem_msb); + r6 = PCIC_READ(sc, mem_map_index[win].cardmem_lsb); + DPRINTF(("pccbb_pcic_do_mem_map window %d: %02x%02x %02x%02x " + "%02x%02x\n", win, r1, r2, r3, r4, r5, r6)); + } +#endif +} + +static int +pccbb_pcic_mem_map(struct pccbb_softc *sc, int kind, + struct resource *r, bus_addr_t card_addr, int *win) +{ + int i; + + *win = -1; + for (i = 0; i < PCIC_MEM_WINS; i++) { + if ((sc->memalloc & (1 << i)) == 0) { + *win = i; + sc->memalloc |= (1 << i); + break; + } + } + if (*win == -1) + return (1); + + card_addr = card_addr - card_addr % PCIC_MEM_PAGESIZE; + + sc->mem[*win].memt = rman_get_bustag(r); + sc->mem[*win].memh = rman_get_bushandle(r); + sc->mem[*win].addr = rman_get_start(r); + sc->mem[*win].size = rman_get_end(r) - sc->mem[*win].addr + 1; + sc->mem[*win].realsize = sc->mem[*win].size + PCIC_MEM_PAGESIZE - 1; + sc->mem[*win].realsize = sc->mem[*win].realsize - + (sc->mem[*win].realsize % PCIC_MEM_PAGESIZE); + sc->mem[*win].offset = ((long)card_addr) - + ((long)(sc->mem[*win].addr)); + sc->mem[*win].kind = kind; + + DPRINTF(("pccbb_pcic_mem_map window %d bus %x+%x+%lx card addr %x\n", + *win, sc->mem[*win].addr, sc->mem[*win].size, + sc->mem[*win].offset, card_addr)); + + pccbb_pcic_do_mem_map(sc, *win); + + return (0); +} + +static void +pccbb_pcic_mem_unmap(struct pccbb_softc *sc, int window) +{ + if (window >= PCIC_MEM_WINS) + panic("pccbb_pcic_mem_unmap: window out of range"); + + PCIC_MASK(sc, PCIC_ADDRWIN_ENABLE, & ~mem_map_index[window].memenable); + + sc->memalloc &= ~(1 << window); +} + +#define PCIC_IOINFO(NUM) { \ + PCIC_IOADDR ## NUM ## _START_LSB, \ + PCIC_IOADDR ## NUM ## _START_MSB, \ + PCIC_IOADDR ## NUM ## _STOP_LSB, \ + PCIC_IOADDR ## NUM ## _STOP_MSB, \ + PCIC_ADDRWIN_ENABLE_IO ## NUM ## , \ + PCIC_IOCTL_IO ## NUM ## _WAITSTATE \ + | PCIC_IOCTL_IO ## NUM ## _ZEROWAIT \ + | PCIC_IOCTL_IO ## NUM ## _IOCS16SRC_MASK \ + | PCIC_IOCTL_IO ## NUM ## _DATASIZE_MASK, \ + { \ + PCIC_IOCTL_IO ## NUM ## _IOCS16SRC_CARD, \ + PCIC_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ + | PCIC_IOCTL_IO ## NUM ## _DATASIZE_8BIT, \ + PCIC_IOCTL_IO ## NUM ## _IOCS16SRC_DATASIZE \ + | PCIC_IOCTL_IO ## NUM ## _DATASIZE_16BIT, \ + } \ +} + +static struct io_map_index_st { + int start_lsb; + int start_msb; + int stop_lsb; + int stop_msb; + int ioenable; + int ioctlmask; + int ioctlbits[3]; /* indexed by PCCARD_WIDTH_* */ +} io_map_index[] = { + PCIC_IOINFO(0), + PCIC_IOINFO(1), +}; +#undef PCIC_IOINFO + +static void pccbb_pcic_do_io_map(struct pccbb_softc *sc, int win) +{ + PCIC_WRITE(sc, io_map_index[win].start_lsb, sc->io[win].addr & 0xff); + PCIC_WRITE(sc, io_map_index[win].start_msb, + (sc->io[win].addr >> 8) & 0xff); + + PCIC_WRITE(sc, io_map_index[win].stop_lsb, + (sc->io[win].addr + sc->io[win].size - 1) & 0xff); + PCIC_WRITE(sc, io_map_index[win].stop_msb, + ((sc->io[win].addr + sc->io[win].size - 1) >> 8) & 0xff); + + PCIC_MASK2(sc, PCIC_IOCTL, + & ~io_map_index[win].ioctlmask, + | io_map_index[win].ioctlbits[sc->io[win].width]); + + PCIC_MASK(sc, PCIC_ADDRWIN_ENABLE, | io_map_index[win].ioenable); +} + +static int +pccbb_pcic_io_map(struct pccbb_softc *sc, int width, + struct resource *r, bus_addr_t card_addr, int *win) +{ + int i; +#ifdef CBB_DEBUG + static char *width_names[] = { "auto", "io8", "io16"}; +#endif + + *win = -1; + for (i=0; i < PCIC_IO_WINS; i++) { + if ((sc->ioalloc & (1 << i)) == 0) { + *win = i; + sc->ioalloc |= (1 << i); + break; + } + } + if (*win == -1) + return (1); + + sc->io[*win].iot = rman_get_bustag(r); + sc->io[*win].ioh = rman_get_bushandle(r); + sc->io[*win].addr = rman_get_start(r); + sc->io[*win].size = rman_get_end(r) - sc->io[*win].addr + 1; + sc->io[*win].flags = 0; + sc->io[*win].width = width; + + DPRINTF(("pccbb_pcic_io_map window %d %s port %x+%x\n", + *win, width_names[width], sc->io[*win].addr, + sc->io[*win].size)); + + pccbb_pcic_do_io_map(sc, *win); + + return (0); +} + +static void +pccbb_pcic_io_unmap(struct pccbb_softc *sc, int window) +{ + if (window >= PCIC_IO_WINS) + panic("pccbb_pcic_io_unmap: window out of range"); + + PCIC_MASK(sc, PCIC_ADDRWIN_ENABLE, & ~io_map_index[window].ioenable); + + sc->ioalloc &= ~(1 << window); + + sc->io[window].iot = 0; + sc->io[window].ioh = 0; + sc->io[window].addr = 0; + sc->io[window].size = 0; + sc->io[window].flags = 0; + sc->io[window].width = 0; +} + +static int +pccbb_pcic_activate_resource(device_t self, device_t child, int type, int rid, + struct resource *r) +{ + int err; + int win; + struct pccbb_reslist *rle; + struct pccbb_softc *sc = device_get_softc(self); + + switch (type) { + case SYS_RES_IOPORT: + err = pccbb_pcic_io_map(sc, 0, r, 0, &win); + if (err) + return err; + break; + case SYS_RES_MEMORY: + err = pccbb_pcic_mem_map(sc, 0, r, 0, &win); + if (err) + return err; + break; + default: + break; + } + SLIST_FOREACH(rle, &sc->rl, entries) { + if (type == rle->type && rid == rle->rid && + child == rle->odev) { + rle->win = win; + break; + } + } + err = bus_generic_activate_resource(self, child, type, rid, r); + return (err); +} + +static int +pccbb_pcic_deactivate_resource(device_t self, device_t child, int type, + int rid, struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + int win; + struct pccbb_reslist *rle; + + win = -1; + SLIST_FOREACH(rle, &sc->rl, entries) { + if (type == rle->type && rid == rle->rid && + child == rle->odev) { + win = rle->win; + break; + } + } + if (win == -1) + return 1; + + switch (type) { + case SYS_RES_IOPORT: + pccbb_pcic_io_unmap(sc, win); + break; + case SYS_RES_MEMORY: + pccbb_pcic_mem_unmap(sc, win); + break; + default: + break; + } + return bus_generic_deactivate_resource(self, child, type, rid, r); +} + +static struct resource* +pccbb_pcic_alloc_resource(device_t self, device_t child, int type, int* rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *r = NULL; + 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; + } + + if (type == SYS_RES_MEMORY) + flags = (flags & ~RF_ALIGNMENT_MASK) + | rman_make_alignment_flags(PCCBB_MEMALIGN); + + r = bus_generic_alloc_resource(self, child, type, rid, start, end, + count, flags & ~RF_ACTIVE); + if (r == NULL) + return NULL; + + rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_WAITOK); + rle->type = type; + rle->rid = *rid; + rle->start = rman_get_start(r); + rle->end = rman_get_end(r); + rle->odev = child; + rle->win = -1; + SLIST_INSERT_HEAD(&sc->rl, rle, entries); + + if (flags & RF_ACTIVE) { + if (bus_activate_resource(child, type, *rid, r) != 0) { + BUS_RELEASE_RESOURCE(self, child, type, *rid, r); + return NULL; + } + } + + return r; +} + +static int +pccbb_pcic_release_resource(device_t self, device_t child, int type, + int rid, struct resource *res) +{ + struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_reslist *rle; + + SLIST_FOREACH(rle, &sc->rl, entries) { + if (type == rle->type && rid == rle->rid && + child == rle->odev) { + SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, entries); + free(rle, M_DEVBUF); + break; + } + } + + return bus_generic_release_resource(self, child, type, rid, res); +} + +/************************************************************************/ +/* PC Card methods */ +/************************************************************************/ + +static int +pccbb_pcic_set_res_flags(device_t self, device_t child, int type, int rid, + u_int32_t flags) +{ + struct pccbb_softc *sc = device_get_softc(self); + + DPRINTF(("%p %p %d %d %#x\n", self, child, type, rid, flags)); + if (type != SYS_RES_MEMORY) + return (EINVAL); + sc->mem[rid].kind = PCCARD_MEM_ATTR; + pccbb_pcic_do_mem_map(sc, rid); + return 0; +} + +static int +pccbb_pcic_set_memory_offset(device_t self, device_t child, int rid, + u_int32_t offset) +{ + struct pccbb_softc *sc = device_get_softc(self); + int win; + struct pccbb_reslist *rle; + + win = -1; + SLIST_FOREACH(rle, &sc->rl, entries) { + if (SYS_RES_MEMORY == rle->type && rid == rle->rid && + child == rle->odev) { + win = rle->win; + break; + } + } + if (win == -1) + return 1; + + offset = offset - offset % PCIC_MEM_PAGESIZE; + sc->mem[win].offset = ((long)offset) - + ((long)(sc->mem[win].addr)); + + pccbb_pcic_do_mem_map(sc, win); + + return 0; +} + +static int +pccbb_pcic_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; +} + +static void +pccbb_pcic_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); +} + +/************************************************************************/ +/* Methods */ +/************************************************************************/ + + +static int +pccbb_activate_resource(device_t self, device_t child, int type, int rid, + struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + + if (sc->sc_flags & PCCBB_16BIT_CARD) + return pccbb_pcic_activate_resource(self, child, type, rid, r); + else + return pccbb_cardbus_activate_resource(self, child, type, rid, + r); +} + +static int +pccbb_deactivate_resource(device_t self, device_t child, int type, + int rid, struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + + if (sc->sc_flags & PCCBB_16BIT_CARD) + return pccbb_pcic_deactivate_resource(self, child, type, + rid, r); + else + return pccbb_cardbus_deactivate_resource(self, child, type, + rid, r); +} + +static struct resource* +pccbb_alloc_resource(device_t self, device_t child, int type, int* rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct pccbb_softc *sc = device_get_softc(self); + + if (sc->sc_flags & PCCBB_16BIT_CARD) + return pccbb_pcic_alloc_resource(self, child, type, rid, + start, end, count, flags); + else + return pccbb_cardbus_alloc_resource(self, child, type, rid, + start, end, count, flags); +} + +static int +pccbb_release_resource(device_t self, device_t child, int type, int rid, + struct resource *r) +{ + struct pccbb_softc *sc = device_get_softc(self); + + if (sc->sc_flags & PCCBB_16BIT_CARD) + return pccbb_pcic_release_resource(self, child, type, + rid, r); + else + return pccbb_cardbus_release_resource(self, child, type, + rid, r); +} + +static int +pccbb_maxslots(device_t dev) +{ + return 0; +} + +static u_int32_t +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). + */ + return PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), + b, s, f, reg, width); +} + +static void +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). + */ + PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), + b, s, f, reg, val, width); +} + +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_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* bus methods */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, pccbb_alloc_resource), + DEVMETHOD(bus_release_resource, pccbb_release_resource), + DEVMETHOD(bus_activate_resource, pccbb_activate_resource), + DEVMETHOD(bus_deactivate_resource, pccbb_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* 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} +}; + +static driver_t pccbb_driver = { + "pccbb", + pccbb_methods, + sizeof(struct pccbb_softc) +}; +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 new file mode 100644 index 000000000000..2f3ddd304484 --- /dev/null +++ b/sys/dev/pccbb/pccbb_if.m @@ -0,0 +1,69 @@ +# +# 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/pccbbreg.h b/sys/dev/pccbb/pccbbreg.h new file mode 100644 index 000000000000..9758335de001 --- /dev/null +++ b/sys/dev/pccbb/pccbbreg.h @@ -0,0 +1,188 @@ +/* + * 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$ + */ + +/* + * Register definitions for PCI to Cardbus Bridge chips + */ + + +/* PCI header registers */ +#define PCCBBR_SOCKBASE 0x10 /* len=4 */ + +#define PCCBBR_MEMBASE0 0x1c /* len=4 */ +#define PCCBBR_MEMLIMIT0 0x20 /* len=4 */ +#define PCCBBR_MEMBASE1 0x24 /* len=4 */ +#define PCCBBR_MEMLIMIT1 0x28 /* len=4 */ +#define PCCBBR_IOBASE0 0x2c /* len=4 */ +#define PCCBBR_IOLIMIT0 0x30 /* len=4 */ +#define PCCBBR_IOBASE1 0x34 /* len=4 */ +#define PCCBBR_IOLIMIT1 0x38 /* len=4 */ +#define PCCBB_MEMALIGN 4096 +#define PCCBB_IOALIGN 4 + +#define PCCBBR_INTRLINE 0x3c /* len=1 */ +#define PCCBBR_INTRPIN 0x3d /* len=1 */ +#define PCCBBR_BRIDGECTRL 0x3e /* len=2 */ +# define PCCBBM_BRIDGECTRL_MASTER_ABORT 0x0020 +# define PCCBBM_BRIDGECTRL_RESET 0x0040 +# define PCCBBM_BRIDGECTRL_INTR_IREQ_EN 0x0080 +# define PCCBBM_BRIDGECTRL_PREFETCH_0 0x0100 +# define PCCBBM_BRIDGECTRL_PREFETCH_1 0x0200 +# define PCCBBM_BRIDGECTRL_WRITE_POST_EN 0x0400 + /* additional bit for RF5C46[567] */ +# define PCCBBM_BRIDGECTRL_RL_3E0_EN 0x0800 +# define PCCBBM_BRIDGECTRL_RL_3E2_EN 0x1000 + +#define PCCBBR_LEGACY 0x44 /* len=4 */ + +#define PCCBBR_CBCTRL 0x91 /* len=1 */ + /* bits for TI 113X */ +# define PCCBBM_CBCTRL_113X_RI_EN 0x80 +# define PCCBBM_CBCTRL_113X_ZV_EN 0x40 +# define PCCBBM_CBCTRL_113X_PCI_IRQ_EN 0x20 +# define PCCBBM_CBCTRL_113X_PCI_INTR 0x10 +# define PCCBBM_CBCTRL_113X_PCI_CSC 0x08 +# define PCCBBM_CBCTRL_113X_PCI_CSC_D 0x04 +# define PCCBBM_CBCTRL_113X_SPEAKER_EN 0x02 +# define PCCBBM_CBCTRL_113X_INTR_DET 0x01 + /* bits for TI 12XX */ +# define PCCBBM_CBCTRL_12XX_RI_EN 0x80 +# define PCCBBM_CBCTRL_12XX_ZV_EN 0x40 +# define PCCBBM_CBCTRL_12XX_AUD2MUX 0x04 +# define PCCBBM_CBCTRL_12XX_SPEAKER_EN 0x02 +# define PCCBBM_CBCTRL_12XX_INTR_DET 0x01 +#define PCCBBR_DEVCTRL 0x92 /* len=1 */ +# define PCCBBM_DEVCTRL_INT_SERIAL 0x04 +# define PCCBBM_DEVCTRL_INT_PCI 0x02 + +#define PCCBBR_TOPIC_SOCKETCTRL 0x90 +# define PCCBBM_TOPIC_SOCKETCTRL_SCR_IRQSEL 0x00000001 /* PCI intr */ + +#define PCCBBR_TOPIC_SLOTCTRL 0xa0 +# define PCCBBM_TOPIC_SLOTCTRL_SLOTON 0x00000080 +# define PCCBBM_TOPIC_SLOTCTRL_SLOTEN 0x00000040 +# define PCCBBM_TOPIC_SLOTCTRL_ID_LOCK 0x00000020 +# define PCCBBM_TOPIC_SLOTCTRL_ID_WP 0x00000010 +# define PCCBBM_TOPIC_SLOTCTRL_PORT_MASK 0x0000000c +# define PCCBBM_TOPIC_SLOTCTRL_PORT_SHIFT 2 +# define PCCBBM_TOPIC_SLOTCTRL_OSF_MASK 0x00000003 +# define PCCBBM_TOPIC_SLOTCTRL_OSF_SHIFT 0 +# define PCCBBM_TOPIC_SLOTCTRL_INTB 0x00002000 +# define PCCBBM_TOPIC_SLOTCTRL_INTA 0x00001000 +# define PCCBBM_TOPIC_SLOTCTRL_INT_MASK 0x00003000 +# define PCCBBM_TOPIC_SLOTCTRL_CLOCK_MASK 0x00000c00 +# define PCCBBM_TOPIC_SLOTCTRL_CLOCK_2 0x00000800 /* PCI Clock/2 */ +# define PCCBBM_TOPIC_SLOTCTRL_CLOCK_1 0x00000400 /* PCI Clock */ +# define PCCBBM_TOPIC_SLOTCTRL_CLOCK_0 0x00000000 /* no clock */ +# define PCCBBM_TOPIC_SLOTCTRL_CARDBUS 0x80000000 +# define PCCBBM_TOPIC_SLOTCTRL_VS1 0x04000000 +# define PCCBBM_TOPIC_SLOTCTRL_VS2 0x02000000 +# define PCCBBM_TOPIC_SLOTCTRL_SWDETECT 0x01000000 + +/* Socket definitions */ +#define PCCBB_SOCKET_EVENT_CSTS 0x01 /* Card Status Change */ +#define PCCBB_SOCKET_EVENT_CD1 0x02 /* Card Detect 1 */ +#define PCCBB_SOCKET_EVENT_CD2 0x04 /* Card Detect 2 */ +#define PCCBB_SOCKET_EVENT_CD 0x06 /* Card Detect all */ +#define PCCBB_SOCKET_EVENT_POWER 0x08 /* Power Cycle */ + +#define PCCBB_SOCKET_MASK_CSTS 0x01 /* Card Status Change */ +#define PCCBB_SOCKET_MASK_CD 0x06 /* Card Detect */ +#define PCCBB_SOCKET_MASK_POWER 0x08 /* Power Cycle */ + +#define PCCBB_SOCKET_STAT_CARDSTS 0x00000001 /* Card Status Change */ +#define PCCBB_SOCKET_STAT_CD1 0x00000002 /* Card Detect 1 */ +#define PCCBB_SOCKET_STAT_CD2 0x00000004 /* Card Detect 2 */ +#define PCCBB_SOCKET_STAT_CD 0x00000006 /* Card Detect all */ +#define PCCBB_SOCKET_STAT_PWRCYCLE 0x00000008 /* Power Cycle */ +#define PCCBB_SOCKET_STAT_16BIT 0x00000010 /* 16-bit Card */ +#define PCCBB_SOCKET_STAT_CB 0x00000020 /* Cardbus Card */ +#define PCCBB_SOCKET_STAT_IREQ 0x00000040 /* Ready */ +#define PCCBB_SOCKET_STAT_NOTCARD 0x00000080 /* Unrecognized Card */ +#define PCCBB_SOCKET_STAT_DATALOST 0x00000100 /* Data Lost */ +#define PCCBB_SOCKET_STAT_BADVCC 0x00000200 /* Bad VccRequest */ +#define PCCBB_SOCKET_STAT_5VCARD 0x00000400 /* 5 V Card */ +#define PCCBB_SOCKET_STAT_3VCARD 0x00000800 /* 3.3 V Card */ +#define PCCBB_SOCKET_STAT_XVCARD 0x00001000 /* X.X V Card */ +#define PCCBB_SOCKET_STAT_YVCARD 0x00002000 /* Y.Y V Card */ +#define PCCBB_SOCKET_STAT_5VSOCK 0x10000000 /* 5 V Socket */ +#define PCCBB_SOCKET_STAT_3VSOCK 0x20000000 /* 3.3 V Socket */ +#define PCCBB_SOCKET_STAT_XVSOCK 0x40000000 /* X.X V Socket */ +#define PCCBB_SOCKET_STAT_YVSOCK 0x80000000 /* Y.Y V Socket */ + +#define PCCBB_SOCKET_FORCE_BADVCC 0x0200 /* Bad Vcc Request */ + +#define PCCBB_SOCKET_CTRL_VPPMASK 0x07 +#define PCCBB_SOCKET_CTRL_VPP_OFF 0x00 +#define PCCBB_SOCKET_CTRL_VPP_12V 0x01 +#define PCCBB_SOCKET_CTRL_VPP_5V 0x02 +#define PCCBB_SOCKET_CTRL_VPP_3V 0x03 +#define PCCBB_SOCKET_CTRL_VPP_XV 0x04 +#define PCCBB_SOCKET_CTRL_VPP_YV 0x05 + +#define PCCBB_SOCKET_CTRL_VCCMASK 0x70 +#define PCCBB_SOCKET_CTRL_VCC_OFF 0x00 +#define PCCBB_SOCKET_CTRL_VCC_5V 0x20 +#define PCCBB_SOCKET_CTRL_VCC_3V 0x30 +#define PCCBB_SOCKET_CTRL_VCC_XV 0x40 +#define PCCBB_SOCKET_CTRL_VCC_YV 0x50 + +#define PCCBB_SOCKET_CTRL_STOPCLK 0x80 + + +/* Vendor/Device IDs */ +#define PCI_DEVICE_ID_PCIC_OZ6729 0x67291217ul +#define PCI_DEVICE_ID_PCIC_OZ6730 0x673A1217ul +#define PCI_DEVICE_ID_PCIC_CLPD6729 0x11001013ul +#define PCI_DEVICE_ID_PCIC_CLPD6832 0x11101013ul +#define PCI_DEVICE_ID_PCIC_CLPD6833 0x11131013ul +#define PCI_DEVICE_ID_PCIC_TI1130 0xac12104cul +#define PCI_DEVICE_ID_PCIC_TI1131 0xac15104cul +#define PCI_DEVICE_ID_PCIC_TI1211 0xac1e104cul +#define PCI_DEVICE_ID_PCIC_TI1220 0xac17104cul +#define PCI_DEVICE_ID_PCIC_TI1221 0xac19104cul +#define PCI_DEVICE_ID_PCIC_TI1225 0xac1c104cul +#define PCI_DEVICE_ID_PCIC_TI1250 0xac16104cul +#define PCI_DEVICE_ID_PCIC_TI1251 0xac1d104cul +#define PCI_DEVICE_ID_PCIC_TI1251B 0xac1f104cul +#define PCI_DEVICE_ID_PCIC_TI1410 0xac50104cul +#define PCI_DEVICE_ID_PCIC_TI1420 0xac51104cul +#define PCI_DEVICE_ID_PCIC_TI1450 0xac1b104cul +#define PCI_DEVICE_ID_PCIC_TI1451 0xac52104cul +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x06031179ul +#define PCI_DEVICE_ID_TOSHIBA_TOPIC95B 0x060a1179ul +#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f1179ul +#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x06171179ul +#define PCI_DEVICE_ID_RICOH_RL5C465 0x04651180ul +#define PCI_DEVICE_ID_RICOH_RL5C466 0x04661180ul +#define PCI_DEVICE_ID_RICOH_RL5C475 0x04751180ul +#define PCI_DEVICE_ID_RICOH_RL5C476 0x04761180ul +#define PCI_DEVICE_ID_RICOH_RL5C477 0x04771180ul +#define PCI_DEVICE_ID_RICOH_RL5C478 0x04781180ul diff --git a/sys/dev/pccbb/pccbbvar.h b/sys/dev/pccbb/pccbbvar.h new file mode 100644 index 000000000000..0a220464c445 --- /dev/null +++ b/sys/dev/pccbb/pccbbvar.h @@ -0,0 +1,105 @@ +/* + * 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$ + */ + +/* + * Structure definitions for the Cardbus Bridge driver + */ + +struct intrhand { + void(*func)(void*arg); + void* arg; + STAILQ_ENTRY(intrhand) entries; +}; + +struct pccbb_socketreg { + u_int32_t socket_event; + u_int32_t socket_mask; + u_int32_t socket_state; + u_int32_t socket_force; + u_int32_t socket_control; + u_int32_t socket_power; +}; + +struct pccbb_reslist { + SLIST_ENTRY(pccbb_reslist) entries; + int type; + int rid; + u_int32_t start; + u_int32_t end; + device_t odev; + int win; +}; + +#define PCCBB_AUTO_OPEN_SMALLHOLE 0x100 + +struct pccbb_softc { + device_t sc_dev; + struct resource *sc_base_res; + struct resource *sc_irq_res; + void *sc_intrhand; + struct pccbb_socketreg *sc_socketreg; + u_int32_t sc_flags; +#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 + int sc_chipset; /* chipset id */ +#define CB_UNKNOWN 0 /* NOT Cardbus-PCI bridge */ +#define CB_TI113X 1 /* TI PCI1130/1131 */ +#define CB_TI12XX 2 /* TI PCI1250/1220 */ +#define CB_RF5C47X 3 /* RICOH RF5C475/476/477 */ +#define CB_RF5C46X 4 /* RICOH RF5C465/466/467 */ +#define CB_TOPIC95 5 /* Toshiba ToPIC95 */ +#define CB_TOPIC95B 6 /* Toshiba ToPIC95B */ +#define CB_TOPIC97 7 /* Toshiba ToPIC97/100 */ +#define CB_CIRRUS 8 /* Cirrus Logic CLPD683x */ + SLIST_HEAD(, pccbb_reslist) rl; + + device_t sc_cbdev; + device_t sc_pccarddev; + + /* PC Card stuff */ + int memalloc; + struct pccard_mem_handle mem[PCIC_MEM_WINS]; + int ioalloc; + struct pccard_io_handle io[PCIC_IO_WINS]; + + /* kthread staff */ + struct proc *event_thread; +}; + +/* 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_END 0xEFFF +