diff options
author | jon <jon@FreeBSD.org> | 2000-10-18 03:25:13 +0000 |
---|---|---|
committer | jon <jon@FreeBSD.org> | 2000-10-18 03:25:13 +0000 |
commit | 9764ffea106deb99ec9392a8d9b44a6af00d0c83 (patch) | |
tree | de924ee3021db9fa3110892757126d60330b332c | |
parent | 8aa6837dc5073e0ff1bbc1f6fbdbf9a14c4444b0 (diff) | |
download | FreeBSD-src-9764ffea106deb99ec9392a8d9b44a6af00d0c83.zip FreeBSD-src-9764ffea106deb99ec9392a8d9b44a6af00d0c83.tar.gz |
Initial commit of NEWCARD cardbus side (that actually compiles and works)
Files:
dev/cardbus/cardbus.c
dev/cardbus/cardbusreg.h
dev/cardbus/cardbusvar.h
dev/cardbus/cardbus_cis.c
dev/cardbus/cardbus_cis.h
dev/pccbb/pccbb.c
dev/pccbb/pccbbreg.h
dev/pccbb/pccbbvar.h
dev/pccbb/pccbb_if.m
This should support:
- cardbus controllers:
* TI 113X
* TI 12XX
* TI 14XX
* Ricoh 47X
* Ricoh 46X
* ToPIC 95
* ToPIC 97
* ToPIC 100
* Cirrus Logic CLPD683x
- cardbus cards
* 3c575BT
* 3c575CT
* Xircom X3201 (includes IBM, Xircom and, Intel cards)
[ 3com support already in kernel, Xircom will be committed real soon now]
This doesn't work with 16bit pccards under NEWCARD.
Enable in your config by having "device pccbb" and "device cardbus".
(A "device pccard" will attach a pccard bus, but it means you system have
a high chance of panicing when a 16bit card is inserted)
It should be fairly simple to make a driver attach to cardbus under
NEWCARD -- simply add an entry for attaching to cardbus on a new
DRIVER_MODULE and add new device IDs as necessary. You should also make
sure the card can be detached nicely without the interrupt routine doing
something weird, like going into an infinite loop. Usually that should
entail adding an additional check when a pci register or the bus space is
read to check if it equals 0xffffffff.
Any problems, please let me know.
Reviewed by: imp
-rw-r--r-- | sys/conf/files | 7 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbus.c | 1198 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbus_cis.c | 477 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbus_cis.h | 99 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbusreg.h | 166 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbusvar.h | 193 | ||||
-rw-r--r-- | sys/dev/pccbb/pccbb.c | 1713 | ||||
-rw-r--r-- | sys/dev/pccbb/pccbb_if.m | 69 | ||||
-rw-r--r-- | sys/dev/pccbb/pccbbreg.h | 188 | ||||
-rw-r--r-- | sys/dev/pccbb/pccbbvar.h | 105 |
10 files changed, 3641 insertions, 574 deletions
diff --git a/sys/conf/files b/sys/conf/files index 22a2537..baec5aa 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 394f1c9..2d68310 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 <se@freebsd.org>) + * + * Written by Jonathan Chen <jon@freebsd.org> + */ + #define CARDBUS_DEBUG -#include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> -#include <sys/device.h> #include <sys/malloc.h> #include <sys/kernel.h> -#include <sys/syslog.h> +#include <sys/bus.h> #include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> -#include <dev/cardbus/pccardcis.h> +#include <pci/pcivar.h> +#include <pci/pcireg.h> +#include <sys/pciio.h> #include <dev/cardbus/cardbusreg.h> #include <dev/cardbus/cardbusvar.h> +#include <dev/cardbus/cardbus_cis.h> -#include <dev/pcmcia/pcmciareg.h> -#include <dev/pcmcia/pcmciavar.h> +#include "pccbb_if.h" +#include "card_if.h" +#include "pcib_if.h" -#include <dev/ic/i82365reg.h> -#include <dev/ic/i82365reg.h> - -#include <dev/pci/pccbbreg.h> -#include <dev/pci/pccbbvar.h> #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 cbslot_attach_args *cba = aux; - - /* which slot? */ - if (cf->cbslotcf_slot != CBSLOT_UNK_SLOT && - cf->cbslotcf_slot != cba->cba_function) { +struct cardbus_quirk cardbus_quirks[] = { + { 0 } +}; - DPRINTF(("cardbusmatch: function differs %d <=> %d\n", - cf->cbslotcf_slot, cba->cba_function)); +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) +{ + device_set_desc(dev, "Cardbus bus (newcard)"); return 0; - } +} - if (cba->cba_function < 0 || cba->cba_function > 255) { +static int +cardbus_attach(device_t dev) +{ return 0; - } - - return 1; } -void -cardslot_if_setup (struct cardbus_softc *csc) +/************************************************************************/ +/* Attach/Detach card */ +/************************************************************************/ + +static void +device_setup_regs(device_t bdev, int b, int s, int f, pcicfgregs *cfg) { - csc->sc_if.if_card_attach = cardbus_attach_card; + 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); + + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 0xa8, 1); + cfg->lattimer = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 1); + + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MINGNT, 0x14, 1); + cfg->mingnt = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MINGNT, 1); + + PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 0x14, 1); + cfg->maxlat = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 1); } -STATIC void -cardbusattach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +static int +cardbus_attach_card(device_t dev) { - 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); - } + device_t bdev = device_get_parent(dev); + int cdstatus; + int cardattached = 0; + static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ + int bus, slot, func; + + /* inspect initial voltage */ + if (0 == (cdstatus = PCCBB_DETECT_CARD(bdev))) { + DEVPRINTF((dev, "cardbusattach: no CardBus card detected\n")); + return ENXIO; + } + + if (cdstatus & CARD_3V_CARD) { + PCCBB_POWER_SOCKET(bdev, CARD_VCC_3V); + } else { + device_printf(dev, "unsupported power: %d\n", cdstatus); + return EINVAL; + } + PCCBB_RESET(bdev); + + 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; } -/********************************************************************** -* 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; +static int +cardbus_detach_card(device_t dev, int flags) { - 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; - } + int numdevs; + device_t *devlist; + int tmp; + int err=0; + + device_get_children(dev, &devlist, &numdevs); - if (cdstatus & CARDBUS_3V_CARD) { - cf->cardbus_power(cc, CARDBUS_VCC_3V); - } - (cf->cardbus_ctrl)(cc, CARDBUS_RESET); + if (numdevs == 0) { + DEVPRINTF((dev, "Detaching card: no cards to detach!\n")); + return ENOENT; + } - device = 0; /* Only one card can attach cardbus slot */ - function = 0; + 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; +} - tag = cardbus_make_tag (cc, cf, sc->sc_bus, device, function); +/************************************************************************/ +/* PCI-Like config reading (copied from pci.c */ +/************************************************************************/ - bhlcr = (cf->cardbus_conf_read)(cc, tag, CARDBUS_BHLC_REG); - max_func = CARDBUS_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; +/* read configuration header into pcicfgrect structure */ - for (function = 0; function < max_func; function++) { - if (function) - tag = cardbus_make_tag (cc, cf, sc->sc_bus, device, function); +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 - 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; +#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 +} - 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; - } - } +/* read config data specific to header type 1 device (PCI to PCI bridge) */ - decode_tuples(tuple, 2048); - if (function == 0) { - struct cardbus_attach_args ca; - cardbusreg_t intr = cardbus_conf_read(cc, cf, tag, CARDBUS_INTERRUPT_REG); +static void * +cardbus_readppb(device_t pcib, int b, int s, int f) +{ + pcih1cfgregs *p; - ca.ca_unit = sc->sc_dev.dv_unit; - ca.ca_cc = sc->sc_cc; - ca.ca_cf = sc->sc_cf; + p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); - ca.ca_iot = sc->sc_iot; - ca.ca_memt = sc->sc_memt; - ca.ca_dmat = sc->sc_dmat; + bzero(p, sizeof *p); - ca.ca_tag = tag; - ca.ca_device = device; - ca.ca_function = function; - ca.ca_id = id; - ca.ca_class = class; + 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); - ca.ca_intrline = sc->sc_intrline; + p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_1, 1); - attached_device = config_found_sm((void *)sc, &ca, cardbusprint, cardbussubmatch); - } else { - printf ("cardbus_attach_card: XXX Multi-function can't handle. function 0 only.\n"); + 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; } - cardbus_free_tag (cc, cf, tag); - } - if (!attached_device) - cf->cardbus_power(cc, CARDBUS_VCC_0V); - return attached_device; +#undef REG } +/* free pcicfgregs structure and all depending data structures */ + static int -cardbussubmatch(parent, cf, aux) - struct device *parent; - struct cfdata *cf; - void *aux; +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) { - struct cardbus_attach_args *ca = aux; + 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 */ +/************************************************************************/ - if (cf->cardbuscf_dev != CARDBUS_UNK_DEV && - cf->cardbuscf_dev != ca->ca_unit) { +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; - } - if (cf->cardbuscf_function != CARDBUS_UNK_FUNCTION && - cf->cardbuscf_function != ca->ca_function) { +} + +static int +cardbus_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) +{ + 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; - } +} - return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +static void +cardbus_delete_resource(device_t dev, device_t child, int type, int rid) +{ + 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); + } + if (device_get_parent(child) == dev) + pci_write_config(child, rid, 0, 4); } static int -cardbusprint(aux, pnp) - void *aux; - const char *pnp; +cardbus_set_resource_method(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) { - 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; + 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); } -/********************************************************************** -* 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; +static int +cardbus_get_resource_method(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - DPRINTF(("- cardbus_intr_establish: irq %d\n", irq)); + 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); +} - return (*cf->cardbus_intr_establish)(cc, irq, level, func, arg); +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); } -/********************************************************************** -* 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; +static void +cardbus_add_map(device_t cbdev, device_t dev, pcicfgregs *cfg, int reg) { - DPRINTF(("- cardbus_intr_disestablish\n")); + 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); + } +} - (*cf->cardbus_intr_disestablish)(cc, handler); - return; +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; + } + } } -/********************************************************************** -* 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; +cardbus_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) { - u_int8_t *tp = tuple; + return bus_deactivate_resource(child, type, rid, r); +} - if (CISTPL_LINKTARGET != *tuple) { - DPRINTF(("WRONG TUPLE\n")); - return 0; - } +/************************************************************************/ +/* Other Bus Methods */ +/************************************************************************/ - while (NULL != (tp = decode_tuple(tp))) { - if (tuple + buflen < tp) { - break; +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 1; + return retval; } -static u_int8_t * -decode_tuple(tuple) - u_int8_t *tuple; +static int +cardbus_print_child(device_t dev, device_t child) { - u_int8_t type; - u_int8_t len; - int i; + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + pcicfgregs *cfg; + int retval = 0; - type = tuple[0]; - len = tuple[1] + 2; + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + rl = &dinfo->resources; - printf("tuple: %s len %d\n", tuple_name(type), len); - if (CISTPL_END == type) { - return NULL; - } + retval += bus_print_child_header(dev, child); - for (i = 0; i < len; ++i) { - if (i % 16 == 0) { - printf(" 0x%2x:", i); - } - printf(" %x",tuple[i]); - if (i % 16 == 15) { - printf("\n"); + 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, "<unknown card>"); + 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])) - - if (type > 0 && type < NAME_LEN(tuple_name_s)) { - return tuple_name_s[type]; - } else if (0xff == type) { - return "END"; - } else { - return "Reserved"; - } + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + 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 0000000..f6565ec --- /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 <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <pci/pcivar.h> + +#include <dev/cardbus/cardbusreg.h> +#include <dev/cardbus/cardbus_cis.h> + +#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 0000000..3edacc4 --- /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 56e2e56..df5bb18 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) - - -#define CARDBUS_COMMAND_STATUS_REG 0x04 - -# define CARDBUS_COMMAND_IO_ENABLE 0x00000001 -# define CARDBUS_COMMAND_MEM_ENABLE 0x00000002 -# define CARDBUS_COMMAND_MASTER_ENABLE 0x00000004 - - -#define CARDBUS_CLASS_REG 0x08 - -/* 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 +/* + * Register definitions for the Cardbus Bus + */ -#define CARDBUS_INTERRUPT_REG 0x3c +/* Cardbus bus constants */ +#define CARDBUS_SLOTMAX 0 +#define CARDBUS_FUNCMAX 7 + +/* 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_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 */ + +/* 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 2f91141..a94cd99 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 <pci/pcivar.h> /* XXX */ -typedef pcitag_t cardbustag_t; /* XXX */ - -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 */ -}; - -#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; +/* + * Structure definitions for the Cardbus Bus driver + */ - /* interrupt information */ - cardbus_intr_line_t ca_intrline; +struct cardbus_devinfo { + struct resource_list resources; + pcicfgregs cfg; + struct pci_conf conf; }; - - -#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 0000000..8f9e7ed --- /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 <jon@freebsd.org> + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/malloc.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> +#include <machine/clock.h> + +#include <dev/pccard/pccardreg.h> +#include <dev/pccard/pccardvar.h> +#include <dev/pcic/i82365reg.h> + +#include <dev/pccbb/pccbbreg.h> +#include <dev/pccbb/pccbbvar.h> + +#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 0000000..2f3ddd3 --- /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 <sys/bus.h> + +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 0000000..9758335 --- /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 0000000..0a22046 --- /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 + |