MFC: Remove OLDCARD. It only panics on my pc98 laptop. I'll fix cbb to attach to isa.
Approved by: re (scottl)
This commit is contained in:
parent
91cfbaebd1
commit
9fc8aec782
@ -2139,24 +2139,10 @@ device nmdm
|
||||
#
|
||||
device bktr
|
||||
|
||||
#
|
||||
# PC Card/PCMCIA
|
||||
# (OLDCARD)
|
||||
#
|
||||
# card: pccard slots
|
||||
# pcic: isa/pccard bridge
|
||||
#device pcic
|
||||
#hint.pcic.0.at="isa"
|
||||
#hint.pcic.1.at="isa"
|
||||
#device card 1
|
||||
|
||||
#
|
||||
# PC Card/PCMCIA and Cardbus
|
||||
# (NEWCARD)
|
||||
#
|
||||
# Note that NEWCARD and OLDCARD are incompatible. Do not use both at the same
|
||||
# time.
|
||||
#
|
||||
# pccbb: pci/cardbus bridge implementing YENTA interface
|
||||
# pccard: pccard slots
|
||||
# cardbus: cardbus slots
|
||||
|
@ -92,29 +92,19 @@ crypto/des/arch/i386/des_enc.S optional crypto
|
||||
crypto/des/des_ecb.c optional crypto
|
||||
crypto/des/des_setkey.c optional crypto
|
||||
dev/aic/aic_cbus.c optional aic isa
|
||||
dev/aic/aic_pccard.c optional aic card
|
||||
dev/an/if_an_pccard.c optional an card
|
||||
dev/ar/if_ar.c optional ar
|
||||
dev/ar/if_ar_pci.c optional ar pci
|
||||
dev/ata/ata-card.c optional ata card
|
||||
dev/awi/if_awi_pccard.c optional awi card
|
||||
dev/cnw/if_cnw.c optional cnw card
|
||||
dev/cp/cpddk.c optional cp
|
||||
dev/cp/if_cp.c optional cp
|
||||
dev/cs/if_cs_pccard.c optional cs card
|
||||
dev/ct/bshw_machdep.c optional ct
|
||||
dev/ct/ct.c optional ct
|
||||
dev/ct/ct_isa.c optional ct isa
|
||||
dev/ed/if_ed_cbus.c optional ed isa
|
||||
dev/ed/if_ed_pccard.c optional ed card
|
||||
dev/ed/if_ed_wd80x3.c optional ed isa
|
||||
dev/ep/if_ep_pccard.c optional ep card
|
||||
dev/ex/if_ex_pccard.c optional ex card
|
||||
dev/fb/fb.c optional fb
|
||||
dev/fb/fb.c optional gdc
|
||||
dev/fb/splash.c optional splash
|
||||
dev/fe/if_fe_cbus.c optional fe isa
|
||||
dev/fe/if_fe_pccard.c optional fe card
|
||||
dev/hwpmc/hwpmc_amd.c optional hwpmc
|
||||
dev/hwpmc/hwpmc_pentium.c optional hwpmc
|
||||
dev/hwpmc/hwpmc_piv.c optional hwpmc
|
||||
@ -128,20 +118,14 @@ dev/lnc/if_lnc_cbus.c optional lnc isa
|
||||
dev/mem/memutil.c optional mem
|
||||
dev/mse/mse.c optional mse
|
||||
dev/mse/mse_cbus.c optional mse isa
|
||||
dev/ncv/ncr53c500_pccard.c optional ncv card
|
||||
dev/nsp/nsp_pccard.c optional nsp card
|
||||
dev/ppc/ppc_puc.c optional ppc puc pci
|
||||
dev/ray/if_ray.c optional ray card
|
||||
dev/sbni/if_sbni.c optional sbni
|
||||
dev/sbni/if_sbni_pci.c optional sbni pci
|
||||
dev/sio/sio_pccard.c optional sio card
|
||||
dev/sn/if_sn_pccard.c optional sn card
|
||||
dev/snc/dp83932.c optional snc
|
||||
dev/snc/dp83932subr.c optional snc
|
||||
dev/snc/if_snc.c optional snc
|
||||
dev/snc/if_snc_cbus.c optional snc isa
|
||||
dev/snc/if_snc_pccard.c optional snc card
|
||||
dev/stg/tmc18c30_pccard.c optional stg card
|
||||
dev/snc/if_snc_pccard.c optional snc pccard
|
||||
dev/syscons/apm/apm_saver.c optional apm_saver apm
|
||||
dev/syscons/schistory.c optional sc
|
||||
dev/syscons/scmouse.c optional sc
|
||||
@ -151,8 +135,6 @@ dev/syscons/scvidctl.c optional sc
|
||||
dev/syscons/syscons.c optional sc
|
||||
dev/syscons/sysmouse.c optional sc
|
||||
dev/uart/uart_cpu_pc98.c optional uart
|
||||
dev/wi/if_wi_pccard.c optional wi card
|
||||
dev/xe/if_xe_pccard.c optional xe card
|
||||
geom/geom_bsd.c standard
|
||||
geom/geom_bsd_enc.c standard
|
||||
geom/geom_pc98.c standard
|
||||
@ -369,13 +351,6 @@ pc98/pc98/canbus.c optional canbus
|
||||
pc98/pc98/canbus_if.m optional canbus
|
||||
pc98/pc98/machdep.c standard
|
||||
pc98/pc98/pc98_machdep.c standard
|
||||
pccard/pccard.c optional card
|
||||
pccard/pccard_beep.c optional card
|
||||
pccard/pccard_nbk.c optional card
|
||||
pccard/pcic.c optional pcic card
|
||||
pccard/pcic_isa.c optional pcic card isa
|
||||
pccard/pcic_pci.c optional pcic card pci
|
||||
pccard/mecia.c optional mecia card
|
||||
pci/agp_ali.c optional agp
|
||||
pci/agp_amd.c optional agp
|
||||
pci/agp_i810.c optional agp
|
||||
|
@ -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);
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
1344
sys/pccard/pcic.c
1344
sys/pccard/pcic.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user