diff options
author | imp <imp@FreeBSD.org> | 2005-09-25 21:29:32 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2005-09-25 21:29:32 +0000 |
commit | add8494ccf5a9aa94810202202861f80378b7d2e (patch) | |
tree | 58cc7567434699af9d901ac0a0ab8c262f3b1f22 | |
parent | 7844c3547462f26592f7a7a3a00ee89693fa5862 (diff) | |
download | FreeBSD-src-add8494ccf5a9aa94810202202861f80378b7d2e.zip FreeBSD-src-add8494ccf5a9aa94810202202861f80378b7d2e.tar.gz |
Remove the kernel portion of OLDCARD. I'm working on a replacement
for pccardc dumpcis, but until I'm done with that, I'm leaving pccardc
in place. As such, I'm leaving the .h files in place for the moment.
-rw-r--r-- | sys/pccard/mecia.c | 767 | ||||
-rw-r--r-- | sys/pccard/pccard.c | 731 | ||||
-rw-r--r-- | sys/pccard/pccard_beep.c | 138 | ||||
-rw-r--r-- | sys/pccard/pccard_nbk.c | 436 | ||||
-rw-r--r-- | sys/pccard/pcic.c | 1344 | ||||
-rw-r--r-- | sys/pccard/pcic_isa.c | 399 | ||||
-rw-r--r-- | sys/pccard/pcic_pci.c | 1586 |
7 files changed, 0 insertions, 5401 deletions
diff --git a/sys/pccard/mecia.c b/sys/pccard/mecia.c deleted file mode 100644 index ce0b756..0000000 --- a/sys/pccard/mecia.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * NEC MECIA controller. - *------------------------------------------------------------------------- - */ -/*- - * Copyright (c) 2001 M. Warner Losh. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - * - * Based heavily on the FreeBSD pcic driver's pcic98 support, derived - * from PAO3 tree. This copyright notice likely needs modification for - * such a linage. The only authorship I could find was: - * - * PC9801 original PCMCIA controller code for NS/A,Ne,NX/C,NR/L. - * by Noriyuki Hosobuchi <hoso@ce.mbn.or.jp> - */ - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> - -#include <pccard/meciareg.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> -#ifndef MECIA_IOBASE -#define MECIA_IOBASE 0x80d0 -#endif - -/* Get pnp IDs */ -#include <isa/isavar.h> - -#include <dev/pccard/pccardvar.h> -#include "card_if.h" - -#define MECIA_DEVICE2SOFTC(dev) ((struct mecia_slot *) device_get_softc(dev)) - -/* - * Prototypes for interrupt handler. - */ -static driver_intr_t meciaintr; -static int mecia_ioctl(struct slot *, int, caddr_t); -static int mecia_power(struct slot *); -static void mecia_mapirq(struct slot *, int); -static timeout_t mecia_reset; -static void mecia_resume(struct slot *); -static void mecia_disable(struct slot *); -static timeout_t meciatimeout; -static struct callout_handle meciatimeout_ch - = CALLOUT_HANDLE_INITIALIZER(&meciatimeout_ch); -static int mecia_memory(struct slot *, int); -static int mecia_io(struct slot *, int); - -/* - * Per-slot data table. - */ -struct mecia_slot { - int unit; /* Unit number */ - int slotnum; /* My slot number */ - struct slot *slt; /* Back ptr to slot */ - device_t dev; /* My device */ - u_char last_reg1; /* Last value of change reg */ -}; - -static struct slot_ctrl mecia_cinfo = { - mecia_mapirq, - mecia_memory, - mecia_io, - mecia_reset, - mecia_disable, - mecia_power, - mecia_ioctl, - mecia_resume, - 1, -#if 0 - 1 -#else - 2 /* Fake for UE2212 LAN card */ -#endif -}; - -static int validunits = 0; - -/* - * Look for an NEC MECIA. - * For each available slot, allocate a PC-CARD slot. - */ - -static int -mecia_probe(device_t dev) -{ - int validslots = 0; - - /* Check isapnp ids */ - if (isa_get_logicalid(dev)) /* skip PnP probes */ - return (ENXIO); - - if (inb(MECIA_REG0) != 0xff) { - validslots++; - /* XXX need to allocated the port resources */ - device_set_desc(dev, "MECIA PC98 Original PCMCIA Controller"); - } - return (validslots ? 0 : ENXIO); -} - -static int -mecia_attach(device_t dev) -{ - int error; - int irq; - void *ih; - device_t kid; - struct resource *r; - int rid; - struct slot *slt; - struct mecia_slot *sp; - - sp = MECIA_DEVICE2SOFTC(dev); - sp->unit = validunits++; - kid = device_add_child(dev, NULL, -1); - if (kid == NULL) { - device_printf(dev, "Can't add pccard bus slot 0\n"); - return (ENXIO); - } - device_probe_and_attach(kid); - slt = pccard_init_slot(kid, &mecia_cinfo); - if (slt == 0) { - device_printf(dev, "Can't get pccard info slot 0\n"); - return (ENXIO); - } - slt->cdata = sp; - sp->slt = slt; - validunits++; - - rid = 0; - r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); - if (!r) - return (ENXIO); - - irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0); - if (irq == 0) { - /* See if the user has requested a specific IRQ */ - if (!getenv_int("machdep.pccard.mecia_irq", &irq)) - irq = 0; - } - rid = 0; - r = 0; - if (irq > 0) { - r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, - irq, 1, RF_ACTIVE); - } - if (r && ((1 << (rman_get_start(r))) & MECIA_INT_MASK_ALLOWED) == 0) { - device_printf(dev, - "Hardware does not support irq %d, trying polling.\n", - irq); - bus_release_resource(dev, SYS_RES_IRQ, rid, r); - r = 0; - irq = 0; - } - if (r) { - error = bus_setup_intr(dev, r, INTR_TYPE_MISC, - meciaintr, (void *) sp, &ih); - if (error) { - bus_release_resource(dev, SYS_RES_IRQ, rid, r); - return (error); - } - irq = rman_get_start(r); - device_printf(dev, "management irq %d\n", irq); - } else { - irq = 0; - } - if (irq == 0) { - meciatimeout_ch = timeout(meciatimeout, (void *) sp, hz/2); - device_printf(dev, "Polling mode\n"); - } - - sp->last_reg1 = inb(MECIA_REG1); - if (sp->last_reg1 & MECIA_CARDEXIST) { - /* PCMCIA card exist */ - sp->slt->laststate = sp->slt->state = filled; - pccard_event(sp->slt, card_inserted); - } else { - sp->slt->laststate = sp->slt->state = empty; - } - sp->slt->irq = irq; - - return (bus_generic_attach(dev)); -} - -static int -mecia_sresource(struct slot *slt, caddr_t data) -{ - struct pccard_resource *pr; - struct resource *r; - int flags; - int rid = 0; - device_t pccarddev = slt->dev; - - pr = (struct pccard_resource *)data; - pr->resource_addr = ~0ul; - switch(pr->type) { - default: - return (EINVAL); - case SYS_RES_MEMORY: - case SYS_RES_IRQ: - case SYS_RES_IOPORT: - break; - } - flags = rman_make_alignment_flags(pr->size); - r = bus_alloc_resource(pccarddev, pr->type, &rid, pr->min, pr->max, - pr->size, flags); - if (r != NULL) { - pr->resource_addr = (u_long)rman_get_start(r); - bus_release_resource(bridgedev, pr->type, rid, r); - } - return (0); -} - -/* - * ioctl calls - Controller specific ioctls - */ -static int -mecia_ioctl(struct slot *slt, int cmd, caddr_t data) -{ - switch(cmd) { - default: - return (ENOTTY); - case PIOCSRESOURCE: /* Can I use this resource? */ - mecia_sresource(slt, data); - break; - } - return (0); -} - -/* - * MECIA timer. If the controller doesn't have a free IRQ to use - * or if interrupt steering doesn't work, poll the controller for - * insertion/removal events. - */ -static void -meciatimeout(void *chan) -{ - meciaintr(chan); - meciatimeout_ch = timeout(meciatimeout, chan, hz/2); -} - -/* - * MECIA Interrupt handler. - * Check the slot and report any changes. - */ -static void -meciaintr(void *arg) -{ - u_char reg1; - int s; - struct mecia_slot *sp = (struct mecia_slot *) arg; - - s = splhigh(); - /* Check for a card in this slot */ - reg1 = inb(MECIA_REG1); - if ((sp->last_reg1 ^ reg1) & MECIA_CARDEXIST) { - sp->last_reg1 = reg1; - if (reg1 & MECIA_CARDEXIST) - pccard_event(sp->slt, card_inserted); - else - pccard_event(sp->slt, card_removed); - } - splx(s); -} - -/* - * local functions for PC-98 Original PC-Card controller - */ -#define MECIA_ALWAYS_128MAPPING 1 /* trick for using UE2212 */ - -int mecia_mode = 0; /* almost the same as the value in MECIA_REG2 */ - -static unsigned char reg_winsel = MECIA_UNMAPWIN; -static unsigned short reg_pagofs = 0; - -static int -mecia_memory(struct slot *slt, int win) -{ - struct mem_desc *mp = &slt->mem[win]; - unsigned char x; - - if (mp->flags & MDF_ACTIVE) { - /* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */ - if ((unsigned long)mp->start != 0xda000) { - printf( - "sys_addr must be 0xda000. requested address = %p\n", - mp->start); - return (EINVAL); - } - - /* omajinai ??? */ - outb(MECIA_REG0, 0); - x = inb(MECIA_REG1); - x &= 0xfc; - x |= 0x02; - outb(MECIA_REG1, x); - reg_winsel = inb(MECIA_REG_WINSEL); - reg_pagofs = inw(MECIA_REG_PAGOFS); - outb(MECIA_REG_WINSEL, MECIA_MAPWIN); - outw(MECIA_REG_PAGOFS, (mp->card >> 13)); /* 8KB */ - - if (mp->flags & MDF_ATTR) - outb(MECIA_REG7, inb(MECIA_REG7) | MECIA_ATTRMEM); - else - outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_ATTRMEM)); - - outb(MECIA_REG_WINSEL, MECIA_MAPWIN); -#if 0 - if ((mp->flags & MDF_16BITS) == 1) /* 16bit */ - outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_8BIT)); - else /* 8bit */ - outb(MECIA_REG2, inb(MECIA_REG2) | MECIA_8BIT); -#endif - } else { /* !(mp->flags & MDF_ACTIVE) */ - outb(MECIA_REG0, 0); - x = inb(MECIA_REG1); - x &= 0xfc; - x |= 0x02; - outb(MECIA_REG1, x); -#if 0 - outb(MECIA_REG_WINSEL, MECIA_UNMAPWIN); - outw(MECIA_REG_PAGOFS, 0); -#else - outb(MECIA_REG_WINSEL, reg_winsel); - outw(MECIA_REG_PAGOFS, reg_pagofs); -#endif - } - return (0); -} - -static int -mecia_io(struct slot *slt, int win) -{ - struct io_desc *ip = &slt->io[win]; - unsigned char x; - unsigned short cardbase; - u_short ofst; - - if (win != 0) { - /* ignore for UE2212 */ - printf( - "mecia:Illegal MECIA I/O window(%d) request! Ignored.\n", win); -/* return (EINVAL);*/ - return (0); - } - - if (ip->flags & IODF_ACTIVE) { - x = inb(MECIA_REG2) & 0x0f; -#if 0 - if (! (ip->flags & IODF_CS16)) - x |= MECIA_8BIT; -#else - if (! (ip->flags & IODF_16BIT)) { - x |= MECIA_8BIT; - mecia_mode |= MECIA_8BIT; - } -#endif - - ofst = ip->start & 0xf; - cardbase = ip->start & ~0xf; -#ifndef MECIA_ALWAYS_128MAPPING - if (ip->size + ofst > 16) -#endif - { /* 128bytes mapping */ - x |= MECIA_MAP128; - mecia_mode |= MECIA_MAP128; - ofst |= ((cardbase & 0x70) << 4); - cardbase &= ~0x70; - } - - x |= MECIA_MAPIO; - outb(MECIA_REG2, x); - - outw(MECIA_REG4, MECIA_IOBASE); /* 98side I/O base */ - outw(MECIA_REG5, cardbase); /* card side I/O base */ - - if (bootverbose) { - printf("mecia: I/O mapped 0x%04x(98) -> " - "0x%04x(Card) and width %d bytes\n", - MECIA_IOBASE+ofst, ip->start, ip->size); - printf("mecia: reg2=0x%02x reg3=0x%02x reg7=0x%02x\n", - inb(MECIA_REG2), inb(MECIA_REG3), - inb(MECIA_REG7)); - printf("mecia: mode=%d\n", mecia_mode); - } - - ip->start = MECIA_IOBASE + ofst; - } else { - outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO)); - mecia_mode = 0; - } - return (0); -} - -static int -mecia_power(struct slot *slt) -{ - unsigned char reg; - - reg = inb(MECIA_REG7) & (~MECIA_VPP12V); - switch(slt->pwr.vpp) { - default: - return (EINVAL); - case 50: - break; - case 120: - reg |= MECIA_VPP12V; - break; - } - outb(MECIA_REG7, reg); - DELAY(100*1000); - - reg = inb(MECIA_REG2) & (~MECIA_VCC3P3V); - switch(slt->pwr.vcc) { - default: - return (EINVAL); - case 33: - reg |= MECIA_VCC3P3V; - break; - case 50: - break; - } - outb(MECIA_REG2, reg); - DELAY(100*1000); - return (0); -} - -static void -mecia_mapirq(struct slot *slt, int irq) -{ - u_char x; - - switch (irq) { - case 3: - x = MECIA_INT0; - break; - case 5: - x = MECIA_INT1; - break; - case 6: - x = MECIA_INT2; - break; - case 10: - x = MECIA_INT4; - break; - case 12: - x = MECIA_INT5; - break; - case 0: /* disable */ - x = MECIA_INTDISABLE; - break; - default: - printf("mecia: illegal irq %d\n", irq); - return; - } -#ifdef MECIA_DEBUG - printf("mecia: irq=%d mapped.\n", irq); -#endif - outb(MECIA_REG3, x); -} - -static void -mecia_reset(void *chan) -{ - struct slot *slt = chan; - - outb(MECIA_REG0, 0); - outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_MAPIO)); - outb(MECIA_REG3, MECIA_INTDISABLE); -#if 0 -/* mecia_reset() is called after mecia_power() */ - outb(MECIA_REG2, inb(MECIA_REG2) & (~MECIA_VCC3P3V)); - outb(MECIA_REG7, inb(MECIA_REG7) & (~MECIA_VPP12V)); -#endif - outb(MECIA_REG1, 0); - - selwakeuppri(&slt->selp, PZERO); -} - -static void -mecia_disable(struct slot *slt) -{ - /* null function */ -} - -static void -mecia_resume(struct slot *slt) -{ - /* XXX MECIA How ? */ -} - -static int -mecia_activate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) - return (bus_generic_activate_resource(dev, child, type, - rid, r)); - - switch (type) { - case SYS_RES_IOPORT: { - struct io_desc *ip; - ip = &devi->slt->io[rid]; - if (ip->flags == 0) { - if (rid == 0) - ip->flags = IODF_WS | IODF_16BIT | IODF_CS16; - else - ip->flags = devi->slt->io[0].flags; - } - ip->flags |= IODF_ACTIVE; - ip->start = rman_get_start(r); - ip->size = rman_get_end(r) - rman_get_start(r) + 1; - err = mecia_cinfo.mapio(devi->slt, rid); - if (err) - return (err); - break; - } - case SYS_RES_IRQ: - /* - * We actually defer the activation of the IRQ resource - * until the interrupt is registered to avoid stray - * interrupt messages. - */ - break; - case SYS_RES_MEMORY: { - struct mem_desc *mp; - if (rid >= NUM_MEM_WINDOWS) - return (EINVAL); - mp = &devi->slt->mem[rid]; - mp->flags |= MDF_ACTIVE; - mp->start = (caddr_t) rman_get_start(r); - mp->size = rman_get_end(r) - rman_get_start(r) + 1; - err = mecia_cinfo.mapmem(devi->slt, rid); - if (err) - return (err); - break; - } - default: - break; - } - err = bus_generic_activate_resource(dev, child, type, rid, r); - return (err); -} - -static int -mecia_deactivate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) - return (bus_generic_deactivate_resource(dev, child, type, - rid, r)); - - switch (type) { - case SYS_RES_IOPORT: { - struct io_desc *ip = &devi->slt->io[rid]; - ip->flags &= ~IODF_ACTIVE; - err = mecia_cinfo.mapio(devi->slt, rid); - if (err) - return (err); - break; - } - case SYS_RES_IRQ: - break; - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - mp->flags &= ~(MDF_ACTIVE | MDF_ATTR); - err = mecia_cinfo.mapmem(devi->slt, rid); - if (err) - return (err); - break; - } - default: - break; - } - err = bus_generic_deactivate_resource(dev, child, type, rid, r); - return (err); -} - -static int -mecia_setup_intr(device_t dev, device_t child, struct resource *irq, - int flags, driver_intr_t *intr, void *arg, void **cookiep) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (((1 << rman_get_start(irq)) & MECIA_INT_MASK_ALLOWED) == 0) { - device_printf(dev, "Hardware does not support irq %ld.\n", - rman_get_start(irq)); - return (EINVAL); - } - - err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg, - cookiep); - if (err == 0) - mecia_cinfo.mapirq(devi->slt, rman_get_start(irq)); - else - device_printf(dev, "Error %d irq %ld\n", err, - rman_get_start(irq)); - return (err); -} - -static int -mecia_teardown_intr(device_t dev, device_t child, struct resource *irq, - void *cookie) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - - mecia_cinfo.mapirq(devi->slt, 0); - return (bus_generic_teardown_intr(dev, child, irq, cookie)); -} - -static int -mecia_set_res_flags(device_t bus, device_t child, int restype, int rid, - u_long value) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err = 0; - - switch (restype) { - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - switch (value) { - case PCCARD_A_MEM_COM: - mp->flags &= ~MDF_ATTR; - break; - case PCCARD_A_MEM_ATTR: - mp->flags |= MDF_ATTR; - break; - case PCCARD_A_MEM_8BIT: - mp->flags &= ~MDF_16BITS; - break; - case PCCARD_A_MEM_16BIT: - mp->flags |= MDF_16BITS; - break; - } - err = mecia_cinfo.mapmem(devi->slt, rid); - break; - } - default: - err = EOPNOTSUPP; - } - return (err); -} - -static int -mecia_get_res_flags(device_t bus, device_t child, int restype, int rid, - u_long *value) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err = 0; - - if (value == 0) - return (ENOMEM); - - switch (restype) { - case SYS_RES_IOPORT: { - struct io_desc *ip = &devi->slt->io[rid]; - *value = ip->flags; - break; - } - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - *value = mp->flags; - break; - } - default: - err = EOPNOTSUPP; - } - return (err); -} - -static int -mecia_set_memory_offset(device_t bus, device_t child, int rid, - u_int32_t offset, u_int32_t *deltap) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - struct mem_desc *mp = &devi->slt->mem[rid]; - - mp->card = offset; - if (deltap) - *deltap = 0; /* XXX BAD XXX */ - return (mecia_cinfo.mapmem(devi->slt, rid)); -} - -static int -mecia_get_memory_offset(device_t bus, device_t child, int rid, - u_int32_t *offset) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - struct mem_desc *mp = &devi->slt->mem[rid]; - - if (offset == 0) - return (ENOMEM); - - *offset = mp->card; - - return (0); -} - -static device_method_t mecia_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, mecia_probe), - DEVMETHOD(device_attach, mecia_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, bus_generic_print_child), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, mecia_activate_resource), - DEVMETHOD(bus_deactivate_resource, mecia_deactivate_resource), - DEVMETHOD(bus_setup_intr, mecia_setup_intr), - DEVMETHOD(bus_teardown_intr, mecia_teardown_intr), - - /* Card interface */ - DEVMETHOD(card_set_res_flags, mecia_set_res_flags), - DEVMETHOD(card_get_res_flags, mecia_get_res_flags), - DEVMETHOD(card_set_memory_offset, mecia_set_memory_offset), - DEVMETHOD(card_get_memory_offset, mecia_get_memory_offset), - - { 0, 0 } -}; - -devclass_t mecia_devclass; - -static driver_t mecia_driver = { - "mecia", - mecia_methods, - sizeof(struct mecia_slot) -}; - -DRIVER_MODULE(mecia, isa, mecia_driver, mecia_devclass, 0, 0); diff --git a/sys/pccard/pccard.c b/sys/pccard/pccard.c deleted file mode 100644 index b8ebea9..0000000 --- a/sys/pccard/pccard.c +++ /dev/null @@ -1,731 +0,0 @@ -/* - * pccard.c - Interface code for PC-CARD controllers. - * - * June 1995, Andrew McRae (andrew@mega.com.au) - *------------------------------------------------------------------------- - */ -/*- - * Copyright (c) 2001 M. Warner Losh. All rights reserved. - * Copyright (c) 1995 Andrew McRae. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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$ - */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/sysctl.h> -#include <sys/conf.h> -#include <sys/uio.h> -#include <sys/poll.h> -#include <sys/bus.h> -#include <sys/proc.h> -#include <machine/bus.h> - -#include <pccard/cardinfo.h> -#include <pccard/driver.h> -#include <pccard/slot.h> -#include <pccard/pccard_nbk.h> - -#include <machine/md_var.h> - -static int allocate_driver(struct slot *, struct dev_desc *); -static void inserted(void *); -static void disable_slot(struct slot *); -static void disable_slot_to(struct slot *); -static void power_off_slot(void *); - -/* - * The driver interface for read/write uses a block - * of memory in the ISA I/O memory space allocated via - * an ioctl setting. - * - * Now that we have different bus attachments, we should really - * use a better algorythm to allocate memory. - */ -static unsigned long pccard_mem; /* Physical memory */ -static unsigned char *pccard_kmem; /* Kernel virtual address */ -static struct resource *pccard_mem_res; -static int pccard_mem_rid; - -static d_open_t crdopen; -static d_close_t crdclose; -static d_read_t crdread; -static d_write_t crdwrite; -static d_ioctl_t crdioctl; -static d_poll_t crdpoll; - -static struct cdevsw crd_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = crdopen, - .d_close = crdclose, - .d_read = crdread, - .d_write = crdwrite, - .d_ioctl = crdioctl, - .d_poll = crdpoll, - .d_name = "crd", -}; - -/* - * Power off the slot. - * (doing it immediately makes the removal of some cards unstable) - */ -static void -power_off_slot(void *arg) -{ - struct slot *slt = (struct slot *)arg; - int s; - - /* - * The following will generate an interrupt. So, to hold off - * the interrupt unitl after disable runs so that we can get rid - * rid of the interrupt before it becomes unsafe to touch the - * device. - * - * XXX In current, the spl stuff is a nop. - */ - s = splhigh(); - /* Power off the slot. */ - slt->pwr_off_pending = 0; - slt->ctrl->disable(slt); - splx(s); -} - -/* - * disable_slot - Disables the slot by removing - * the power and unmapping the I/O - */ -static void -disable_slot(struct slot *slt) -{ - device_t pccarddev; - device_t *kids; - int nkids; - int i; - int ret; - - /* - * Note that a race condition is possible here; if a - * driver is accessing the device and it is removed, then - * all bets are off... - */ - pccarddev = slt->dev; - device_get_children(pccarddev, &kids, &nkids); - for (i = 0; i < nkids; i++) { - if ((ret = device_delete_child(pccarddev, kids[i])) != 0) - printf("pccard: delete of %s failed: %d\n", - device_get_nameunit(kids[i]), ret); - } - free(kids, M_TEMP); - - /* Power off the slot 1/2 second after removal of the card */ - slt->poff_ch = timeout(power_off_slot, (caddr_t)slt, hz / 2); - slt->pwr_off_pending = 1; -} - -static void -disable_slot_to(struct slot *slt) -{ - disable_slot(slt); - if (slt->state == empty) - printf("pccard: card removed, slot %d\n", slt->slotnum); - else - printf("pccard: card deactivated, slot %d\n", slt->slotnum); - pccard_remove_beep(); - selwakeuppri(&slt->selp, PZERO); -} - -/* - * pccard_init_slot - Initialize the slot controller and attach various - * things to it. We also make the device for it. We create the device that - * will be exported to devfs. - */ -struct slot * -pccard_init_slot(device_t dev, struct slot_ctrl *ctrl) -{ - int slotno; - struct slot *slt; - - slt = PCCARD_DEVICE2SOFTC(dev); - slotno = device_get_unit(dev); - slt->dev = dev; - slt->d = make_dev(&crd_cdevsw, slotno, 0, 0, 0600, "card%d", slotno); - slt->d->si_drv1 = slt; - slt->ctrl = ctrl; - slt->slotnum = slotno; - callout_handle_init(&slt->insert_ch); - callout_handle_init(&slt->poff_ch); - - return (slt); -} - -/* - * allocate_driver - Create a new device entry for this - * slot, and attach a driver to it. - */ -static int -allocate_driver(struct slot *slt, struct dev_desc *desc) -{ - struct pccard_devinfo *devi; - device_t pccarddev; - int err, irq = 0; - device_t child; - device_t *devs; - int count; - - pccarddev = slt->dev; - err = device_get_children(pccarddev, &devs, &count); - if (err != 0) - return (err); - free(devs, M_TEMP); - if (count) { - device_printf(pccarddev, - "Can not attach more than one child.\n"); - return (EIO); - } - irq = ffs(desc->irqmask) - 1; - MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF, - M_WAITOK | M_ZERO); - strcpy(devi->name, desc->name); - /* - * Create an entry for the device under this slot. - */ - devi->running = 1; - devi->slt = slt; - bcopy(desc->misc, devi->misc, sizeof(desc->misc)); - strcpy(devi->manufstr, desc->manufstr); - strcpy(devi->versstr, desc->versstr); - strcpy(devi->cis3str, desc->cis3str); - strcpy(devi->cis4str, desc->cis4str); - devi->manufacturer = desc->manufacturer; - devi->product = desc->product; - devi->prodext = desc->prodext; - resource_list_init(&devi->resources); - child = device_add_child(pccarddev, devi->name, desc->unit); - if (child == NULL) { - if (desc->unit != -1) - device_printf(pccarddev, - "Unit %d failed for %s, try a different unit\n", - desc->unit, devi->name); - else - device_printf(pccarddev, - "No units available for %s. Impossible?\n", - devi->name); - return (EIO); - } - device_set_flags(child, desc->flags); - device_set_ivars(child, devi); - if (bootverbose) { - device_printf(pccarddev, "Assigning %s:", - device_get_nameunit(child)); - if (desc->iobase) - printf(" io 0x%x-0x%x", - desc->iobase, desc->iobase + desc->iosize - 1); - if (irq) - printf(" irq %d", irq); - if (desc->mem) - printf(" mem 0x%lx-0x%lx", desc->mem, - desc->mem + desc->memsize - 1); - printf(" flags 0x%x\n", desc->flags); - } - err = bus_set_resource(child, SYS_RES_IOPORT, 0, desc->iobase, - desc->iosize); - if (err) - goto err; - if (irq) - err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); - if (err) - goto err; - if (desc->memsize) { - err = bus_set_resource(child, SYS_RES_MEMORY, 0, desc->mem, - desc->memsize); - if (err) - goto err; - } - err = device_probe_and_attach(child); - /* - * XXX We unwisely assume that the detach code won't run while the - * XXX the attach code is attaching. Someone should put some - * XXX interlock code. This can happen if probe/attach takes a while - * XXX and the user ejects the card, which causes the detach - * XXX function to be called. - */ - strncpy(desc->name, device_get_nameunit(child), sizeof(desc->name)); - desc->name[sizeof(desc->name) - 1] = '\0'; -err: - if (err) - device_delete_child(pccarddev, child); - return (err); -} - -/* - * card insert routine - Called from a timeout to debounce - * insertion events. - */ -static void -inserted(void *arg) -{ - struct slot *slt = arg; - - slt->state = filled; - /* - * Disable any pending timeouts for this slot, and explicitly - * power it off right now. Then, re-enable the power using - * the (possibly new) power settings. - */ - untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch); - power_off_slot(slt); - - /* - * Enable 5V to the card so that the CIS can be read. Well, - * enable the most natural voltage so that the CIS can be read. - */ - slt->pwr.vcc = -1; - slt->pwr.vpp = -1; - slt->ctrl->power(slt); - - printf("pccard: card inserted, slot %d\n", slt->slotnum); - pccard_insert_beep(); - slt->ctrl->reset(slt); -} - -/* - * Card event callback. Called at splhigh to prevent - * device interrupts from interceding. - */ -void -pccard_event(struct slot *slt, enum card_event event) -{ - if (slt->insert_seq) { - slt->insert_seq = 0; - untimeout(inserted, (void *)slt, slt->insert_ch); - } - - switch(event) { - case card_removed: - case card_deactivated: - if (slt->state == filled || slt->state == inactive) { - if (event == card_removed) - slt->state = empty; - else - slt->state = inactive; - disable_slot_to(slt); - } - break; - case card_inserted: - slt->insert_seq = 1; - slt->insert_ch = timeout(inserted, (void *)slt, hz/4); - break; - } -} - -/* - * Device driver interface. - */ -static int -crdopen(struct cdev *dev, int oflags, int devtype, d_thread_t *td) -{ - struct slot *slt = PCCARD_DEV2SOFTC(dev); - - if (slt == NULL) - return (ENXIO); - if (slt->rwmem == 0) - slt->rwmem = MDF_ATTR; - return (0); -} - -/* - * Close doesn't de-allocate any resources, since - * slots may be assigned to drivers already. - */ -static int -crdclose(struct cdev *dev, int fflag, int devtype, d_thread_t *td) -{ - return (0); -} - -/* - * read interface. Map memory at lseek offset, - * then transfer to user space. - */ -static int -crdread(struct cdev *dev, struct uio *uio, int ioflag) -{ - struct slot *slt = PCCARD_DEV2SOFTC(dev); - struct mem_desc *mp, oldmap; - unsigned char *p; - unsigned int offs; - int error = 0, win, count; - - if (slt == 0 || slt->state != filled) - return (ENXIO); - if (pccard_mem == 0) - return (ENOMEM); - for (win = slt->ctrl->maxmem - 1; win >= 0; win--) - if ((slt->mem[win].flags & MDF_ACTIVE) == 0) - break; - if (win < 0) - return (EBUSY); - mp = &slt->mem[win]; - oldmap = *mp; - mp->flags = slt->rwmem | MDF_ACTIVE; - while (uio->uio_resid && error == 0) { - mp->card = uio->uio_offset; - mp->size = PCCARD_MEMSIZE; - mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem; - if ((error = slt->ctrl->mapmem(slt, win)) != 0) - break; - offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1); - p = pccard_kmem + offs; - count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid); - error = uiomove(p, count, uio); - } - /* - * Restore original map. - */ - *mp = oldmap; - slt->ctrl->mapmem(slt, win); - - return (error); -} - -/* - * crdwrite - Write data to card memory. - * Handles wrap around so that only one memory - * window is used. - */ -static int -crdwrite(struct cdev *dev, struct uio *uio, int ioflag) -{ - struct slot *slt = PCCARD_DEV2SOFTC(dev); - struct mem_desc *mp, oldmap; - unsigned char *p; - unsigned int offs; - int error = 0, win, count; - - if (slt == 0 || slt->state != filled) - return (ENXIO); - if (pccard_mem == 0) - return (ENOMEM); - for (win = slt->ctrl->maxmem - 1; win >= 0; win--) - if ((slt->mem[win].flags & MDF_ACTIVE) == 0) - break; - if (win < 0) - return (EBUSY); - mp = &slt->mem[win]; - oldmap = *mp; - mp->flags = slt->rwmem | MDF_ACTIVE; - while (uio->uio_resid && error == 0) { - mp->card = uio->uio_offset; - mp->size = PCCARD_MEMSIZE; - mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem; - if ((error = slt->ctrl->mapmem(slt, win)) != 0) - break; - offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1); - p = pccard_kmem + offs; - count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid); - error = uiomove(p, count, uio); - } - /* - * Restore original map. - */ - *mp = oldmap; - slt->ctrl->mapmem(slt, win); - - return (error); -} - -/* - * ioctl calls - allows setting/getting of memory and I/O - * descriptors, and assignment of drivers. - */ -static int -crdioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td) -{ - u_int32_t addr; - int err; - struct io_desc *ip; - struct mem_desc *mp; - device_t pccarddev; - int pwval; - int s; - struct slot *slt = PCCARD_DEV2SOFTC(dev); -/*XXX*/#if __FreeBSD_version < 5000000 /* 4.x compatibility only. */ - struct dev_desc d; - struct dev_desc_old *odp; -/*XXX*/#endif - - if (slt == 0 && cmd != PIOCRWMEM) - return (ENXIO); - switch(cmd) { - default: - if (slt->ctrl->ioctl) - return (slt->ctrl->ioctl(slt, cmd, data)); - return (ENOTTY); - /* - * Get slot state. - */ - case PIOCGSTATE: - s = splhigh(); - ((struct slotstate *)data)->state = slt->state; - ((struct slotstate *)data)->laststate = slt->laststate; - slt->laststate = slt->state; - splx(s); - ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem; - ((struct slotstate *)data)->maxio = slt->ctrl->maxio; - ((struct slotstate *)data)->irqs = 0; - break; - /* - * Get memory context. - */ - case PIOCGMEM: - s = ((struct mem_desc *)data)->window; - if (s < 0 || s >= slt->ctrl->maxmem) - return (EINVAL); - mp = &slt->mem[s]; - ((struct mem_desc *)data)->flags = mp->flags; - ((struct mem_desc *)data)->start = mp->start; - ((struct mem_desc *)data)->size = mp->size; - ((struct mem_desc *)data)->card = mp->card; - break; - /* - * Set memory context. If context already active, then unmap it. - * It is hard to see how the parameters can be checked. - * At the very least, we only allow root to set the context. - */ - case PIOCSMEM: - if (suser(td)) - return (EPERM); - if (slt->state != filled) - return (ENXIO); - s = ((struct mem_desc *)data)->window; - if (s < 0 || s >= slt->ctrl->maxmem) - return (EINVAL); - slt->mem[s] = *((struct mem_desc *)data); - return (slt->ctrl->mapmem(slt, s)); - /* - * Get I/O port context. - */ - case PIOCGIO: - s = ((struct io_desc *)data)->window; - if (s < 0 || s >= slt->ctrl->maxio) - return (EINVAL); - ip = &slt->io[s]; - ((struct io_desc *)data)->flags = ip->flags; - ((struct io_desc *)data)->start = ip->start; - ((struct io_desc *)data)->size = ip->size; - break; - /* - * Set I/O port context. - */ - case PIOCSIO: - if (suser(td)) - return (EPERM); - if (slt->state != filled) - return (ENXIO); - s = ((struct io_desc *)data)->window; - if (s < 0 || s >= slt->ctrl->maxio) - return (EINVAL); - slt->io[s] = *((struct io_desc *)data); - /* XXX Don't actually map */ - return (0); - break; - /* - * Set memory window flags for read/write interface. - */ - case PIOCRWFLAG: - slt->rwmem = *(int *)data; - break; - /* - * Set the memory window to be used for the read/write interface. - */ - case PIOCRWMEM: - if (*(unsigned long *)data == 0) { - *(unsigned long *)data = pccard_mem; - break; - } - if (suser(td)) - return (EPERM); - /* - * Validate the memory by checking it against the I/O - * memory range. It must also start on an aligned block size. - */ - if (*(unsigned long *)data & (PCCARD_MEMSIZE-1)) - return (EINVAL); - pccarddev = PCCARD_DEV2SOFTC(dev)->dev; - pccard_mem_rid = 0; - addr = *(unsigned long *)data; - if (pccard_mem_res) - bus_release_resource(pccarddev, SYS_RES_MEMORY, - pccard_mem_rid, pccard_mem_res); - pccard_mem_res = bus_alloc_resource(pccarddev, SYS_RES_MEMORY, - &pccard_mem_rid, addr, addr, PCCARD_MEMSIZE, - RF_ACTIVE | rman_make_alignment_flags(PCCARD_MEMSIZE)); - if (pccard_mem_res == NULL) - return (EINVAL); - pccard_mem = rman_get_start(pccard_mem_res); - pccard_kmem = rman_get_virtual(pccard_mem_res); - break; - /* - * Set power values. - */ - case PIOCSPOW: - slt->pwr = *(struct power *)data; - return (slt->ctrl->power(slt)); - /* - * Allocate a driver to this slot. - */ - case PIOCSDRV: - if (suser(td)) - return (EPERM); - err = allocate_driver(slt, (struct dev_desc *)data); - if (!err) - pccard_success_beep(); - else - pccard_failure_beep(); - return (err); -/***/#if __FreeBSD_version < 5000000 /* 4.x compatibility only. */ - case PIOCSDRVOLD: - if (suser(td)) - return (EPERM); - odp = (struct dev_desc_old *) data; - strlcpy(d.name, odp->name, sizeof(d.name)); - d.unit = odp->unit; - d.mem = odp->mem; - d.memsize = odp->memsize; - d.iobase = odp->iobase; - d.iosize = odp->iosize; - d.irqmask = odp->irqmask; - d.flags = odp->flags; - memcpy(d.misc, odp->misc, sizeof(odp->misc)); - strlcpy(d.manufstr, odp->manufstr, sizeof(d.manufstr)); - strlcpy(d.versstr, odp->versstr, sizeof(d.versstr)); - *d.cis3str = '\0'; - *d.cis4str = '\0'; - d.manufacturer = odp->manufacturer; - d.product = odp->product; - d.prodext = odp->prodext; - err = allocate_driver(slt, &d); - if (!err) - pccard_success_beep(); - else - pccard_failure_beep(); - return (err); -/***/#endif - /* - * Virtual removal/insertion - */ - case PIOCSVIR: - pwval = *(int *)data; - if (!pwval) { - if (slt->state != filled) - return (EINVAL); - pccard_event(slt, card_deactivated); - } else { - if (slt->state != empty && slt->state != inactive) - return (EINVAL); - pccard_event(slt, card_inserted); - } - break; - case PIOCSBEEP: - if (pccard_beep_select(*(int *)data)) { - return (EINVAL); - } - break; - } - return (0); -} - -/* - * poll - Poll on exceptions will return true - * when a change in card status occurs. - */ -static int -crdpoll(struct cdev *dev, int events, d_thread_t *td) -{ - int revents = 0; - int s; - struct slot *slt = PCCARD_DEV2SOFTC(dev); - - if (events & (POLLIN | POLLRDNORM)) - revents |= events & (POLLIN | POLLRDNORM); - - if (events & (POLLOUT | POLLWRNORM)) - revents |= events & (POLLIN | POLLRDNORM); - - s = splhigh(); - /* - * select for exception - card event. - */ - if (events & POLLRDBAND) - if (slt == 0 || slt->laststate != slt->state) - revents |= POLLRDBAND; - - if (revents == 0) - selrecord(td, &slt->selp); - - splx(s); - return (revents); -} - -/* - * APM hooks for suspending and resuming. - */ -int -pccard_suspend(device_t dev) -{ - struct slot *slt = PCCARD_DEVICE2SOFTC(dev); - - /* This code stolen from pccard_event:card_removed */ - if (slt->state == filled) { - int s = splhigh(); /* nop on current */ - disable_slot(slt); - slt->laststate = suspend; /* for pccardd */ - slt->state = empty; - splx(s); - printf("pccard: card disabled, slot %d\n", slt->slotnum); - } - /* - * Disable any pending timeouts for this slot since we're - * powering it down/disabling now. - */ - untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch); - slt->ctrl->disable(slt); - return (0); -} - -int -pccard_resume(device_t dev) -{ - struct slot *slt = PCCARD_DEVICE2SOFTC(dev); - - slt->ctrl->resume(slt); - return (0); -} diff --git a/sys/pccard/pccard_beep.c b/sys/pccard/pccard_beep.c deleted file mode 100644 index e608dc1..0000000 --- a/sys/pccard/pccard_beep.c +++ /dev/null @@ -1,138 +0,0 @@ -/*- - * pccard noise interface. - * Nate Williams, October 1997. - * This file is in the public domain. - */ -/* $FreeBSD$ */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> - -#include <machine/clock.h> - -#include <pccard/driver.h> - -static enum beepstate allow_beep = BEEP_OFF; -static int melody_type = 0; - -#define MAX_TONE_MODE 3 -#define MAX_STATE 4 - -struct tone { - int pitch; - int duration; -}; - -static struct tone silent_beep[] = { - {0, 0} -}; - -static struct tone success_beep[] = { - {1200, 40}, {0, 0} -}; -static struct tone failure_beep[] = { - {3200, 40}, {0, 0} -}; -static struct tone insert_remove_beep[] = { - {1600, 20}, {0, 0} -}; - -static struct tone success_melody_beep[] = { - {1200, 7}, {1000, 7}, { 800, 15}, {0, 0} -}; -static struct tone failure_melody_beep[] = { - {2000, 7}, {2400, 7}, {2800, 15}, {0, 0} -}; -static struct tone insert_melody_beep[] = { - {1600, 10}, {1200, 5}, {0, 0} -}; -static struct tone remove_melody_beep[] = { - {1200, 10}, {1600, 5}, {0, 0} -}; - -static struct tone *melody_table[MAX_TONE_MODE][MAX_STATE] = { - { /* silent mode */ - silent_beep, silent_beep, silent_beep, silent_beep, - }, - { /* simple beep mode */ - success_beep, failure_beep, - insert_remove_beep, insert_remove_beep, - }, - { /* melody beep mode */ - success_melody_beep, failure_melody_beep, - insert_melody_beep, remove_melody_beep, - }, -}; - - -static void -pccard_beep_sub(void *arg) -{ - struct tone *melody; - melody = (struct tone *)arg; - - if (melody->pitch != 0) { - sysbeep(melody->pitch, (melody->duration * hz + 99) / 100); - timeout(pccard_beep_sub, melody + 1, - (melody->duration * hz + 99) / 100); - } else - allow_beep = BEEP_ON; -} - -static void -pccard_beep_start(void *arg) -{ - struct tone *melody; - melody = (struct tone *)arg; - - if (allow_beep == BEEP_ON && melody->pitch != 0) { - allow_beep = BEEP_OFF; - sysbeep(melody->pitch, (melody->duration * hz + 99) / 100); - timeout(pccard_beep_sub, melody + 1, - (melody->duration * hz + 99) / 100); - } -} - -void -pccard_success_beep(void) -{ - pccard_beep_start(melody_table[melody_type][0]); -} - -void -pccard_failure_beep(void) -{ - pccard_beep_start(melody_table[melody_type][1]); -} - -void -pccard_insert_beep(void) -{ - pccard_beep_start(melody_table[melody_type][2]); -} - -void -pccard_remove_beep(void) -{ - pccard_beep_start(melody_table[melody_type][3]); -} - -int -pccard_beep_select(int type) -{ - int errcode = 0; - - if (type == 0) { - allow_beep = BEEP_OFF; - melody_type = 0; - } else if (type < 0 || MAX_TONE_MODE - 1 < type) { - errcode = 1; - } else { - allow_beep = BEEP_ON; - melody_type = type; - } - return (errcode); -} diff --git a/sys/pccard/pccard_nbk.c b/sys/pccard/pccard_nbk.c deleted file mode 100644 index bda9db1..0000000 --- a/sys/pccard/pccard_nbk.c +++ /dev/null @@ -1,436 +0,0 @@ -/*- - * Copyright (c) 1999, 2001 M. Warner Losh. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * This file contains various kludges to allow the legacy pccard system to - * work in the newbus system until the pccard system can be converted - * wholesale to newbus. As that is a while off, I'm providing this glue to - * allow newbus drivers to have pccard attachments. - * - * We do *NOT* implement ISA ivars at all. We are not an isa bus, and drivers - * that abuse isa_{set,get}_* must be fixed in order to work with pccard. - * We use ivars for something else anyway, so it becomes fairly awkward - * to do so. - * - * Here's a summary of the glue that we do to make things work. - * - * First, we have pccard node in the device and driver trees. The pccard - * device lives in the instance tree attached to the nexus. The pccard - * attachments will be attached to that node. This allows one to pass things - * up the tree that terminates at the nexus, like other buses. The pccard - * code will create a device instance for each of the drivers that are to - * be attached. - * - * These compatibility nodes are called pccnbk. PCCard New Bus Kludge. - */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/module.h> -#include <sys/kernel.h> -#include <sys/sysctl.h> -#include <sys/queue.h> -#include <sys/types.h> - -#include <sys/bus.h> -#include <machine/bus.h> -#include <machine/resource.h> - -/* XXX Shouldn't reach into the MD code here */ -#ifdef PC98 -#include <pc98/cbus/cbus.h> -#else -#include <i386/isa/isa.h> -#endif - -#include <pccard/cardinfo.h> -#include <pccard/slot.h> - -#include <dev/pccard/pccardvar.h> -#include <net/ethernet.h> - -#include "card_if.h" - -devclass_t pccard_devclass; - -#define PCCARD_NPORT 2 -#define PCCARD_NMEM 5 -#define PCCARD_NIRQ 1 -#define PCCARD_NDRQ 0 - -#define PCCARD_DEVINFO(d) (struct pccard_devinfo *) device_get_ivars(d) - -SYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard"); - -#ifdef UNSAFE -static u_long mem_start = IOM_BEGIN; -static u_long mem_end = IOM_END; -#else -static u_long mem_start = 0xd0000; -static u_long mem_end = 0xeffff; -#endif - -SYSCTL_ULONG(_machdep_pccard, OID_AUTO, mem_start, CTLFLAG_RW, - &mem_start, 0, ""); -SYSCTL_ULONG(_machdep_pccard, OID_AUTO, mem_end, CTLFLAG_RW, - &mem_end, 0, ""); - -#if __FreeBSD_version >= 500000 -/* - * glue for NEWCARD/OLDCARD compat layer - */ -static int -pccard_compat_do_probe(device_t bus, device_t dev) -{ - return (CARD_COMPAT_PROBE(dev)); -} - -static int -pccard_compat_do_attach(device_t bus, device_t dev) -{ - return (CARD_COMPAT_ATTACH(dev)); -} -#endif - -static int -pccard_probe(device_t dev) -{ - device_set_desc(dev, "PC Card 16-bit bus (classic)"); - return (0); -} - -static int -pccard_attach(device_t dev) -{ - return (0); -} - -static void -pccard_print_resources(struct resource_list *rl, const char *name, int type, - int count, const char *format) -{ - struct resource_list_entry *rle; - int printed; - int i; - - printed = 0; - for (i = 0; i < count; i++) { - rle = resource_list_find(rl, type, i); - if (rle) { - if (printed == 0) - printf(" %s ", name); - else if (printed > 0) - printf(","); - printed++; - printf(format, rle->start); - if (rle->count > 1) { - printf("-"); - printf(format, rle->start + rle->count - 1); - } - } else if (i > 3) { - /* check the first few regardless */ - break; - } - } -} - -static int -pccard_print_child(device_t dev, device_t child) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - struct resource_list *rl = &devi->resources; - int retval = 0; - int flags = device_get_flags(child); - - retval += bus_print_child_header(dev, child); - retval += printf(" at"); - - if (devi) { - pccard_print_resources(rl, "port", SYS_RES_IOPORT, - PCCARD_NPORT, "%#lx"); - pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, - PCCARD_NMEM, "%#lx"); - pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, - "%ld"); - pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, - "%ld"); - if (flags != 0) - retval += printf(" flags 0x%x", flags); - retval += printf(" slot %d", devi->slt->slotnum); - } - - retval += bus_print_child_footer(dev, child); - - return (retval); -} - -static int -pccard_set_resource(device_t dev, device_t child, int type, int rid, - u_long start, u_long count) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - struct resource_list *rl = &devi->resources; - - if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY - && type != SYS_RES_IRQ && type != SYS_RES_DRQ) - return (EINVAL); - if (rid < 0) - return (EINVAL); - if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) - return (EINVAL); - if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) - return (EINVAL); - if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) - return (EINVAL); - if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) - return (EINVAL); - - resource_list_add(rl, type, rid, start, start + count - 1, count); - - return (0); -} - -static int -pccard_get_resource(device_t dev, device_t child, int type, int rid, - u_long *startp, u_long *countp) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - struct resource_list *rl = &devi->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); -} - -static void -pccard_delete_resource(device_t dev, device_t child, int type, int rid) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - struct resource_list *rl = &devi->resources; - resource_list_delete(rl, type, rid); -} - -static struct resource * -pccard_alloc_resource(device_t bus, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - /* - * Consider adding a resource definition. We allow rid 0 for - * irq, 0-4 for memory and 0-1 for ports - */ - int passthrough = (device_get_parent(child) != bus); - int isdefault; - struct pccard_devinfo *devi = device_get_ivars(child); - struct resource_list *rl = &devi->resources; - struct resource_list_entry *rle; - struct resource *res; - - if (start == 0 && end == ~0 && type == SYS_RES_MEMORY && count != 1) { - start = mem_start; - end = mem_end; - } - isdefault = (start == 0UL && end == ~0UL); - if (!passthrough && !isdefault) { - rle = resource_list_find(rl, type, *rid); - if (!rle) { - if (*rid < 0) - return (NULL); - switch (type) { - case SYS_RES_IRQ: - if (*rid >= PCCARD_NIRQ) - return (NULL); - break; - case SYS_RES_DRQ: - if (*rid >= PCCARD_NDRQ) - return (NULL); - break; - case SYS_RES_MEMORY: - if (*rid >= PCCARD_NMEM) - return (NULL); - break; - case SYS_RES_IOPORT: - if (*rid >= PCCARD_NPORT) - return (NULL); - break; - default: - return (NULL); - } - resource_list_add(rl, type, *rid, start, end, count); - } - } - res = resource_list_alloc(rl, bus, child, type, rid, start, end, - count, flags); - return (res); -} - -static int -pccard_release_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - struct resource_list *rl = &devi->resources; - return (resource_list_release(rl, bus, child, type, rid, r)); -} - -static int -pccard_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) -{ - struct pccard_devinfo *devi = PCCARD_DEVINFO(child); - - switch (which) { - case PCCARD_IVAR_ETHADDR: - bcopy(devi->misc, result, ETHER_ADDR_LEN); - return (0); - case PCCARD_IVAR_VENDOR: - *(u_int32_t *) result = devi->manufacturer; - return (0); - case PCCARD_IVAR_PRODUCT: - *(u_int32_t *) result = devi->product; - return (0); - case PCCARD_IVAR_PRODEXT: - *(u_int16_t *) result = devi->prodext; - return (0); - case PCCARD_IVAR_VENDOR_STR: - *(char **) result = devi->manufstr; - break; - case PCCARD_IVAR_PRODUCT_STR: - *(char **) result = devi->versstr; - break; - case PCCARD_IVAR_CIS3_STR: - *(char **) result = devi->cis3str; - break; - case PCCARD_IVAR_CIS4_STR: - *(char **) result = devi->cis4str; - break; - } - return (ENOENT); -} - -static int -pccard_set_res_flags(device_t bus, device_t child, int restype, int rid, - u_long value) -{ - return (CARD_SET_RES_FLAGS(device_get_parent(bus), child, restype, - rid, value)); -} - -static int -pccard_get_res_flags(device_t bus, device_t child, int restype, int rid, - u_long *value) -{ - return (CARD_GET_RES_FLAGS(device_get_parent(bus), child, restype, - rid, value)); -} - -static int -pccard_set_memory_offset(device_t bus, device_t child, int rid, - u_int32_t offset -#if __FreeBSD_version >= 500000 - , u_int32_t *deltap -#endif -) -{ - return (CARD_SET_MEMORY_OFFSET(device_get_parent(bus), child, rid, - offset -#if __FreeBSD_version >= 500000 - , deltap -#endif - )); -} - -static int -pccard_get_memory_offset(device_t bus, device_t child, int rid, - u_int32_t *offset) -{ - return (CARD_GET_MEMORY_OFFSET(device_get_parent(bus), child, rid, - offset)); -} - -#if __FreeBSD_version >= 500000 -static const struct pccard_product * -pccard_do_product_lookup(device_t bus, device_t dev, - const struct pccard_product *tab, - size_t ent_size, pccard_product_match_fn matchfn) -{ - return (NULL); -} -#endif - -static device_method_t pccard_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pccard_probe), - DEVMETHOD(device_attach, pccard_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, pccard_suspend), - DEVMETHOD(device_resume, pccard_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, pccard_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), - DEVMETHOD(bus_release_resource, pccard_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, pccard_set_resource), - DEVMETHOD(bus_get_resource, pccard_get_resource), - DEVMETHOD(bus_delete_resource, pccard_delete_resource), - DEVMETHOD(bus_read_ivar, pccard_read_ivar), - - /* Card interface */ - DEVMETHOD(card_set_res_flags, pccard_set_res_flags), - DEVMETHOD(card_get_res_flags, pccard_get_res_flags), - DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), - DEVMETHOD(card_get_memory_offset, pccard_get_memory_offset), -#if __FreeBSD_version >= 500000 - DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), - DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), - DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup), -#endif - { 0, 0 } -}; - -static driver_t pccard_driver = { - "pccard", - pccard_methods, - sizeof(struct slot) -}; - -DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); -DRIVER_MODULE(pccard, mecia, pccard_driver, pccard_devclass, 0, 0); -MODULE_VERSION(pccard, 1); diff --git a/sys/pccard/pcic.c b/sys/pccard/pcic.c deleted file mode 100644 index be4fea8..0000000 --- a/sys/pccard/pcic.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* - * Intel PCIC or compatible Controller driver - *------------------------------------------------------------------------- - */ - -/*- - * Copyright (c) 2001 M. Warner Losh. All rights reserved. - * Copyright (c) 1995 Andrew McRae. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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$ - */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/sysctl.h> -#include <sys/systm.h> - -#include <machine/clock.h> -#include <pccard/i82365.h> -#include <pccard/pcic_pci.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> -#include <pccard/pcicvar.h> - -/* Get pnp IDs */ -#include <isa/isavar.h> - -#include <dev/pccard/pccardvar.h> -#include "card_if.h" - -/* - * Prototypes for interrupt handler. - */ -static int pcic_ioctl(struct slot *, int, caddr_t); -static int pcic_power(struct slot *); -static void pcic_mapirq(struct slot *, int); -static timeout_t pcic_reset; -static void pcic_resume(struct slot *); -static void pcic_disable(struct slot *); -static int pcic_memory(struct slot *, int); -static int pcic_io(struct slot *, int); - -devclass_t pcic_devclass; - -static struct slot_ctrl pcic_cinfo = { - pcic_mapirq, - pcic_memory, - pcic_io, - pcic_reset, - pcic_disable, - pcic_power, - pcic_ioctl, - pcic_resume, - PCIC_MEM_WIN, - PCIC_IO_WIN -}; - -/* sysctl vars */ -SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters"); - -int pcic_override_irq = 0; -TUNABLE_INT("machdep.pccard.pcic_irq", &pcic_override_irq); -TUNABLE_INT("hw.pcic.irq", &pcic_override_irq); -SYSCTL_INT(_hw_pcic, OID_AUTO, irq, CTLFLAG_RDTUN, - &pcic_override_irq, 0, - "Override the IRQ configured by the config system for all pcic devices"); - -int pcic_boot_deactivated = 0; -TUNABLE_INT("hw.pcic.boot_deactivated", &pcic_boot_deactivated); -SYSCTL_INT(_hw_pcic, OID_AUTO, boot_deactivated, CTLFLAG_RDTUN, - &pcic_boot_deactivated, 0, - "Override the automatic powering up of pccards at boot. This works\n\ -around what turns out to be an old bug in the code that has since been\n\ -corrected. It is now deprecated and will be removed completely before\n\ -FreeBSD 4.8."); - -/* - * CL-PD6722's VSENSE method - * 0: NO VSENSE (assume a 5.0V card) - * 1: 6710's method (default) - * 2: 6729's method - */ -int pcic_pd6722_vsense = 1; -TUNABLE_INT("hw.pcic.pd6722_vsense", &pcic_pd6722_vsense); -SYSCTL_INT(_hw_pcic, OID_AUTO, pd6722_vsense, CTLFLAG_RDTUN, - &pcic_pd6722_vsense, 1, - "Select CL-PD6722's VSENSE method. VSENSE is used to determine the\n\ -volatage of inserted cards. The CL-PD6722 has two methods to determine the\n\ -voltage of the card. 0 means assume a 5.0V card and do not check. 1 means\n\ -use the same method that the CL-PD6710 uses (default). 2 means use the\n\ -same method as the CL-PD6729. 2 is documented in the datasheet as being\n\ -the correct way, but 1 seems to give better results on more laptops."); - -/* - * Read a register from the PCIC. - */ -unsigned char -pcic_getb_io(struct pcic_slot *sp, int reg) -{ - bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, sp->offset + reg); - return (bus_space_read_1(sp->bst, sp->bsh, PCIC_DATA)); -} - -/* - * Write a register on the PCIC - */ -void -pcic_putb_io(struct pcic_slot *sp, int reg, unsigned char val) -{ - /* - * Many datasheets recommend using outw rather than outb to save - * a microsecond. Maybe we should do this, but we'd likely only - * save 20-30us on card activation. - */ - bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, sp->offset + reg); - bus_space_write_1(sp->bst, sp->bsh, PCIC_DATA, val); -} - -/* - * Clear bit(s) of a register. - */ -__inline void -pcic_clrb(struct pcic_slot *sp, int reg, unsigned char mask) -{ - sp->putb(sp, reg, sp->getb(sp, reg) & ~mask); -} - -/* - * Set bit(s) of a register - */ -__inline void -pcic_setb(struct pcic_slot *sp, int reg, unsigned char mask) -{ - sp->putb(sp, reg, sp->getb(sp, reg) | mask); -} - -/* - * Write a 16 bit value to 2 adjacent PCIC registers - */ -static __inline void -pcic_putw(struct pcic_slot *sp, int reg, unsigned short word) -{ - sp->putb(sp, reg, word & 0xFF); - sp->putb(sp, reg + 1, (word >> 8) & 0xff); -} - -/* - * pc98 cbus cards introduce a slight wrinkle here. They route the irq7 pin - * from the pcic chip to INT 2 on the cbus. INT 2 is normally mapped to - * irq 6 on the pc98 architecture, so if we get a request for irq 6 - * lie to the hardware and say it is 7. All the other usual mappings for - * cbus INT into irq space are the same as the rest of the system. - */ -static __inline int -host_irq_to_pcic(int irq) -{ -#ifdef PC98 - if (irq == 6) - irq = 7; -#endif - return (irq); -} - -/* - * Free up resources allocated so far. - */ -void -pcic_dealloc(device_t dev) -{ - struct pcic_softc *sc; - - sc = (struct pcic_softc *) device_get_softc(dev); - if (sc->slot_poll) - untimeout(sc->slot_poll, sc, sc->timeout_ch); - if (sc->iores) - bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, - sc->iores); - if (sc->memres) - bus_release_resource(dev, SYS_RES_MEMORY, sc->memrid, - sc->memres); - if (sc->ih) - bus_teardown_intr(dev, sc->irqres, sc->ih); - if (sc->irqres) - bus_release_resource(dev, SYS_RES_IRQ, sc->irqrid, sc->irqres); -} - -/* - * entry point from main code to map/unmap memory context. - */ -static int -pcic_memory(struct slot *slt, int win) -{ - struct pcic_slot *sp = slt->cdata; - struct mem_desc *mp = &slt->mem[win]; - int reg = win * PCIC_MEMSIZE + PCIC_MEMBASE; - - if (win < 0 || win >= slt->ctrl->maxmem) { - printf("Illegal PCIC MEMORY window request %d\n", win); - return (ENXIO); - } - if (mp->flags & MDF_ACTIVE) { - unsigned long sys_addr = (uintptr_t)(void *)mp->start >> 12; - if ((sys_addr >> 12) != 0 && - (sp->sc->flags & PCIC_YENTA_HIGH_MEMORY) == 0) { - printf("This pcic does not support mapping > 24M\n"); - return (ENXIO); - } - /* - * Write the addresses, card offsets and length. - * The values are all stored as the upper 12 bits of the - * 24 bit address i.e everything is allocated as 4 Kb chunks. - * Memory mapped cardbus bridges extend this slightly to allow - * one to set the upper 8 bits of the 32bit address as well. - * If the chip supports it, then go ahead and write those - * upper 8 bits. - */ - pcic_putw(sp, reg, sys_addr & 0xFFF); - pcic_putw(sp, reg+2, (sys_addr + (mp->size >> 12) - 1) & 0xFFF); - pcic_putw(sp, reg+4, ((mp->card >> 12) - sys_addr) & 0x3FFF); - if (sp->sc->flags & PCIC_YENTA_HIGH_MEMORY) - sp->putb(sp, PCIC_MEMORY_HIGH0 + win, sys_addr >> 12); - /* - * Each 16 bit register has some flags in the upper bits. - */ - if (mp->flags & MDF_16BITS) - pcic_setb(sp, reg+1, PCIC_DATA16); - if (mp->flags & MDF_ZEROWS) - pcic_setb(sp, reg+1, PCIC_ZEROWS); - if (mp->flags & MDF_WS0) - pcic_setb(sp, reg+3, PCIC_MW0); - if (mp->flags & MDF_WS1) - pcic_setb(sp, reg+3, PCIC_MW1); - if (mp->flags & MDF_ATTR) - pcic_setb(sp, reg+5, PCIC_REG); - if (mp->flags & MDF_WP) - pcic_setb(sp, reg+5, PCIC_WP); - /* - * Enable the memory window. By experiment, we need a delay. - */ - pcic_setb(sp, PCIC_ADDRWINE, (1<<win) | PCIC_MEMCS16); - DELAY(50); - } else { - pcic_clrb(sp, PCIC_ADDRWINE, 1<<win); - pcic_putw(sp, reg, 0); - pcic_putw(sp, reg+2, 0); - pcic_putw(sp, reg+4, 0); - } - if (bootverbose) - printf("pcic: mem addr %p: reg %d: %x %x %x %x %x %x %x\n", - mp->start, reg, sp->getb(sp, reg), sp->getb(sp, reg+1), - sp->getb(sp, reg+2), sp->getb(sp, reg+3), - sp->getb(sp, reg+3), sp->getb(sp, reg+5), - sp->getb(sp, PCIC_ADDRWINE)); - return (0); -} - -/* - * pcic_io - map or unmap I/O context - */ -static int -pcic_io(struct slot *slt, int win) -{ - int mask, reg; - struct pcic_slot *sp = slt->cdata; - struct io_desc *ip = &slt->io[win]; - if (bootverbose) { - printf("pcic: I/O win %d flags %x %x-%x\n", win, ip->flags, - ip->start, ip->start + ip->size - 1); - } - - switch (win) { - case 0: - mask = PCIC_IO0_EN; - reg = PCIC_IO0; - break; - case 1: - mask = PCIC_IO1_EN; - reg = PCIC_IO1; - break; - default: - printf("Illegal PCIC I/O window request %d\n", win); - return (ENXIO); - } - if (ip->flags & IODF_ACTIVE) { - unsigned char x, ioctlv; - - pcic_putw(sp, reg, ip->start); - pcic_putw(sp, reg+2, ip->start + ip->size - 1); - x = 0; - if (ip->flags & IODF_ZEROWS) - x |= PCIC_IO_0WS; - if (ip->flags & IODF_WS) - x |= PCIC_IO_WS; - if (ip->flags & IODF_CS16) - x |= PCIC_IO_CS16; - if (ip->flags & IODF_16BIT) - x |= PCIC_IO_16BIT; - /* - * Extract the current flags and merge with new flags. - * Flags for window 0 in lower nybble, and in upper nybble - * for window 1. - */ - ioctlv = sp->getb(sp, PCIC_IOCTL); - DELAY(100); - switch (win) { - case 0: - sp->putb(sp, PCIC_IOCTL, x | (ioctlv & 0xf0)); - break; - case 1: - sp->putb(sp, PCIC_IOCTL, (x << 4) | (ioctlv & 0xf)); - break; - } - DELAY(100); - pcic_setb(sp, PCIC_ADDRWINE, mask); - DELAY(100); - } else { - pcic_clrb(sp, PCIC_ADDRWINE, mask); - DELAY(100); - pcic_putw(sp, reg, 0); - pcic_putw(sp, reg + 2, 0); - } - return (0); -} - -static void -pcic_do_mgt_irq(struct pcic_slot *sp, int irq) -{ - u_int32_t reg; - - if (sp->sc->csc_route == pcic_iw_pci) { - /* Do the PCI side of things: Enable the Card Change int */ - reg = CB_SM_CD; - bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_MASK, reg); - /* - * TI Chips need us to set the following. We tell the - * controller to route things via PCI interrupts. Also - * we clear the interrupt number in the STAT_INT register - * as well. The TI-12xx and newer chips require one or the - * other of these to happen, depending on what is set in the - * diagnostic register. I do both on the theory that other - * chips might need one or the other and that no harm will - * come from it. If there is harm, then I'll make it a bit - * in the tables. - */ - pcic_setb(sp, PCIC_INT_GEN, PCIC_INTR_ENA); - pcic_clrb(sp, PCIC_STAT_INT, PCIC_CSCSELECT); - } else { - /* Management IRQ changes */ - /* - * The PCIC_INTR_ENA bit means either "tie the function - * and csc interrupts together" or "Route csc interrupts - * via PCI" or "Reserved". In any case, we want to clear - * it since we're using ISA interrupts. - */ - pcic_clrb(sp, PCIC_INT_GEN, PCIC_INTR_ENA); - irq = host_irq_to_pcic(irq); - sp->putb(sp, PCIC_STAT_INT, (irq << PCIC_SI_IRQ_SHIFT) | - PCIC_CDEN); - } -} - -int -pcic_attach(device_t dev) -{ - int i; - device_t kid; - struct pcic_softc *sc; - struct slot *slt; - struct pcic_slot *sp; - - sc = (struct pcic_softc *) device_get_softc(dev); - callout_handle_init(&sc->timeout_ch); - sp = &sc->slots[0]; - for (i = 0; i < PCIC_CARD_SLOTS; i++, sp++) { - if (!sp->slt) - continue; - sp->slt = 0; - kid = device_add_child(dev, NULL, -1); - if (kid == NULL) { - device_printf(dev, "Can't add pccard bus slot %d", i); - return (ENXIO); - } - device_probe_and_attach(kid); - slt = pccard_init_slot(kid, &pcic_cinfo); - if (slt == 0) { - device_printf(dev, "Can't get pccard info slot %d", i); - return (ENXIO); - } - sc->slotmask |= (1 << i); - slt->cdata = sp; - sp->slt = slt; - sp->sc = sc; - } - - sp = &sc->slots[0]; - for (i = 0; i < PCIC_CARD_SLOTS; i++, sp++) { - if (sp->slt == NULL) - continue; - - pcic_do_mgt_irq(sp, sc->irq); - sp->slt->irq = sc->irq; - - /* Check for changes */ - sp->slt->laststate = sp->slt->state = empty; - if (pcic_boot_deactivated) { - sp->putb(sp, PCIC_POWER, 0); - if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) == PCIC_CD) { - sp->slt->state = inactive; - pccard_event(sp->slt, card_deactivated); - } - } else { - pcic_do_stat_delta(sp); - } - } - - return (bus_generic_attach(dev)); -} - - -static int -pcic_sresource(struct slot *slt, caddr_t data) -{ - struct pccard_resource *pr; - struct resource *r; - int flags; - int rid = 0; - device_t bridgedev = slt->dev; - struct pcic_slot *sp = slt->cdata; - - pr = (struct pccard_resource *)data; - pr->resource_addr = ~0ul; - - /* - * If we're using PCI interrupt routing, then force the IRQ to - * use and to heck with what the user requested. If they want - * to be able to request IRQs, they must use ISA interrupt - * routing. If we don't give them an irq, and it is the - * pccardd 0,0 case, then just return (giving the "bad resource" - * return in pr->resource_addr). - */ - if (pr->type == SYS_RES_IRQ) { - if (sp->sc->func_route >= pcic_iw_pci) { - pr->resource_addr = sp->sc->irq; - return (0); - } - if (pr->min == 0 && pr->max == 0) - return (0); - } - - /* - * Make sure we grok this type. - */ - switch(pr->type) { - default: - return (EINVAL); - case SYS_RES_MEMORY: - case SYS_RES_IRQ: - case SYS_RES_IOPORT: - break; - } - - /* - * Allocate the resource, and align it to the most natural - * size. If we get it, then tell userland what we actually got - * in the range they requested. - */ - flags = rman_make_alignment_flags(pr->size); - r = bus_alloc_resource(bridgedev, pr->type, &rid, pr->min, pr->max, - pr->size, flags); - if (r != NULL) { - pr->resource_addr = (u_long)rman_get_start(r); - bus_release_resource(bridgedev, pr->type, rid, r); - } - return (0); -} - -/* - * ioctl calls - Controller specific ioctls - */ -static int -pcic_ioctl(struct slot *slt, int cmd, caddr_t data) -{ - struct pcic_slot *sp = slt->cdata; - struct pcic_reg *preg = (struct pcic_reg *) data; - - switch(cmd) { - default: - return (ENOTTY); - case PIOCGREG: /* Get pcic register */ - preg->value = sp->getb(sp, preg->reg); - break; /* Set pcic register */ - case PIOCSREG: - sp->putb(sp, preg->reg, preg->value); - break; - case PIOCSRESOURCE: /* Can I use this resource? */ - pcic_sresource(slt, data); - break; - } - return (0); -} - -/* - * pcic_cardbus_power - * - * Power the card up, as specified, using the cardbus power - * registers to control power. Microsoft recommends that cardbus - * vendors support powering the card via cardbus registers because - * there is no standard for 3.3V cards. Since at least a few of the - * cardbus bridges have minor issues with power via the ExCA registers, - * go ahead and do it all via cardbus registers. - * - * An expamination of the code will show the relative ease that we do - * Vpp in comparison to the ExCA case (which may be partially broken). - */ -static int -pcic_cardbus_power(struct pcic_slot *sp, struct slot *slt) -{ - uint32_t power; - uint32_t state; - - /* - * If we're doing an auto-detect, and we're in a badvcc state, then - * we need to force the socket to rescan the card. We don't do this - * all the time because the socket can take up to 200ms to do the deed, - * and that's too long to busy wait. Since this is a relatively rare - * event (some BIOSes, and earlier versions of OLDCARD caused it), we - * test for it special. - */ - state = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - if (slt->pwr.vcc == -1 && (state & CB_SS_BADVCC)) { - /* - * Force the bridge to scan the card for the proper voltages - * that it supports. - */ - bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_FORCE, - CB_SF_INTCVS); - state = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - /* This while loop can take 100-150ms */ - while ((state & CB_SS_CARD_MASK) == 0) { - DELAY(10 * 1000); - state = bus_space_read_4(sp->bst, sp->bsh, - CB_SOCKET_STATE); - } - } - - - /* - * Preserve the clock stop bit of the socket power register. Not - * sure that we want to do that, but maybe we should set it based - * on the power state. - */ - power = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_POWER); - power = 0; - - /* - * vcc == -1 means automatically detect the voltage of the card. - * Do so and apply the right amount of power. - */ - if (slt->pwr.vcc == -1) { - if (state & CB_SS_5VCARD) - slt->pwr.vcc = 50; - else if (state & CB_SS_3VCARD) - slt->pwr.vcc = 33; - else if (state & CB_SS_XVCARD) - slt->pwr.vcc = 22; - else if (state & CB_SS_YVCARD) - slt->pwr.vcc = 11; - if (bootverbose && slt->pwr.vcc != -1) - device_printf(sp->sc->dev, - "Autodetected %d.%dV card\n", - slt->pwr.vcc / 10, slt->pwr.vcc % 10); - } - - switch(slt->pwr.vcc) { - default: - return (EINVAL); - case 0: - power |= CB_SP_VCC_0V; - break; - case 11: - power |= CB_SP_VCC_YV; - break; - case 22: - power |= CB_SP_VCC_XV; - break; - case 33: - power |= CB_SP_VCC_3V; - break; - case 50: - power |= CB_SP_VCC_5V; - break; - } - - /* - * vpp == -1 means use vcc voltage. - */ - if (slt->pwr.vpp == -1) - slt->pwr.vpp = slt->pwr.vcc; - switch(slt->pwr.vpp) { - default: - return (EINVAL); - case 0: - power |= CB_SP_VPP_0V; - break; - case 11: - power |= CB_SP_VPP_YV; - break; - case 22: - power |= CB_SP_VPP_XV; - break; - case 33: - power |= CB_SP_VPP_3V; - break; - case 50: - power |= CB_SP_VPP_5V; - break; - case 120: - power |= CB_SP_VPP_12V; - break; - } - bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_POWER, power); - - /* - * OK. We need to bring the card out of reset. Let the power - * stabilize for 300ms (why 300?) and then enable the outputs - * and then wait 100ms (why 100?) for it to stabilize. These numbers - * were stolen from the dim, dark past of OLDCARD and I have no clue - * how they were derived. I also use the bit setting routines here - * as a measure of conservatism. - */ - if (power) { - pcic_setb(sp, PCIC_POWER, PCIC_DISRST); - DELAY(300*1000); - pcic_setb(sp, PCIC_POWER, PCIC_DISRST | PCIC_OUTENA); - DELAY(100*1000); - } else { - pcic_clrb(sp, PCIC_POWER, PCIC_DISRST | PCIC_OUTENA); - } - - return (0); -} - -/* - * pcic_power - Enable the power of the slot according to - * the parameters in the power structure(s). - */ -static int -pcic_power(struct slot *slt) -{ - unsigned char c, c2; - unsigned char reg = PCIC_DISRST | PCIC_PCPWRE; - struct pcic_slot *sp = slt->cdata; - struct pcic_slot *sp2; - struct pcic_softc *sc = sp->sc; - int dodefault = 0; - char controller; - - /* - * Cardbus power registers are completely different. - */ - if (sc->flags & PCIC_CARDBUS_POWER) - return (pcic_cardbus_power(sp, slt)); - - if (bootverbose) - device_printf(sc->dev, "Power: Vcc=%d Vpp=%d\n", slt->pwr.vcc, - slt->pwr.vpp); - /* - * If we're automatically detecting what voltage to use, then we need - * to ask the bridge what type (voltage-wise) the card is. - */ - if (slt->pwr.vcc == -1) { - if (sc->flags & PCIC_DF_POWER) { - /* - * Look at the VS[12]# bits on the card. If VS1 is - * clear then the card needs 3.3V instead of 5.0V. - */ - c = sp->getb(sp, PCIC_CDGC); - if ((c & PCIC_VS1STAT) == 0) - slt->pwr.vcc = 33; - else - slt->pwr.vcc = 50; - } - if (sc->flags & PCIC_PD_POWER) { - /* - * The 6710 does it one way, and the '22 and '29 do it - * another. The '22 can also do it the same way as a - * '10 does it, despite what the datasheets say. Some - * laptops with '22 don't seem to have the signals - * wired right for the '29 method to work. The - * laptops that don't work hang solid when the pccard - * memory is accessed. - * - * To allow for both types of laptops, - * hw.pcic.pd6722_vsense will select which one to use. - * 0 - none, 1 - the '10 way and 2 - the '29 way. - */ - controller = sp->controller; - if (controller == PCIC_PD6722) { - switch (pcic_pd6722_vsense) { - case 1: - controller = PCIC_PD6710; - break; - case 2: - controller = PCIC_PD6729; - break; - } - } - - switch (controller) { - case PCIC_PD6710: - c = sp->getb(sp, PCIC_MISC1); - if ((c & PCIC_MISC1_5V_DETECT) == 0) - slt->pwr.vcc = 33; - else - slt->pwr.vcc = 50; - break; - case PCIC_PD6722: /* see above for why we do */ - break; /* none here */ - case PCIC_PD6729: - /* - * VS[12] signals are in slot1's - * extended reg 0xa for both slots. - */ - sp2 = &sc->slots[1]; - sp2->putb(sp2, PCIC_EXT_IND, PCIC_EXT_DATA); - c = sp2->getb(sp2, PCIC_EXTENDED); - if (sp == sp2) /* slot 1 */ - c >>= 2; - if ((c & PCIC_VS1A) == 0) - slt->pwr.vcc = 33; - else - slt->pwr.vcc = 50; - break; - default: - /* I have no idea how to do this for others */ - break; - } - - /* - * Regardless of the above, setting the Auto Power - * Switch Enable appears to help. - */ - reg |= PCIC_APSENA; - } - if (sc->flags & PCIC_RICOH_POWER) { - /* - * The ISA bridge have the 5V/3.3V in register - * 1, bit 7. However, 3.3V cards can only be - * detected if GPI_EN is disabled. - */ - c = sp->getb(sp, PCIC_STATUS); - c2 = sp->getb(sp, PCIC_CDGC); - if ((c & PCIC_RICOH_5VCARD) && (c2 & PCIC_GPI_EN) == 0) - slt->pwr.vcc = 33; - else - slt->pwr.vcc = 50; - } - /* Other power schemes here */ - - if (bootverbose && slt->pwr.vcc != -1) - device_printf(sc->dev, "Autodetected %d.%dV card\n", - slt->pwr.vcc / 10, slt->pwr.vcc %10); - } - if (slt->pwr.vcc == -1) { - if (bootverbose) - device_printf(sc->dev, - "Couldn't autodetect voltage, assuming 5.0V\n"); - dodefault = 1; - slt->pwr.vcc = 50; - } - - /* - * XXX Note: The Vpp controls varies quit a bit between bridge chips - * and the following might not be right in all cases. The Linux - * code and wildboar code bases are more complex. However, most - * applications want vpp == vcc and the following code does appear - * to do that for all bridge sets. - */ - if (slt->pwr.vpp == -1) - slt->pwr.vpp = slt->pwr.vcc; - switch(slt->pwr.vpp) { - default: - return (EINVAL); - case 0: - break; - case 50: - case 33: - reg |= PCIC_VPP_5V; - break; - case 120: - reg |= PCIC_VPP_12V; - break; - } - - if (slt->pwr.vcc) - reg |= PCIC_VCC_ON; /* Turn on Vcc */ - switch(slt->pwr.vcc) { - default: - return (EINVAL); - case 0: - break; - case 33: - /* - * The wildboar code has comments that state that - * the IBM KING controller doesn't support 3.3V - * on the "IBM Smart PC card drive". The code - * intemates that's the only place they have seen - * it used and that there's a boatload of issues - * with it. I'm not even sure this is right because - * the only docs I've been able to find say this is for - * 5V power. Of course, this "doc" is just code comments - * so who knows for sure. - */ - if (sc->flags & PCIC_KING_POWER) { - reg |= PCIC_VCC_5V_KING; - break; - } - if (sc->flags & PCIC_VG_POWER) { - pcic_setb(sp, PCIC_CVSR, PCIC_CVSR_VS); - break; - } - if (sc->flags & PCIC_PD_POWER) { - pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33); - break; - } - if (sc->flags & PCIC_RICOH_POWER) { - pcic_setb(sp, PCIC_RICOH_MCR2, PCIC_MCR2_VCC_33); - break; - } - if (sc->flags & PCIC_DF_POWER) - reg |= PCIC_VCC_3V; - break; - case 50: - if (sc->flags & PCIC_KING_POWER) - reg |= PCIC_VCC_5V_KING; - /* - * For all of the variant power schemes for 3.3V go - * ahead and turn off the 3.3V enable bit. For all - * bridges, the setting the Vcc on bit does the rest. - * Note that we don't have to turn off the 3.3V bit - * for the '365 step D since with the reg assigments - * to this point it doesn't get turned on. - */ - if (sc->flags & PCIC_VG_POWER) - pcic_clrb(sp, PCIC_CVSR, PCIC_CVSR_VS); - if (sc->flags & PCIC_PD_POWER) - pcic_clrb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33); - if (sc->flags & PCIC_RICOH_POWER) - pcic_clrb(sp, PCIC_RICOH_MCR2, PCIC_MCR2_VCC_33); - break; - } - sp->putb(sp, PCIC_POWER, reg); - if (bootverbose) - device_printf(sc->dev, "Power applied\n"); - DELAY(300*1000); - if (slt->pwr.vcc) { - reg |= PCIC_OUTENA; - sp->putb(sp, PCIC_POWER, reg); - if (bootverbose) - device_printf(sc->dev, "Output enabled\n"); - DELAY(100*1000); - if (bootverbose) - device_printf(sc->dev, "Settling complete\n"); - } - - /* - * Some chipsets will attempt to preclude us from supplying - * 5.0V to cards that only handle 3.3V. We seem to need to - * try 3.3V to paper over some power handling issues in other - * parts of the system. Maybe the proper detection of 3.3V cards - * now obviates the need for this hack, so put a printf in to - * warn the world about it. - */ - if (!(sp->getb(sp, PCIC_STATUS) & PCIC_POW) && dodefault) { - slt->pwr.vcc = 33; - slt->pwr.vpp = 0; - device_printf(sc->dev, - "Failed at 5.0V. Trying 3.3V. Please report message to mobile@freebsd.org\n"); - return (pcic_power(slt)); - } - if (bootverbose) - printf("Power complete.\n"); - return (0); -} - -/* - * tell the PCIC which irq we want to use. only the following are legal: - * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15. We require the callers of this - * routine to do the check for legality. - */ -static void -pcic_mapirq(struct slot *slt, int irq) -{ - struct pcic_slot *sp = slt->cdata; - - sp->sc->chip->map_irq(sp, irq); -} - -/* - * pcic_reset - Reset the card and enable initial power. This may - * need to be interrupt driven in the future. We should likely turn - * the reset on, DELAY for a period of time < 250ms, turn it off and - * tsleep for a while and check it when we're woken up. I think that - * we're running afoul of the card status interrupt glitching, causing - * an interrupt storm because the card doesn't seem to be able to - * clear this pin while in reset. - */ -static void -pcic_reset(void *chan) -{ - struct slot *slt = chan; - struct pcic_slot *sp = slt->cdata; - - if (bootverbose) - device_printf(sp->sc->dev, "reset %d ", slt->insert_seq); - switch (slt->insert_seq) { - case 0: /* Something funny happended on the way to the pub... */ - if (bootverbose) - printf("\n"); - return; - case 1: /* Assert reset */ - pcic_clrb(sp, PCIC_INT_GEN, PCIC_CARDRESET); - if (bootverbose) - printf("int is %x stat is %x\n", - sp->getb(sp, PCIC_INT_GEN), - sp->getb(sp, PCIC_STATUS)); - slt->insert_seq = 2; - timeout(pcic_reset, (void *)slt, hz/4); - return; - case 2: /* Deassert it again */ - pcic_setb(sp, PCIC_INT_GEN, PCIC_CARDRESET | PCIC_IOCARD); - if (bootverbose) - printf("int is %x stat is %x\n", - sp->getb(sp, PCIC_INT_GEN), - sp->getb(sp, PCIC_STATUS)); - slt->insert_seq = 3; - timeout(pcic_reset, (void *)slt, hz/4); - return; - case 3: /* Wait if card needs more time */ - if (bootverbose) - printf("int is %x stat is %x\n", - sp->getb(sp, PCIC_INT_GEN), - sp->getb(sp, PCIC_STATUS)); - if ((sp->getb(sp, PCIC_STATUS) & PCIC_READY) == 0) { - timeout(pcic_reset, (void *)slt, hz/10); - return; - } - } - slt->insert_seq = 0; - if (sp->controller == PCIC_PD6722 || sp->controller == PCIC_PD6710) { - sp->putb(sp, PCIC_TIME_SETUP0, 0x1); - sp->putb(sp, PCIC_TIME_CMD0, 0x6); - sp->putb(sp, PCIC_TIME_RECOV0, 0x0); - sp->putb(sp, PCIC_TIME_SETUP1, 1); - sp->putb(sp, PCIC_TIME_CMD1, 0xf); - sp->putb(sp, PCIC_TIME_RECOV1, 0); - } - selwakeuppri(&slt->selp, PZERO); -} - -/* - * pcic_disable - Disable the slot. I wonder if these operations can - * cause an interrupt we need to acknowledge? XXX - */ -static void -pcic_disable(struct slot *slt) -{ - struct pcic_slot *sp = slt->cdata; - - pcic_clrb(sp, PCIC_INT_GEN, PCIC_CARDTYPE | PCIC_CARDRESET); - pcic_mapirq(slt, 0); - slt->pwr.vcc = slt->pwr.vpp = 0; - pcic_power(slt); -} - -/* - * pcic_resume - Suspend/resume support for PCIC - */ -static void -pcic_resume(struct slot *slt) -{ - struct pcic_slot *sp = slt->cdata; - - pcic_do_mgt_irq(sp, slt->irq); - if (sp->controller == PCIC_PD6722) { - pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER); - pcic_setb(sp, PCIC_MISC2, PCIC_LPDM_EN); - } - if (sp->slt->state != inactive) - pcic_do_stat_delta(sp); -} - -int -pcic_activate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) - return (bus_generic_activate_resource(dev, child, type, - rid, r)); - - switch (type) { - case SYS_RES_IOPORT: { - struct io_desc *ip; - ip = &devi->slt->io[rid]; - if (ip->flags == 0) { - if (rid == 0) - ip->flags = IODF_WS | IODF_16BIT | IODF_CS16; - else - ip->flags = devi->slt->io[0].flags; - } - ip->flags |= IODF_ACTIVE; - ip->start = rman_get_start(r); - ip->size = rman_get_end(r) - rman_get_start(r) + 1; - err = pcic_io(devi->slt, rid); - if (err) - return (err); - break; - } - case SYS_RES_IRQ: - /* - * We actually defer the activation of the IRQ resource - * until the interrupt is registered to avoid stray - * interrupt messages. - */ - break; - case SYS_RES_MEMORY: { - struct mem_desc *mp; - if (rid >= NUM_MEM_WINDOWS) - return (EINVAL); - mp = &devi->slt->mem[rid]; - mp->flags |= MDF_ACTIVE; - mp->start = (caddr_t) rman_get_start(r); - mp->size = rman_get_end(r) - rman_get_start(r) + 1; - err = pcic_memory(devi->slt, rid); - if (err) - return (err); - break; - } - default: - break; - } - err = bus_generic_activate_resource(dev, child, type, rid, r); - return (err); -} - -int -pcic_deactivate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) - return (bus_generic_deactivate_resource(dev, child, type, - rid, r)); - - switch (type) { - case SYS_RES_IOPORT: { - struct io_desc *ip = &devi->slt->io[rid]; - ip->flags &= ~IODF_ACTIVE; - err = pcic_io(devi->slt, rid); - if (err) - return (err); - break; - } - case SYS_RES_IRQ: - break; - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - mp->flags &= ~(MDF_ACTIVE | MDF_ATTR); - err = pcic_memory(devi->slt, rid); - if (err) - return (err); - break; - } - default: - break; - } - err = bus_generic_deactivate_resource(dev, child, type, rid, r); - return (err); -} - -int -pcic_setup_intr(device_t dev, device_t child, struct resource *irq, - int flags, driver_intr_t *intr, void *arg, void **cookiep) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err; - - if (((1 << rman_get_start(irq)) & PCIC_INT_MASK_ALLOWED) == 0) { - device_printf(dev, "Hardware does not support irq %ld.\n", - rman_get_start(irq)); - return (EINVAL); - } - - err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg, - cookiep); - if (err == 0) - pcic_mapirq(devi->slt, rman_get_start(irq)); - else - device_printf(dev, "Error %d irq %ld\n", err, - rman_get_start(irq)); - return (err); -} - -int -pcic_teardown_intr(device_t dev, device_t child, struct resource *irq, - void *cookie) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - - pcic_mapirq(devi->slt, 0); - return (bus_generic_teardown_intr(dev, child, irq, cookie)); -} - -int -pcic_set_res_flags(device_t bus, device_t child, int restype, int rid, - u_long value) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err = 0; - - switch (restype) { - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - switch (value) { - case PCCARD_A_MEM_COM: - mp->flags &= ~MDF_ATTR; - break; - case PCCARD_A_MEM_ATTR: - mp->flags |= MDF_ATTR; - break; - case PCCARD_A_MEM_8BIT: - mp->flags &= ~MDF_16BITS; - break; - case PCCARD_A_MEM_16BIT: - mp->flags |= MDF_16BITS; - break; - } - err = pcic_memory(devi->slt, rid); - break; - } - default: - err = EOPNOTSUPP; - } - return (err); -} - -int -pcic_get_res_flags(device_t bus, device_t child, int restype, int rid, - u_long *value) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - int err = 0; - - if (value == 0) - return (ENOMEM); - - switch (restype) { - case SYS_RES_IOPORT: { - struct io_desc *ip = &devi->slt->io[rid]; - *value = ip->flags; - break; - } - case SYS_RES_MEMORY: { - struct mem_desc *mp = &devi->slt->mem[rid]; - *value = mp->flags; - break; - } - default: - err = EOPNOTSUPP; - } - return (err); -} - -int -pcic_set_memory_offset(device_t bus, device_t child, int rid, u_int32_t offset -#if __FreeBSD_version >= 500000 - ,u_int32_t *deltap -#endif - ) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - struct mem_desc *mp = &devi->slt->mem[rid]; - - mp->card = offset; -#if __FreeBSD_version >= 500000 - if (deltap) - *deltap = 0; /* XXX BAD XXX */ -#endif - return (pcic_memory(devi->slt, rid)); -} - -int -pcic_get_memory_offset(device_t bus, device_t child, int rid, u_int32_t *offset) -{ - struct pccard_devinfo *devi = device_get_ivars(child); - struct mem_desc *mp = &devi->slt->mem[rid]; - - if (offset == 0) - return (ENOMEM); - - *offset = mp->card; - - return (0); -} - -struct resource * -pcic_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - struct pcic_softc *sc = device_get_softc(dev); - - /* - * If we're routing via pci, we can share. - */ - if (sc->func_route == pcic_iw_pci && type == SYS_RES_IRQ) { - if (bootverbose) - device_printf(child, "Forcing IRQ to %d\n", sc->irq); - start = end = sc->irq; - flags |= RF_SHAREABLE; - } - - return (bus_generic_alloc_resource(dev, child, type, rid, start, end, - count, flags)); -} - -void -pcic_do_stat_delta(struct pcic_slot *sp) -{ - if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) != PCIC_CD) - pccard_event(sp->slt, card_removed); - else - pccard_event(sp->slt, card_inserted); -} -/* - * Wrapper function for pcicintr so that signatures match. - */ -void -pcic_isa_intr(void *arg) -{ - pcic_isa_intr1(arg); -} - -/* - * PCIC timer. If the controller doesn't have a free IRQ to use - * or if interrupt steering doesn't work, poll the controller for - * insertion/removal events. - */ -void -pcic_timeout(void *chan) -{ - struct pcic_softc *sc = (struct pcic_softc *) chan; - - if (pcic_isa_intr1(chan) != 0) { - device_printf(sc->dev, - "Static bug detected, ignoring hardware."); - sc->slot_poll = 0; - return; - } - sc->timeout_ch = timeout(sc->slot_poll, chan, hz/2); -} - -/* - * PCIC Interrupt handler. - * Check each slot in turn, and read the card status change - * register. If this is non-zero, then a change has occurred - * on this card, so send an event to the main code. - */ -int -pcic_isa_intr1(void *arg) -{ - int slot, s; - u_int8_t chg; - struct pcic_softc *sc = (struct pcic_softc *) arg; - struct pcic_slot *sp = &sc->slots[0]; - - s = splhigh(); - for (slot = 0; slot < PCIC_CARD_SLOTS; slot++, sp++) { - if (sp->slt == NULL) - continue; - if ((chg = sp->getb(sp, PCIC_STAT_CHG)) != 0) { - /* - * if chg is 0xff, then we know that we've hit - * the famous "static bug" for some desktop - * pcmcia cards. This is caused by static - * discharge frying the poor card's mind and - * it starts return 0xff forever. We return - * an error and stop polling the card. When - * we're interrupt based, we never see this. - * The card just goes away silently. - */ - if (chg == 0xff) { - splx(s); - return (EIO); - } - if (chg & PCIC_CDTCH) - pcic_do_stat_delta(sp); - } - } - splx(s); - return (0); -} - -int -pcic_isa_mapirq(struct pcic_slot *sp, int irq) -{ - irq = host_irq_to_pcic(irq); - if (irq == 0) - pcic_clrb(sp, PCIC_INT_GEN, 0xF); - else - sp->putb(sp, PCIC_INT_GEN, - (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq); - return (0); -} diff --git a/sys/pccard/pcic_isa.c b/sys/pccard/pcic_isa.c deleted file mode 100644 index a013346..0000000 --- a/sys/pccard/pcic_isa.c +++ /dev/null @@ -1,399 +0,0 @@ -/*- - * Copyright (c) 2001 M. Warner Losh. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/sysctl.h> -#include <sys/systm.h> - -#include <pccard/i82365.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> -#include <pccard/pcicvar.h> - -/* Get pnp IDs */ -#include <isa/isavar.h> - -#include <dev/pccard/pccardvar.h> -#include "card_if.h" - -static struct isa_pnp_id pcic_ids[] = { - {PCIC_PNP_ACTIONTEC, NULL}, /* AEI0218 */ - {PCIC_PNP_IBM3765, NULL}, /* IBM3765 */ - {PCIC_PNP_82365, NULL}, /* PNP0E00 */ - {PCIC_PNP_CL_PD6720, NULL}, /* PNP0E01 */ - {PCIC_PNP_VLSI_82C146, NULL}, /* PNP0E02 */ - {PCIC_PNP_82365_CARDBUS, NULL}, /* PNP0E03 */ - {PCIC_PNP_SCM_SWAPBOX, NULL}, /* SCM0469 */ - {PCIC_NEC_PC9801_102, NULL}, /* NEC8091 */ - {PCIC_NEC_PC9821RA_E01, NULL}, /* NEC8121 */ - {0} -}; - -static struct { - const char *name; - u_int32_t flags; -} bridges[] = { - { "Intel i82365SL-A/B", PCIC_AB_POWER}, - { "IBM PCIC", PCIC_AB_POWER}, - { "VLSI 82C146", PCIC_AB_POWER}, - { "Cirrus logic 6722", PCIC_PD_POWER}, - { "Cirrus logic 6710", PCIC_PD_POWER}, - { "Vadem 365", PCIC_VG_POWER}, - { "Vadem 465", PCIC_VG_POWER}, - { "Vadem 468", PCIC_VG_POWER}, - { "Vadem 469", PCIC_VG_POWER}, - { "Ricoh RF5C296", PCIC_RICOH_POWER}, - { "Ricoh RF5C396", PCIC_RICOH_POWER}, - { "IBM KING", PCIC_KING_POWER}, - { "Intel i82365SL-DF", PCIC_DF_POWER} -}; - -static pcic_intr_way_t pcic_isa_intr_way; -static pcic_init_t pcic_isa_init; - -struct pcic_chip pcic_isa_chip = { - pcic_isa_intr_way, - pcic_isa_intr_way, - pcic_isa_mapirq, - pcic_isa_init -}; - -/* - * Look for an Intel PCIC (or compatible). - * For each available slot, allocate a PC-CARD slot. - */ -static int -pcic_isa_probe(device_t dev) -{ - int slotnum, validslots = 0; - struct pcic_slot *sp; - struct pcic_slot *sp0; - struct pcic_slot *sp1; - struct pcic_slot spsave; - unsigned char c; - struct resource *r; - int rid; - struct pcic_softc *sc; - int error; - - /* Check isapnp ids */ - error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids); - if (error == ENXIO) - return (ENXIO); - - if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0) - bus_set_resource(dev, SYS_RES_IOPORT, 0, PCIC_PORT_0, - PCIC_NPORT); - rid = 0; - r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); - if (!r) { - if (bootverbose) - device_printf(dev, "Cannot get I/O range\n"); - return (ENOMEM); - } - - sc = (struct pcic_softc *) device_get_softc(dev); - sc->dev = dev; - sp = &sc->slots[0]; - for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { - /* - * Initialise the PCIC slot table. - */ - sp->getb = pcic_getb_io; - sp->putb = pcic_putb_io; - sp->bst = rman_get_bustag(r); - sp->bsh = rman_get_bushandle(r); - sp->offset = slotnum * PCIC_SLOT_SIZE; - sp->controller = -1; - } - - /* - * Prescan for the broken VLSI chips. - * - * According to the Linux PCMCIA code from David Hinds, - * working chipsets return 0x84 from their (correct) ID ports, - * while the broken ones would need to be probed at the new - * offset we set after we assume it's broken. - * - * Note: because of this, we may incorrectly detect a single - * slot vlsi chip as an i82365sl step D. I cannot find a - * datasheet for the affected chip, so that's the best we can - * do for now. - */ - sp0 = &sc->slots[0]; - sp1 = &sc->slots[1]; - if (sp0->getb(sp0, PCIC_ID_REV) == PCIC_VLSI82C146 && - sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { - spsave = *sp1; - sp1->bsh += 4; - sp1->offset = PCIC_SLOT_SIZE << 1; - if (sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { - *sp1 = spsave; - } else { - sp0->controller = PCIC_VLSI; - sp1->controller = PCIC_VLSI; - } - } - - /* - * Look for normal chipsets here. - */ - sp = &sc->slots[0]; - for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { - /* - * see if there's a PCMCIA controller here - * Intel PCMCIA controllers use 0x82 and 0x83 - * IBM clone chips use 0x88 and 0x89, apparently - */ - c = sp->getb(sp, PCIC_ID_REV); - sp->revision = -1; - switch(c) { - /* - * 82365 or clones. - */ - case PCIC_INTEL0: - case PCIC_INTEL1: - sp->controller = PCIC_I82365; - sp->revision = c & 1; - /* - * Check for Vadem chips by unlocking their extra - * registers and looking for valid ID. Bit 3 in - * the ID register is normally 0, except when - * PCIC_VADEMREV is set. Other bridges appear - * to ignore this frobbing. - */ - bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, 0x0E); - bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, 0x37); - pcic_setb(sp, PCIC_VMISC, PCIC_VADEMREV); - c = sp->getb(sp, PCIC_ID_REV); - if (c & 0x08) { - switch (sp->revision = c & 7) { - case 1: - sp->controller = PCIC_VG365; - break; - case 2: - sp->controller = PCIC_VG465; - break; - case 3: - sp->controller = PCIC_VG468; - break; - default: - sp->controller = PCIC_VG469; - break; - } - pcic_clrb(sp, PCIC_VMISC, PCIC_VADEMREV); - } - - /* - * Check for RICOH RF5C[23]96 PCMCIA Controller - */ - c = sp->getb(sp, PCIC_RICOH_ID); - if (c == PCIC_RID_396) - sp->controller = PCIC_RF5C396; - else if (c == PCIC_RID_296) - sp->controller = PCIC_RF5C296; - - break; - /* - * Intel i82365sl-DF step or maybe a vlsi 82c146 - * we detected the vlsi case earlier, so if the controller - * isn't set, we know it is an i82365sl step D. - */ - case PCIC_INTEL2: - if (sp->controller == -1) - sp->controller = PCIC_I82365SL_DF; - break; - case PCIC_IBM1: - case PCIC_IBM2: - sp->controller = PCIC_IBM; - sp->revision = c & 1; - break; - case PCIC_IBM3: - sp->controller = PCIC_IBM_KING; - sp->revision = c & 1; - break; - default: - continue; - } - /* - * Check for Cirrus logic chips. - */ - sp->putb(sp, PCIC_CLCHIP, 0); - c = sp->getb(sp, PCIC_CLCHIP); - if ((c & PCIC_CLC_TOGGLE) == PCIC_CLC_TOGGLE) { - c = sp->getb(sp, PCIC_CLCHIP); - if ((c & PCIC_CLC_TOGGLE) == 0) { - if (c & PCIC_CLC_DUAL) - sp->controller = PCIC_PD6722; - else - sp->controller = PCIC_PD6710; - sp->revision = 8 - ((c & 0x1F) >> 2); - } - } - device_set_desc(dev, bridges[(int) sp->controller].name); - sc->flags = bridges[(int) sp->controller].flags; - /* - * OK it seems we have a PCIC or lookalike. - * Allocate a slot and initialise the data structures. - */ - validslots++; - sp->slt = (struct slot *) 1; - /* - * Modem cards send the speaker audio (dialing noises) - * to the host's speaker. Cirrus Logic PCIC chips must - * enable this. There is also a Low Power Dynamic Mode bit - * that claims to reduce power consumption by 30%, so - * enable it and hope for the best. - */ - if (sp->controller == PCIC_PD6722) { - pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER); - pcic_setb(sp, PCIC_MISC2, PCIC_LPDM_EN); - } - } - bus_release_resource(dev, SYS_RES_IOPORT, rid, r); - return (validslots ? 0 : ENXIO); -} - -static int -pcic_isa_attach(device_t dev) -{ - struct pcic_softc *sc; - int rid; - struct resource *r; - int irq = 0; - int error; - - sc = device_get_softc(dev); - rid = 0; - r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); - if (!r) { - pcic_dealloc(dev); - return (ENXIO); - } - sc->iorid = rid; - sc->iores = r; - sc->csc_route = pcic_iw_isa; - sc->func_route = pcic_iw_isa; - sc->chip = &pcic_isa_chip; - - rid = 0; - r = NULL; - r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); - if (r == NULL && pcic_override_irq != 0) { - irq = pcic_override_irq; - r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1, - RF_ACTIVE); - } - if (r && ((1 << (rman_get_start(r))) & PCIC_INT_MASK_ALLOWED) == 0) { - device_printf(dev, - "Hardware does not support irq %d, trying polling.\n", - irq); - bus_release_resource(dev, SYS_RES_IRQ, rid, r); - irq = 0; - r = NULL; - } - sc->irqrid = rid; - sc->irqres = r; - irq = 0; - if (r != NULL) { - error = bus_setup_intr(dev, r, INTR_TYPE_MISC, - pcic_isa_intr, (void *) sc, &sc->ih); - if (error) { - pcic_dealloc(dev); - return (error); - } - irq = rman_get_start(r); - device_printf(dev, "management irq %d\n", irq); - } - sc->irq = irq; - if (irq == 0) { - sc->slot_poll = pcic_timeout; - sc->timeout_ch = timeout(sc->slot_poll, (void *) sc, hz/2); - device_printf(dev, "Polling mode\n"); - } - - return (pcic_attach(dev)); -} - -/* - * ISA cards can only do ISA interrupts. There's no need to do - * anything but check args for sanity. - */ -static int -pcic_isa_intr_way(struct pcic_slot *sp, enum pcic_intr_way iw) -{ - if (iw != pcic_iw_isa) - return (EINVAL); - return (0); -} - -/* - * No speicial initialization is necesary for ISA cards. - */ -static void -pcic_isa_init(device_t dev) -{ -} - -static device_method_t pcic_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pcic_isa_probe), - DEVMETHOD(device_attach, pcic_isa_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, bus_generic_print_child), - DEVMETHOD(bus_alloc_resource, pcic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, pcic_activate_resource), - DEVMETHOD(bus_deactivate_resource, pcic_deactivate_resource), - DEVMETHOD(bus_setup_intr, pcic_setup_intr), - DEVMETHOD(bus_teardown_intr, pcic_teardown_intr), - - /* Card interface */ - DEVMETHOD(card_set_res_flags, pcic_set_res_flags), - DEVMETHOD(card_get_res_flags, pcic_get_res_flags), - DEVMETHOD(card_set_memory_offset, pcic_set_memory_offset), - DEVMETHOD(card_get_memory_offset, pcic_get_memory_offset), - - { 0, 0 } -}; - -static driver_t pcic_driver = { - "pcic", - pcic_methods, - sizeof(struct pcic_softc) -}; - -DRIVER_MODULE(pcic, isa, pcic_driver, pcic_devclass, 0, 0); diff --git a/sys/pccard/pcic_pci.c b/sys/pccard/pcic_pci.c deleted file mode 100644 index 227043f..0000000 --- a/sys/pccard/pcic_pci.c +++ /dev/null @@ -1,1586 +0,0 @@ -/*- - * Copyright (c) 2000, 2002 M. Warner Losh. All Rights Reserved. - * Copyright (c) 1997 Ted Faber 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Absolutely no warranty of function or purpose is made by the author - * Ted Faber. - * - * 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$ - */ - -#define OBSOLETE_IN_6 - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/sysctl.h> -#include <sys/systm.h> - -#if __FreeBSD_version < 500000 -#include <pci/pcireg.h> -#include <pci/pcivar.h> -#else -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> -#endif - -#include <pccard/pcic_pci.h> -#include <pccard/i82365.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> -#include <pccard/pcicvar.h> - -#include <dev/pccard/pccardvar.h> -#include "card_if.h" - -#define PRVERB(x) do { \ - if (bootverbose) { device_printf x; } \ - } while (0) - -static int pcic_pci_get_memory(device_t dev); - -SYSCTL_DECL(_hw_pcic); - -static int pcic_ignore_function_1 = 0; -TUNABLE_INT("hw.pcic.ignore_function_1", &pcic_ignore_function_1); -SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_function_1, CTLFLAG_RDTUN, - &pcic_ignore_function_1, 0, - "When set, driver ignores pci function 1 of the bridge. This option\n\ -is obsolete and will be deleted before FreeBSD 4.8."); - -/* - * The following should be a hint, so we can do it on a per device - * instance, but this is convenient. Do not set this unless pci - * routing doesn't work. It is purposely vague and undocumented - * at the moment. Sadly, this seems to be needed way too often. - */ -static int pcic_intr_path = (int)pcic_iw_pci; -TUNABLE_INT("hw.pcic.intr_path", &pcic_intr_path); -SYSCTL_INT(_hw_pcic, OID_AUTO, intr_path, CTLFLAG_RDTUN, &pcic_intr_path, 0, - "Which path to send the interrupts over. Normally interrupts for\n\ -cardbus bridges are routed over the PCI bus (2). However, some laptops\n\ -will hang when using PCI interrupts due to bugs in this code. Those\n\ -bugs can be worked around by forcings ISA interrupts (1)."); - -static int pcic_init_routing = 0; -TUNABLE_INT("hw.pcic.init_routing", &pcic_init_routing); -SYSCTL_INT(_hw_pcic, OID_AUTO, init_routing, CTLFLAG_RDTUN, - &pcic_init_routing, 0, - "Force the interrupt routing to be initialized on those bridges where\n\ -doing so will cause probelms. This is very rare and generally is not\n\ -needed. The default of 0 is almost always appropriate. Only set to 1 if\n\ -instructed to do so for debugging. Only TI bridges are affected by this\n\ -option, and what the code does is of dubious value. This option is obsolete\n\ -and will be deleted before FreeBSD 4.8."); - -static int pcic_ignore_pci = 0; -TUNABLE_INT("hw.pcic.ignore_pci", &pcic_ignore_pci); -SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_pci, CTLFLAG_RDTUN, - &pcic_ignore_pci, 0, - "When set, driver ignores pci cardbus bridges it would otherwise claim.\n\ -Generally speaking, this option is not needed for anything other than as an\n\ -aid in debugging."); - -static int pcic_pd6729_intr_path = (int)pcic_iw_isa; -TUNABLE_INT("hw.pcic.pd6729_intr_path", &pcic_pd6729_intr_path); -SYSCTL_INT(_hw_pcic, OID_AUTO, pd6729_intr_path, CTLFLAG_RDTUN, - &pcic_pd6729_intr_path, 0, - "Determine the interrupt path or method for Cirrus Logic PD6729 and\n\ -similar I/O space based pcmcia bridge. Chips on a PCI expansion card need\n\ -a value of 2, while chips installed in a laptop need a value of 1 (which is\n\ -also the default). This is similar to hw.pcic.intr_path, but separate so\n\ -that it can default to ISA when intr_path defaults to PCI."); - -static int pcic_ti12xx_enable_pci_clock = 0; -TUNABLE_INT("hw.pcic.ti12xx_enable_pci_clock", &pcic_ti12xx_enable_pci_clock); -SYSCTL_INT(_hw_pcic, OID_AUTO, ti12xx_enable_pci_clock, CTLFLAG_RDTUN, - &pcic_ti12xx_enable_pci_clock, 0, - "Some TI-12xx parts need to have the PCI clock enabled. These designs do\n\ -not provide a clock themselves. Most of the reference boards have the\n\ -required oscillator parts, so the number of machines that needs this to be\n\ -set is vanishingly small."); - -static void pcic_pci_cardbus_init(device_t); -static pcic_intr_way_t pcic_pci_gen_func; -static pcic_intr_way_t pcic_pci_gen_csc; -static pcic_intr_mapirq_t pcic_pci_gen_mapirq; - -static pcic_intr_way_t pcic_pci_oz67xx_func; -static pcic_intr_way_t pcic_pci_oz67xx_csc; -static pcic_init_t pcic_pci_oz67xx_init; - -static pcic_intr_way_t pcic_pci_oz68xx_func; -static pcic_intr_way_t pcic_pci_oz68xx_csc; -static pcic_init_t pcic_pci_oz68xx_init; - -static pcic_intr_way_t pcic_pci_pd6729_func; -static pcic_intr_way_t pcic_pci_pd6729_csc; -static pcic_init_t pcic_pci_pd6729_init; - -static pcic_intr_way_t pcic_pci_pd68xx_func; -static pcic_intr_way_t pcic_pci_pd68xx_csc; -static pcic_init_t pcic_pci_pd68xx_init; - -static pcic_intr_way_t pcic_pci_ricoh_func; -static pcic_intr_way_t pcic_pci_ricoh_csc; -static pcic_init_t pcic_pci_ricoh_init; - -static pcic_intr_way_t pcic_pci_ti113x_func; -static pcic_intr_way_t pcic_pci_ti113x_csc; -static pcic_init_t pcic_pci_ti_init; - -static pcic_intr_way_t pcic_pci_ti12xx_func; -static pcic_intr_way_t pcic_pci_ti12xx_csc; - -static pcic_intr_way_t pcic_pci_topic_func; -static pcic_intr_way_t pcic_pci_topic_csc; -static pcic_init_t pcic_pci_topic_init; - -static struct pcic_chip pcic_pci_oz67xx_chip = { - pcic_pci_oz67xx_func, - pcic_pci_oz67xx_csc, - pcic_pci_gen_mapirq, - pcic_pci_oz67xx_init -}; - -static struct pcic_chip pcic_pci_oz68xx_chip = { - pcic_pci_oz68xx_func, - pcic_pci_oz68xx_csc, - pcic_pci_gen_mapirq, - pcic_pci_oz68xx_init -}; - -static struct pcic_chip pcic_pci_pd6729_chip = { - pcic_pci_pd6729_func, - pcic_pci_pd6729_csc, - pcic_pci_gen_mapirq, - pcic_pci_pd6729_init -}; - -static struct pcic_chip pcic_pci_pd68xx_chip = { - pcic_pci_pd68xx_func, - pcic_pci_pd68xx_csc, - pcic_pci_gen_mapirq, - pcic_pci_pd68xx_init -}; - -static struct pcic_chip pcic_pci_ricoh_chip = { - pcic_pci_ricoh_func, - pcic_pci_ricoh_csc, - pcic_pci_gen_mapirq, - pcic_pci_ricoh_init -}; - -static struct pcic_chip pcic_pci_ti113x_chip = { - pcic_pci_ti113x_func, - pcic_pci_ti113x_csc, - pcic_pci_gen_mapirq, - pcic_pci_ti_init -}; - -static struct pcic_chip pcic_pci_ti12xx_chip = { - pcic_pci_ti12xx_func, - pcic_pci_ti12xx_csc, - pcic_pci_gen_mapirq, - pcic_pci_ti_init -}; - -static struct pcic_chip pcic_pci_topic_chip = { - pcic_pci_topic_func, - pcic_pci_topic_csc, - pcic_pci_gen_mapirq, - pcic_pci_topic_init -}; - -static struct pcic_chip pcic_pci_generic_chip = { - pcic_pci_gen_func, - pcic_pci_gen_csc, - pcic_pci_gen_mapirq, - pcic_pci_cardbus_init -}; - -/* Chipset specific flags */ -#define TI_NO_MFUNC 0x10000 - -struct pcic_pci_table -{ - u_int32_t devid; - const char *descr; - int type; - u_int32_t flags; - struct pcic_chip *chip; -} pcic_pci_devs[] = { - { PCIC_ID_OMEGA_82C094, "Omega 82C094G", - PCIC_I82365, PCIC_DF_POWER, &pcic_pci_pd6729_chip }, - { PCIC_ID_CLPD6729, "Cirrus Logic PD6729/6730 PCI-PCMCIA Bridge", - PCIC_PD6729, PCIC_PD_POWER, &pcic_pci_pd6729_chip }, - { PCIC_ID_CLPD6832, "Cirrus Logic PD6832 PCI-CardBus Bridge", - PCIC_PD673X, PCIC_CARDBUS_POWER, &pcic_pci_pd68xx_chip }, - { PCIC_ID_CLPD6833, "Cirrus Logic PD6833 PCI-CardBus Bridge", - PCIC_PD673X, PCIC_CARDBUS_POWER, &pcic_pci_pd68xx_chip }, - { PCIC_ID_CLPD6834, "Cirrus Logic PD6834 PCI-CardBus Bridge", - PCIC_PD673X, PCIC_CARDBUS_POWER, &pcic_pci_pd68xx_chip }, - { PCIC_ID_OZ6729, "O2micro OZ6729 PC-Card Bridge", - PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz67xx_chip }, - { PCIC_ID_OZ6730, "O2micro OZ6730 PC-Card Bridge", - PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz67xx_chip }, - { PCIC_ID_OZ6832, "O2micro 6832/6833 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_OZ6860, "O2micro 6836/6860 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_OZ6872, "O2micro 6812/6872 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_OZ6912, "O2micro 6912 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_OZ6922, "O2micro 6922 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_OZ6933, "O2micro 6933 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz68xx_chip }, - { PCIC_ID_RICOH_RL5C465, "Ricoh RL5C465 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_ricoh_chip }, - { PCIC_ID_RICOH_RL5C475, "Ricoh RL5C475 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_ricoh_chip }, - { PCIC_ID_RICOH_RL5C476, "Ricoh RL5C476 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_ricoh_chip }, - { PCIC_ID_RICOH_RL5C477, "Ricoh RL5C477 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_ricoh_chip }, - { PCIC_ID_RICOH_RL5C478, "Ricoh RL5C478 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_ricoh_chip }, - { PCIC_ID_SMC_34C90, "SMC 34C90 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_CARDBUS_POWER, &pcic_pci_generic_chip }, - { PCIC_ID_TI1031, "TI PCI-1031 PCI-PCMCIA Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti113x_chip }, - { PCIC_ID_TI1130, "TI PCI-1130 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti113x_chip }, - { PCIC_ID_TI1131, "TI PCI-1131 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti113x_chip }, - { PCIC_ID_TI1210, "TI PCI-1210 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1211, "TI PCI-1211 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1220, "TI PCI-1220 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1221, "TI PCI-1221 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1225, "TI PCI-1225 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1250, "TI PCI-1250 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER | TI_NO_MFUNC, - &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1251, "TI PCI-1251 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER | TI_NO_MFUNC, - &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1251B, "TI PCI-1251B PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER | TI_NO_MFUNC, - &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1260, "TI PCI-1260 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1260B, "TI PCI-1260B PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1410, "TI PCI-1410 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1420, "TI PCI-1420 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1421, "TI PCI-1421 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1450, "TI PCI-1450 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER | TI_NO_MFUNC, - &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1451, "TI PCI-1451 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1510, "TI PCI-1510 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI1520, "TI PCI-1520 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI4410, "TI PCI-4410 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI4450, "TI PCI-4450 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI4451, "TI PCI-4451 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TI4510, "TI PCI-4510 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_CARDBUS_POWER, &pcic_pci_ti12xx_chip }, - { PCIC_ID_TOPIC95, "Toshiba ToPIC95 PCI-CardBus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_topic_chip }, - { PCIC_ID_TOPIC95B, "Toshiba ToPIC95B PCI-CardBus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_topic_chip }, - { PCIC_ID_TOPIC97, "Toshiba ToPIC97 PCI-CardBus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_topic_chip }, - { PCIC_ID_TOPIC100, "Toshiba ToPIC100 PCI-CardBus Bridge", - PCIC_I82365, PCIC_CARDBUS_POWER, &pcic_pci_topic_chip }, - { 0, NULL, 0, 0, NULL } -}; - -/* - * Read a register from the PCIC. - */ -static unsigned char -pcic_pci_getb2(struct pcic_slot *sp, int reg) -{ - return (bus_space_read_1(sp->bst, sp->bsh, sp->offset + reg)); -} - -/* - * Write a register on the PCIC - */ -static void -pcic_pci_putb2(struct pcic_slot *sp, int reg, unsigned char val) -{ - bus_space_write_1(sp->bst, sp->bsh, sp->offset + reg, val); -} - -/* - * lookup inside the table - */ -static struct pcic_pci_table * -pcic_pci_lookup(u_int32_t devid, struct pcic_pci_table *tbl) -{ - while (tbl->devid) { - if (tbl->devid == devid) - return (tbl); - tbl++; - } - return (NULL); -} - -/* - * The standard way to control fuction interrupts is via bit 7 in the BCR - * register. Some data sheets indicate that this is just for "intterupts" - * while others are clear that it is for function interrupts. When this - * bit is set, function interrupts are routed via the ExCA register. When - * this bit is clear, they are routed via the PCI bus, usually via the int - * in the INTPIN register. - */ -static int -pcic_pci_gen_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - u_int16_t bcr; - - bcr = pci_read_config(sp->sc->dev, CB_PCI_BRIDGE_CTRL, 2); - if (way == pcic_iw_pci) - bcr &= ~CB_BCR_INT_EXCA; - else - bcr |= CB_BCR_INT_EXCA; - pci_write_config(sp->sc->dev, CB_PCI_BRIDGE_CTRL, bcr, 2); - return (0); -} - -static int -pcic_pci_gen_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - return (0); -} - -/* - * The O2micro OZ67xx chips functions. - */ -static int -pcic_pci_oz67xx_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_oz67xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - /* - * Need datasheet to find out what's going on. However, the - * 68xx datasheets are so vague that it is hard to know what - * the right thing to do is. - */ - /* XXX */ - return (0); -} - - -static void -pcic_pci_oz67xx_init(device_t dev) -{ - device_printf(dev, "Warning: O2micro OZ67xx chips may not work\n"); - pcic_pci_cardbus_init(dev); -} - -/* - * The O2micro OZ68xx chips functions. - */ -static int -pcic_pci_oz68xx_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_oz68xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - /* - * The 68xx datasheets make it hard to know what the right thing - * to do here is. We do what we know, which is nothing, and - * hope for the best. - * - * XXX NEWCARD may have some useful code here. - */ - /* XXX */ - return (0); -} - -static void -pcic_pci_oz68xx_init(device_t dev) -{ - /* - * This is almost certainly incomplete. - */ - device_printf(dev, "Warning: O2micro OZ68xx chips may not work\n"); - pcic_pci_cardbus_init(dev); -} - -/* - * The Cirrus Logic PD6729/30. These are weird beasts, so be careful. - * They are ISA parts glued to the PCI bus and do not follow the yenta - * specification for cardbus bridges. They seem to be similar to the - * intel parts that were also cloned by o2micro and maybe others, but - * they are so much more common that the author doesn't have experience - * with them to know for sure. - */ -static int -pcic_pci_pd6729_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - /* - * For pci interrupts, we need to set bit 3 of extension register - * 3 to 1. For ISA interrupts, we need to clear it. - */ - sp->putb(sp, PCIC_EXT_IND, PCIC_EXTCTRL1); - if (way == pcic_iw_pci) - pcic_setb(sp, PCIC_EXTENDED, PCIC_EC1_CARD_IRQ_INV); - else - pcic_clrb(sp, PCIC_EXTENDED, PCIC_EC1_CARD_IRQ_INV); - - return (0); -} - -static int -pcic_pci_pd6729_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - /* - * For pci interrupts, we need to set bit 4 of extension register - * 3 to 1. For ISA interrupts, we need to clear it. - */ - sp->putb(sp, PCIC_EXT_IND, PCIC_EXTCTRL1); - if (way == pcic_iw_pci) - pcic_setb(sp, PCIC_EXTENDED, PCIC_EC1_CSC_IRQ_INV); - else - pcic_clrb(sp, PCIC_EXTENDED, PCIC_EC1_CSC_IRQ_INV); - - return (0); -} - - -static void -pcic_pci_pd6729_init(device_t dev) -{ - struct pcic_softc *sc = device_get_softc(dev); - - /* - * Tell the chip to do its routing thing. - */ - pcic_pci_pd6729_func(&sc->slots[0], sc->func_route); - pcic_pci_pd6729_csc(&sc->slots[0], sc->csc_route); -} - -/* - * Set up the CL-PD6832, 6833 and 6834. - */ -static int -pcic_pci_pd68xx_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_pd68xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - struct pcic_softc *sc = sp->sc; - device_t dev = sc->dev; - u_int32_t device_id = pci_get_devid(dev); - u_long bcr; - u_long cm1; - - /* - * CLPD6832 management interrupt enable bit is bit 11 - * (MGMT_IRQ_ENA) in bridge control register(offset 0x3d). - * When on, card status interrupts are ISA controlled by - * the ExCA register 0x05. - * - * The CLPD6833 does things differently. It doesn't have bit - * 11 in the bridge control register. Instead, this - * functionality appears to be in the "Configuration - * Miscellaneous 1" register bit 1. - * - * I'm assuming that the CLPD6834 does things like the '33 - */ - if (device_id == PCIC_ID_CLPD6832) { - bcr = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); - if (way == pcic_iw_pci) - bcr &= ~CLPD6832_BCR_MGMT_IRQ_ENA; - else - bcr |= CLPD6832_BCR_MGMT_IRQ_ENA; - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, bcr, 2); - } - if (device_id != PCIC_ID_CLPD6832) { - cm1 = pci_read_config(dev, CLPD6833_CFG_MISC_1, 4); - if (way == pcic_iw_pci) - cm1 &= ~CLPD6833_CM1_MGMT_EXCA_ENA; - else - cm1 |= CLPD6833_CM1_MGMT_EXCA_ENA; - pci_write_config(dev, CLPD6833_CFG_MISC_1, cm1, 4); - } - return (0); -} - -static void -pcic_pci_pd68xx_init(device_t dev) -{ - pcic_pci_cardbus_init(dev); -} - -static int -pcic_pci_ricoh_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_ricoh_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - struct pcic_softc *sc = sp->sc; - device_t dev = sc->dev; - u_int16_t mcr2; - - /* - * For CSC interrupts via ISA, we can't do that exactly. - * However, we can disable INT# routing, which is usually what - * we want. This is bit 7 in the field. Note, bit 6 looks - * interesting, but appears to be unnecessary. - */ - mcr2 = pci_read_config(dev, R5C47X_MISC_CONTROL_REGISTER_2, 2); - if (way == pcic_iw_pci) - mcr2 &= ~R5C47X_MCR2_CSC_TO_INTX_DISABLE; - else - mcr2 |= R5C47X_MCR2_CSC_TO_INTX_DISABLE; - pci_write_config(dev, R5C47X_MISC_CONTROL_REGISTER_2, mcr2, 2); - - return (0); -} - -static void -pcic_pci_ricoh_init(device_t dev) -{ - u_int16_t brgcntl; - u_int32_t device_id = pci_get_devid(dev); - - switch (device_id) { - case PCIC_ID_RICOH_RL5C465: - case PCIC_ID_RICOH_RL5C466: - /* - * Ricoh chips have a legacy bridge enable different than most - * Code cribbed from NEWBUS's bridge code since I can't find a - * datasheet for them that has register definitions. - */ - brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); - brgcntl &= ~(CB_BCR_RL_3E2_EN | CB_BCR_RL_3E0_EN); - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); - break; - } - pcic_pci_cardbus_init(dev); -} - -/* - * TI 1030, 1130, and 1131. - */ -static int -pcic_pci_ti113x_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - u_int32_t cardcntl; - device_t dev = sp->sc->dev; - - /* - * The TI-1130 (and 1030 and 1131) have a different interrupt - * routing control than the newer chips. assume we're not - * routing either csc or func interrupts via PCI, but enable - * as necessary when we find someone uses PCI interrupts. In - * order to get any pci interrupts, PCI_IRQ_ENA (bit 5) must - * be set. If either PCI_IREQ (bit 4) or PCI_CSC (bit 3) are - * set, then set bit 5 at the same time, since setting them - * enables the PCI interrupt routing. - * - * It also appears necessary to set the function routing bit - * in the bridge control register, but cardbus_init does that - * for us. - */ - cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); - if (way == pcic_iw_pci) - cardcntl |= TI113X_CARDCNTL_PCI_IREQ; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_IREQ; - if (cardcntl & (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC)) - cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_IRQ_ENA; - pci_write_config(dev, TI113X_PCI_CARD_CONTROL, cardcntl, 1); - - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_ti113x_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - u_int32_t cardcntl; - device_t dev = sp->sc->dev; - - /* - * The TI-1130 (and 1030 and 1131) have a different interrupt - * routing control than the newer cards. assume we're not - * routing PCI, but enable as necessary when we find someone - * uses PCI interrupts. In order to get any pci interrupts, - * PCI_IRQ_ENA (bit 5) must be set. If either PCI_IREQ (bit - * 4) or PCI_CSC (bit 3) are set, then set bit 5 at the same - * time, since setting them enables the PCI interrupt routing. - * - * It also appears necessary to set the function routing bit - * in the bridge control register, but cardbus_init does that - * for us. - */ - cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); - if (way == pcic_iw_pci) - cardcntl |= TI113X_CARDCNTL_PCI_CSC; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_CSC; - if (cardcntl & (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC)) - cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_IRQ_ENA; - pci_write_config(dev, TI113X_PCI_CARD_CONTROL, cardcntl, 1); - - return (0); -} - -static int -pcic_pci_ti12xx_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ - u_int32_t syscntl, devcntl, cardcntl, mfunc; - device_t dev = sp->sc->dev; - - syscntl = pci_read_config(dev, TI113X_PCI_SYSTEM_CONTROL, 4); - devcntl = pci_read_config(dev, TI113X_PCI_DEVICE_CONTROL, 1); - cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); - - /* - * Special code for the Orinoco cards (and a few others). They - * seem to need this special code to make them work only over pci - * interrupts. Sadly, doing this code also causes problems for - * many laptops, so we have to make it controlled by a tunable. - * Actually, experience has shown that this rarely, if ever, - * helps. - */ - if (way == pcic_iw_pci) { - /* - * pcic_init_routing seems to do nothing useful towards - * fixing the hang problems. I plan on removing it in - * 4.8 or so. - */ - if (pcic_init_routing) { - devcntl &= ~TI113X_DEVCNTL_INTR_MASK; - pci_write_config(dev, TI113X_PCI_DEVICE_CONTROL, - devcntl, 1); - syscntl |= TI113X_SYSCNTL_INTRTIE; - } - - /* - * I've had reports that we need the pci clock enabled, - * provide a hook to do so. The number of cards that - * require this is quite small. - */ - if (pcic_ti12xx_enable_pci_clock) { - syscntl |= TI12XX_SYSCNTL_PCI_CLOCK; - pci_write_config(dev, TI113X_PCI_SYSTEM_CONTROL, - syscntl, 4); - } - - /* - * Some PCI add-in cards don't have good EEPROMs on them, - * so they get this MUX register wrong. The MUX register - * defaults to 0, which is usually wrong for this register, - * so we initialize it to make sense. - * - * We don't bother to turn it off in the ISA case since it - * is an initialization issue. - * - * A few weird TI bridges don't have MFUNC, so filter - * those out too. - */ - if ((sp->sc->flags & TI_NO_MFUNC) == 0) { - mfunc = pci_read_config(dev, TI12XX_PCI_MFUNC, 4); - if (mfunc == 0) { - mfunc = (mfunc & ~TI12XX_MFUNC_PIN0) | - TI12XX_MFUNC_PIN0_INTA; - if ((syscntl & TI113X_SYSCNTL_INTRTIE) == 0) - mfunc = (mfunc & ~TI12XX_MFUNC_PIN1) | - TI12XX_MFUNC_PIN1_INTB; - pci_write_config(dev, TI12XX_PCI_MFUNC, mfunc, - 4); - } - } - - } - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_ti12xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - /* - * Nothing happens here. The TI12xx parts will route the - * CSC interrupt via PCI if ExCA register tells it to use - * interrupt 0. And via IRQ otherwise (except for reserved - * values which may or may not do anything). - * - * We just hope for the best here that doing nothing is the - * right thing to do. - */ - return (0); -} - -/* - * TI PCI-CardBus Host Adapter specific function code. - * This function is separated from pcic_pci_attach(). - * Takeshi Shibagaki(shiba@jp.freebsd.org). - */ -static void -pcic_pci_ti_init(device_t dev) -{ - u_int32_t syscntl, diagctl, devcntl, cardcntl; - u_int32_t device_id = pci_get_devid(dev); - int ti113x = (device_id == PCIC_ID_TI1031) || - (device_id == PCIC_ID_TI1130) || - (device_id == PCIC_ID_TI1131); - - syscntl = pci_read_config(dev, TI113X_PCI_SYSTEM_CONTROL, 4); - devcntl = pci_read_config(dev, TI113X_PCI_DEVICE_CONTROL, 1); - cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); - - if (ti113x) { - device_printf(dev, "TI113X PCI Config Reg: "); - if (syscntl & TI113X_SYSCNTL_CLKRUN_ENA) { - if (syscntl & TI113X_SYSCNTL_CLKRUN_SEL) - printf("[clkrun irq 12]"); - else - printf("[clkrun irq 10]"); - } - } else { - device_printf(dev, "TI12XX PCI Config Reg: "); - - /* - * Turn on async CSC interrupts. This appears to - * be the default, but the old, pre pci-aware, code - * did this and it appears PAO does as well. - */ - diagctl = pci_read_config(dev, TI12XX_PCI_DIAGNOSTIC, 1); - diagctl |= TI12XX_DIAG_CSC_INTR; - pci_write_config(dev, TI12XX_PCI_DIAGNOSTIC, diagctl, 1); - - /* - * Turn off Zoom Video. Some cards have this enabled, - * some do not but it causes problems when enabled. This - * register doesn't exist on the 1130 (and likely the 1131, - * but without a datasheet it is impossible to know). - * Some 12xx chips may not have it, but setting it is - * believed to be harmless on those models. - */ - pci_write_config(dev, TI12XX_PCI_MULTIMEDIA_CONTROL, 0, 4); - } - if (cardcntl & TI113X_CARDCNTL_RING_ENA) - printf("[ring enable]"); - if (cardcntl & TI113X_CARDCNTL_SPKR_ENA) - printf("[speaker enable]"); - if (syscntl & TI113X_SYSCNTL_PWRSAVINGS) - printf("[pwr save]"); - switch(devcntl & TI113X_DEVCNTL_INTR_MASK){ - case TI113X_DEVCNTL_INTR_ISA : - printf("[CSC parallel isa irq]"); - break; - case TI113X_DEVCNTL_INTR_SERIAL : - printf("[CSC serial isa irq]"); - break; - case TI113X_DEVCNTL_INTR_NONE : - printf("[pci only]"); - break; - case TI12XX_DEVCNTL_INTR_ALLSERIAL : - printf("[FUNC pci int + CSC serial isa irq]"); - break; - } - printf("\n"); - pcic_pci_cardbus_init(dev); -} - -/* - * Code for TOPIC chips - */ -static int -pcic_pci_topic_func(struct pcic_slot *sp, enum pcic_intr_way way) -{ -#ifdef THIS_BRAEKS_THINGS - device_t dev = sp->sc->dev; - u_int32_t scr; - - scr = pci_read_config(dev, TOPIC_SOCKET_CTRL, 4); - if (way == pcic_iw_pci) - scr |= TOPIC_SOCKET_CTRL_SCR_IRQSEL; - else - scr &= ~TOPIC_SOCKET_CTRL_SCR_IRQSEL; - pci_write_config(dev, TOPIC_SLOT_CTRL, scr, 4); -#endif - return (pcic_pci_gen_func(sp, way)); -} - -static int -pcic_pci_topic_csc(struct pcic_slot *sp, enum pcic_intr_way way) -{ - device_t dev = sp->sc->dev; - u_int32_t scr; - u_int32_t device_id; - - device_id = pci_get_devid(dev); - if (device_id == PCIC_ID_TOPIC100 || device_id == PCIC_ID_TOPIC97) { - scr = pci_read_config(dev, TOPIC_SLOT_CTRL, 4); - if (way == pcic_iw_pci) - scr |= TOPIC97_SLOT_CTRL_PCIINT; - else - scr &= ~TOPIC97_SLOT_CTRL_PCIINT; - pci_write_config(dev, TOPIC_SLOT_CTRL, scr, 4); - } - - return (0); -} - -static void -pcic_pci_topic_init(device_t dev) -{ - struct pcic_softc *sc = device_get_softc(dev); - u_int32_t reg; - u_int32_t device_id; - - device_id = pci_get_devid(dev); - reg = pci_read_config(dev, TOPIC_SLOT_CTRL, 4); - reg |= (TOPIC_SLOT_CTRL_SLOTON | TOPIC_SLOT_CTRL_SLOTEN | - TOPIC_SLOT_CTRL_ID_LOCK | TOPIC_SLOT_CTRL_CARDBUS); - reg &= ~TOPIC_SLOT_CTRL_SWDETECT; - if (device_id == PCIC_ID_TOPIC100 || device_id == PCIC_ID_TOPIC97) { - reg |= TOPIC97_SLOT_CTRL_PCIINT; - reg &= ~(TOPIC97_SLOT_CTRL_STSIRQP | TOPIC97_SLOT_CTRL_IRQP); - } - pci_write_config(dev, TOPIC_SLOT_CTRL, reg, 4); - pcic_pci_cardbus_init(dev); - - if (device_id == PCIC_ID_TOPIC100 || device_id == PCIC_ID_TOPIC97) { - /* - * We need to enable voltage sense and 3V cards explicitly - * in the bridge. The datasheets I have for both the - * ToPIC 97 and 100 both lists these ports. Without - * datasheets for the ToPIC95s, I can't tell if we need - * to do it there or not. - */ - pcic_setb(&sc->slots[0], PCIC_TOPIC_FCR, - PCIC_FCR_3V_EN | PCIC_FCR_VS_EN); - } -} - -static void -pcic_pci_cardbus_init(device_t dev) -{ - struct pcic_softc *sc = device_get_softc(dev); - u_int16_t brgcntl; - int unit; - - unit = device_get_unit(dev); - - brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); - brgcntl |= CB_BCR_WRITE_POST_EN | CB_BCR_MASTER_ABORT; - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); - - /* Turn off legacy address */ - pci_write_config(dev, CB_PCI_LEGACY16_IOADDR, 0, 2); - - /* - * Write zeros into the remaining memory I/O windows. This - * seems to turn off the pci configuration of these things and - * make the cardbus bridge use the values for memory - * programmed into the pcic registers. - */ - pci_write_config(dev, CB_PCI_MEMBASE0, 0, 4); - pci_write_config(dev, CB_PCI_MEMLIMIT0, 0, 4); - pci_write_config(dev, CB_PCI_MEMBASE1, 0, 4); - pci_write_config(dev, CB_PCI_MEMLIMIT1, 0, 4); - pci_write_config(dev, CB_PCI_IOBASE0, 0, 4); - pci_write_config(dev, CB_PCI_IOLIMIT0, 0, 4); - pci_write_config(dev, CB_PCI_IOBASE1, 0, 4); - pci_write_config(dev, CB_PCI_IOLIMIT1, 0, 4); - - /* - * Tell the chip to do its routing thing. - */ - sc->chip->func_intr_way(&sc->slots[0], sc->func_route); - sc->chip->csc_intr_way(&sc->slots[0], sc->csc_route); - - return; -} - -static const char * -pcic_pci_cardtype(u_int32_t stat) -{ - if (stat & CB_SS_NOTCARD) - return ("unrecognized by bridge"); - if ((stat & (CB_SS_16BIT | CB_SS_CB)) == (CB_SS_16BIT | CB_SS_CB)) - return ("16-bit and 32-bit (can't happen)"); - if (stat & CB_SS_16BIT) - return ("16-bit pccard"); - if (stat & CB_SS_CB) - return ("32-bit cardbus"); - return ("none (can't happen)"); -} - -/* - * Card insertion and removal code. The insertion events need to be - * debounced so that the noisy insertion/removal events don't result - * in the hardware being initialized many times, only to be torn down - * as well. This may also cause races with pccardd. Instead, we wait - * for the insertion signal to be stable for 0.5 seconds before we declare - * it to be a real insertion event. Removal is also debounced. We turn - * off interrupt servicing during the settling time to prevent infinite - * loops in the driver. - * - * Note: We only handle the card detect change events. We don't handle - * power events and status change events. - */ -static void -pcic_cd_change(void *arg) -{ - struct pcic_softc *sc = (struct pcic_softc *) arg; - struct pcic_slot *sp = &sc->slots[0]; - u_int32_t stat; - - sc->cd_pending = 0; - stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - - /* Status changed while present; remove the card from the system. */ - if (sc->cd_present) { - sc->cd_present = 0; - pccard_event(sp->slt, card_removed); - } - /* Nothing to do if the debounced state is 'not present'. */ - if ((stat & CB_SS_CD) != 0) - return; - - sc->cd_present = 1; - if (bootverbose && (stat & CB_SS_BADVCC) != 0) - device_printf(sc->dev, "BAD Vcc request: 0x%x\n", stat); - if ((stat & CB_SS_16BIT) == 0) - device_printf(sp->sc->dev, "Card type %s is unsupported\n", - pcic_pci_cardtype(stat)); - else - pccard_event(sp->slt, card_inserted); -} - -static void -pcic_pci_intr(void *arg) -{ - struct pcic_softc *sc = (struct pcic_softc *) arg; - struct pcic_slot *sp = &sc->slots[0]; - u_int32_t event; - - event = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_EVENT); - if (event != 0) { - if (bootverbose) - device_printf(sc->dev, "Event mask 0x%x\n", event); - - /* - * Treat all card-detect signal transitions the same way - * since we can't reliably tell if this is an insert or a - * remove event. Stop the card from getting interrupts and - * defer the insert/remove event until the CB_SOCKET_STATE - * signals have had time to settle. - */ - if ((event & CB_SE_CD) != 0) { - if (sc->cd_pending) { - untimeout(pcic_cd_change, arg, sc->cd_ch); - sc->cd_pending = 0; - } - sc->cd_pending = 1; - sc->cd_ch = timeout(pcic_cd_change, arg, hz/2); - sc->func_intr = NULL; - } - - /* Ack the interrupt */ - bus_space_write_4(sp->bst, sp->bsh, 0, event); - } - - /* - * Some TI chips also require us to read the old ExCA register for - * card status change when we route CSC via PCI! So, we go ahead - * and read it to clear the bits. Maybe we should check the status - * ala the ISA interrupt handler, but those changes should be caught - * in the CD change. - * - * We have to check it every interrupt because these bits can sometimes - * show up indepentently of the CB_SOCKET_EVENT register above. - */ - sp->getb(sp, PCIC_STAT_CHG); -} - -/* - * Return the ID string for the controller if the vendor/product id - * matches, NULL otherwise. - */ -static int -pcic_pci_probe(device_t dev) -{ - u_int8_t subclass; - u_int8_t progif; - const char *desc; - u_int32_t device_id; - struct pcic_pci_table *itm; - struct resource *res; - int rid; - - if (pcic_ignore_pci) - return (ENXIO); - device_id = pci_get_devid(dev); - desc = NULL; - itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); - if (pcic_ignore_function_1 && pci_get_function(dev) == 1) { - if (itm != NULL) - PRVERB((dev, "Ignoring function 1\n")); - return (ENXIO); - } - if (itm != NULL) - desc = itm->descr; - if (desc == NULL && pci_get_class(dev) == PCIC_BRIDGE) { - subclass = pci_get_subclass(dev); - progif = pci_get_progif(dev); - if (subclass == PCIS_BRIDGE_PCMCIA && progif == 0) - desc = "Generic PCI-PCMCIA Bridge"; - if (subclass == PCIS_BRIDGE_CARDBUS && progif == 0) - desc = "YENTA PCI-CardBus Bridge"; - if (bootverbose && desc) - printf("Found unknown %s devid 0x%x\n", desc, device_id); - } - if (desc == NULL) - return (ENXIO); - device_set_desc(dev, desc); - - /* - * Take us out of power down mode, if necessary. It also - * appears that even reading the power register is enough on - * some systems to cause correct behavior. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - /* Reset the power state. */ - device_printf(dev, "chip is in D%d power mode " - "-- setting to D0\n", pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - } - - /* - * Allocated/deallocate interrupt. This forces the PCI BIOS or - * other MD method to route the interrupts to this card. - * This so we get the interrupt number in the probe message. - * We only need to route interrupts when we're doing pci - * parallel interrupt routing. - * - * We use two different variables for the memory based and I/O - * based cards, so the check here is a little more complex than - * one would otherwise hope. - * - * XXX The bus code for PCI really should do this for us. - */ - if ((pcic_intr_path == pcic_iw_pci && - device_id != PCIC_ID_CLPD6729) || - (pcic_pd6729_intr_path == pcic_iw_pci && - device_id == PCIC_ID_CLPD6729)) { - rid = 0; -#ifdef __i386__ - /* - * IRQ 0 is invalid on x86, but not other platforms. - * If we have irq 0, then write 255 to force a new, non- - * bogus one to be assigned. I think that in -current - * the code in this ifdef may be obsolete with the new - * invalid mapping that we're doing in the pci layer -- imp - */ - if (pci_get_irq(dev) == 0) { - pci_set_irq(dev, 255); - pci_write_config(dev, PCIR_INTLINE, 255, 1); - } -#endif - res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); - if (res) - bus_release_resource(dev, SYS_RES_IRQ, rid, res); - } - - return (0); -} - -static void -pcic_pci_shutdown(device_t dev) -{ -/* - * More reports of things working w/o this code than with it. - */ -#if 0 - struct pcic_softc *sc; - struct pcic_slot *sp; - - sc = (struct pcic_softc *) device_get_softc(dev); - sp = &sc->slots[0]; - - /* - * Turn off the power to the slot in an attempt to - * keep the system from hanging on reboot. We also turn off - * card interrupts in an attempt to control interrupt storms. - * on some (all?) this has the effect of also turning off - * card status change interrupts. A side effect of writing 0 - * to INT_GEN is that the card is placed into "reset" mode - * where nothing happens until it is taken out of "reset" - * mode. - * - * Also, turn off the generation of status interrupts too. - */ - sp->putb(sp, PCIC_INT_GEN, 0); - sp->putb(sp, PCIC_STAT_INT, 0); - sp->putb(sp, PCIC_POWER, 0); - DELAY(4000); - - /* - * Writing to INT_GEN can cause an interrupt, so we blindly - * ack all possible interrupts here. Reading the stat change - * shouldn't be necessary, but some TI chipsets need it in the - * normal course of operations, so we do it here too. We can't - * lose any interrupts after this point, so go ahead and ack - * everything. The bits in INT_GEN clear upon reading them. - * We also set the interrupt mask to 0, in an effort to avoid - * getting further interrupts. - */ - bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_MASK, 0); - bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_EVENT, 0xffffffff); - sp->getb(sp, PCIC_STAT_CHG); -#endif -} - -/* - * Print out the config space - */ -static void -pcic_pci_print_config(device_t dev) -{ - int i; - - device_printf(dev, "PCI Configuration space:"); - for (i = 0; i < 256; i += 4) { - if (i % 16 == 0) - printf("\n 0x%02x: ", i); - printf("0x%08x ", pci_read_config(dev, i, 4)); - } - printf("\n"); -} - -/* - * Generic pci interrupt attach routine. It tries to understand all parts, - * and do sane things for those parts it does not understand. - */ -static int -pcic_pci_attach(device_t dev) -{ - u_int32_t device_id = pci_get_devid(dev); - u_long command; - struct pcic_slot *sp; - struct pcic_softc *sc; - u_int32_t sockbase; - u_int32_t stat; - struct pcic_pci_table *itm; - int rid; - int i; - struct resource *r = NULL; - int error; - u_long irq = 0; - driver_intr_t *intr = NULL; - - /* - * In sys/pci/pcireg.h, PCIR_COMMAND must be separated - * PCI_COMMAND_REG(0x04) and PCI_STATUS_REG(0x06). - * Takeshi Shibagaki(shiba@jp.freebsd.org). - */ - command = pci_read_config(dev, PCIR_COMMAND, 4); - command |= PCIM_CMD_PORTEN | PCIM_CMD_MEMEN; - pci_write_config(dev, PCIR_COMMAND, command, 4); - - sc = (struct pcic_softc *) device_get_softc(dev); - sp = &sc->slots[0]; - sp->sc = sc; - sockbase = pci_read_config(dev, 0x10, 4); - if (sockbase & 0x1) { - sc->iorid = CB_PCI_SOCKET_BASE; - sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, - &sc->iorid, RF_ACTIVE | RF_SHAREABLE); - if (sc->iores == NULL) - return (ENOMEM); - - sc->flags = PCIC_PD_POWER; - itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); - for (i = 0; i < 2; i++) { - sp[i].bst = rman_get_bustag(sc->iores); - sp[i].bsh = rman_get_bushandle(sc->iores); - sp[i].sc = sc; - sp[i].revision = 0; - sp[i].getb = pcic_getb_io; - sp[i].putb = pcic_putb_io; - sp[i].offset = i * PCIC_SLOT_SIZE; - sp[i].controller = itm ? itm->type : PCIC_PD6729; - if ((sp[i].getb(&sp[i], PCIC_ID_REV) & 0xc0) == 0x80) - sp[i].slt = (struct slot *) 1; - } - sc->csc_route = sc->func_route = pcic_pd6729_intr_path; - if (itm) - sc->flags = itm->flags; - /* - * We have to use the ISA interrupt routine for status - * changes since we don't have any "yenta" pci registers. - * We have to do this even when we're using pci type - * interrupts because on these cards the interrupts are - * cleared in the same way that the ISA cards clear them. - */ - intr = pcic_isa_intr; - } else { - sc->memrid = CB_PCI_SOCKET_BASE; - sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->memrid, RF_ACTIVE); - if (sc->memres == NULL && pcic_pci_get_memory(dev) != 0) - return (ENOMEM); - sp->getb = pcic_pci_getb2; - sp->putb = pcic_pci_putb2; - sp->offset = CB_EXCA_OFFSET; - sp->bst = rman_get_bustag(sc->memres); - sp->bsh = rman_get_bushandle(sc->memres); - itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); - if (itm != NULL) { - sp->controller = itm->type; - sp->revision = 0; - sc->flags = itm->flags; - } else { - /* By default, assume we're a D step compatible */ - sp->controller = PCIC_I82365SL_DF; - sp->revision = 0; - sc->flags = PCIC_CARDBUS_POWER; - } - /* All memory mapped cardbus bridges have these registers */ - sc->flags |= PCIC_YENTA_HIGH_MEMORY; - sp->slt = (struct slot *) 1; - sc->csc_route = pcic_intr_path; - sc->func_route = pcic_intr_path; - stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - sc->cd_present = (stat & CB_SS_CD) == 0; - } - sc->dev = dev; - if (itm) - sc->chip = itm->chip; - else - sc->chip = &pcic_pci_generic_chip; - - if (sc->csc_route == pcic_iw_pci) { - rid = 0; - r = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE | RF_SHAREABLE); - if (r == NULL) { - sc->csc_route = pcic_iw_isa; - sc->func_route = pcic_iw_isa; - device_printf(dev, - "No PCI interrupt routed, trying ISA.\n"); - } else { - if (intr == NULL) - intr = pcic_pci_intr; - irq = rman_get_start(r); - } - } - if (sc->csc_route == pcic_iw_isa) { - rid = 0; - irq = pcic_override_irq; - if (irq != 0) { - r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, - irq, 1, RF_ACTIVE); - if (r == NULL) { - device_printf(dev, - "Can't route ISA CSC interrupt.\n"); - pcic_dealloc(dev); - return (ENXIO); - } - device_printf(dev, - "Management interrupt on ISA IRQ %ld\n", irq); - if (intr == NULL) - intr = pcic_isa_intr; - } else { - sc->slot_poll = pcic_timeout; - sc->timeout_ch = timeout(sc->slot_poll, sc, hz/2); - device_printf(dev, "Polling mode\n"); - intr = NULL; - } - } - - /* - * Initialize AFTER we figure out what kind of interrupt we're - * going to be using, if any. - */ - if (!sc->chip) - panic("Bug: sc->chip not set!\n"); - sc->chip->init(dev); - - /* - * Now install the interrupt handler, if necessary. - */ - sc->irqrid = rid; - sc->irqres = r; - sc->irq = irq; - if (intr) { - error = bus_setup_intr(dev, r, INTR_TYPE_AV, intr, sc, &sc->ih); - if (error) { - pcic_dealloc(dev); - return (error); - } - } - if (bootverbose) - pcic_pci_print_config(dev); - return (pcic_attach(dev)); -} - -static int -pcic_pci_detach(device_t dev) -{ - return (EBUSY); /* Can't detach this device */ -} - -/* - * The PCI bus should do this for us. However, it doesn't quite yet, so - * we cope by doing it ourselves. If it ever does, this code can go quietly - * into that good night. - */ -static int -pcic_pci_get_memory(device_t dev) -{ - struct pcic_softc *sc; - u_int32_t sockbase; - - sc = (struct pcic_softc *) device_get_softc(dev); - sockbase = pci_read_config(dev, sc->memrid, 4); - if (sockbase >= 0x100000 && sockbase < 0xfffffff0) { - device_printf(dev, "Could not map register memory 0x%x\n", - sockbase); - return (ENOMEM); - } - pci_write_config(dev, sc->memrid, 0xffffffff, 4); - sockbase = pci_read_config(dev, sc->memrid, 4); - sockbase = (sockbase & 0xfffffff0) & -(sockbase & 0xfffffff0); -#define CARDBUS_SYS_RES_MEMORY_START 0x88000000 -#define CARDBUS_SYS_RES_MEMORY_END 0xFFFFFFFF - sc->memres = bus_generic_alloc_resource(device_get_parent(dev), - dev, SYS_RES_MEMORY, &sc->memrid, - CARDBUS_SYS_RES_MEMORY_START, CARDBUS_SYS_RES_MEMORY_END, - sockbase, RF_ACTIVE | rman_make_alignment_flags(sockbase)); - if (sc->memres == NULL) { - device_printf(dev, "Could not grab register memory\n"); - return (ENOMEM); - } - sockbase = rman_get_start(sc->memres); - pci_write_config(dev, sc->memrid, sockbase, 4); - device_printf(dev, "PCI Memory allocated: 0x%08x\n", sockbase); - return (0); -} - -static int -pcic_pci_gen_mapirq(struct pcic_slot *sp, int irq) -{ - /* - * If we're doing ISA interrupt routing, then just go to the - * generic ISA routine. Also, irq 0 means turn off the interrupts - * at the bridge. - */ - if (sp->sc->func_route == pcic_iw_isa || irq == 0) - return (pcic_isa_mapirq(sp, irq)); - - /* - * Ohterwise we're doing PCI interrupts. For those cardbus bridges - * that follow yenta (and the one pcmcia bridge that does), we don't - * do a thing to get the IRQ mapped into the system. However, - * for other controllers that are PCI, but not yetna compliant, we - * need to do some special mapping. - * - * XXX Maybe we shouldn't assume INTA#, but rather as the function - * XXX what Intline to use. - */ - if (sp->controller == PCIC_PD6729) { - /* - * INTA - 3 - * INTB - 4 - * INTC - 5 - * INTD - 7 - */ - sp->putb(sp, PCIC_INT_GEN, /* Assume INTA# */ - (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | 3); - return (0); - } - return (0); -} - -static void -pcic_pci_func_intr(void *arg) -{ - struct pcic_softc *sc = (struct pcic_softc *) arg; - struct pcic_slot *sp = &sc->slots[0]; - u_int32_t stat; - int doit = 0; - - /* - * The 6729 controller is a weird one, and we have to use - * the ISA registers to check to see if the card is there. - * Otherwise we look at the PCI state register to find out - * if the card is there. - */ - if (sp->controller == PCIC_PD6729) { - if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) == PCIC_CD) - doit = 1; - } - else { - stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); - if ((stat & CB_SS_CD) == 0 && sc->func_intr != 0) - doit = 1; - } - if (doit && sc->func_intr != NULL) - sc->func_intr(sc->func_arg); -} - -static int -pcic_pci_setup_intr(device_t dev, device_t child, struct resource *irq, - int flags, driver_intr_t *intr, void *arg, void **cookiep) -{ - struct pcic_softc *sc = device_get_softc(dev); - struct pcic_slot *sp = &sc->slots[0]; - int err; - - if (sc->func_route == pcic_iw_isa) - return(pcic_setup_intr(dev, child, irq, flags, intr, arg, - cookiep)); - -#if __FreeBSD_version >= 500000 - if ((flags & INTR_FAST) != 0) -#else - if ((flags & INTR_TYPE_FAST) != 0) -#endif - return (EINVAL); - if (sc->func_intr != NULL) { - device_printf(child, "Can't establish another ISR\n"); - return (EINVAL); - } - - err = bus_generic_setup_intr(dev, child, irq, flags, - pcic_pci_func_intr, sc, cookiep); - if (err != 0) - return (err); - sc->chip->map_irq(sp, rman_get_start(irq)); - sc->func_intr = intr; - sc->func_arg = arg; - return (0); -} - -static int -pcic_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, - void *cookie) -{ - struct pcic_softc *sc = device_get_softc(dev); - - if (sc->func_route == pcic_iw_isa) - return (pcic_teardown_intr(dev, child, irq, cookie)); - sc->func_intr = NULL; - return (bus_generic_teardown_intr(dev, child, irq, cookie)); -} - -static int -pcic_pci_resume(device_t dev) -{ - struct pcic_softc *sc = device_get_softc(dev); - - /* - * Some BIOSes will not save the BARs for the pci chips, so we - * must do it ourselves. If the BAR is reset to 0 for an I/O - * device, it will read back as 0x1, so no explicit test for - * memory devices are needed. - * - * Note: The PCI bus code should do this automatically for us on - * suspend/resume, but until it does, we have to cope. - */ - if (pci_read_config(dev, CB_PCI_SOCKET_BASE, 4) == 0) - pci_write_config(dev, CB_PCI_SOCKET_BASE, - rman_get_start(sc->memres), 4); - return (bus_generic_resume(dev)); -} - -static device_method_t pcic_pci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pcic_pci_probe), - DEVMETHOD(device_attach, pcic_pci_attach), - DEVMETHOD(device_detach, pcic_pci_detach), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, pcic_pci_resume), - DEVMETHOD(device_shutdown, pcic_pci_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_alloc_resource, pcic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, pcic_activate_resource), - DEVMETHOD(bus_deactivate_resource, pcic_deactivate_resource), - DEVMETHOD(bus_setup_intr, pcic_pci_setup_intr), - DEVMETHOD(bus_teardown_intr, pcic_pci_teardown_intr), - - /* Card interface */ - DEVMETHOD(card_set_res_flags, pcic_set_res_flags), - DEVMETHOD(card_get_res_flags, pcic_get_res_flags), - DEVMETHOD(card_set_memory_offset, pcic_set_memory_offset), - DEVMETHOD(card_get_memory_offset, pcic_get_memory_offset), - - {0, 0} -}; - -static driver_t pcic_pci_driver = { - "pcic", - pcic_pci_methods, - sizeof(struct pcic_softc) -}; - -DRIVER_MODULE(pcic, pci, pcic_pci_driver, pcic_devclass, 0, 0); |