Reorganize the attachement point for pcic (it was unattached and

floating before).  Attach pccard devices to pcic, one per slot
(although this may change to one per pcic).  pcic is now attached to
isa (to act as a bridge) and pccard is attached to pcic, cbb and
pc98ic (the last two are card bus bridge and the pc98ic version of
pcic, neither of which are in the tree yet).  Move pccard compat code
into pccard/pccard_compat.c.

THIS REQUIRES A CONFIG FILE CHANGE.  You must change your pcic/card
entries to be:
# PCCARD (PCMCIA) support
controller	pcic0	at isa?
controller	pcic1	at isa?
controller	card0

The old system was upside down and this corrects that problem.  It
will make it easier to add support for YENTA pccard/card bus bridges.

Much more cleanup needs to happen before newbus devices can have
pccard attachments.  My previous commit's comments were premature.
This commit is contained in:
Warner Losh 1999-10-15 17:29:21 +00:00
parent ae409c2b97
commit b5137699ae
8 changed files with 64 additions and 310 deletions

View File

@ -1810,11 +1810,11 @@ device bktr0
#
# PCCARD/PCMCIA
#
# card: slot controller
# pcic: slots
# card: pccard slots
# pcic: isa/pccard bridge
controller pcic0 at isa?
controller pcic1 at isa?
controller card0
device pcic0 at card?
device pcic1 at card?
# You may need to reset all pccards after resuming
options PCIC_RESUME_RESET # reset after resume

View File

@ -1810,11 +1810,11 @@ device bktr0
#
# PCCARD/PCMCIA
#
# card: slot controller
# pcic: slots
# card: pccard slots
# pcic: isa/pccard bridge
controller pcic0 at isa?
controller pcic1 at isa?
controller card0
device pcic0 at card?
device pcic1 at card?
# You may need to reset all pccards after resuming
options PCIC_RESUME_RESET # reset after resume

View File

@ -1810,11 +1810,11 @@ device bktr0
#
# PCCARD/PCMCIA
#
# card: slot controller
# pcic: slots
# card: pccard slots
# pcic: isa/pccard bridge
controller pcic0 at isa?
controller pcic1 at isa?
controller card0
device pcic0 at card?
device pcic1 at card?
# You may need to reset all pccards after resuming
options PCIC_RESUME_RESET # reset after resume

View File

@ -139,8 +139,8 @@ device apm0 at nexus? disable flags 0x31 # Advanced Power Management
# PCCARD (PCMCIA) support
controller card0
device pcic0 at card?
device pcic1 at card?
controller pcic0 at isa?
controller pcic1 at isa?
# Serial (COM) ports
device sio0 at isa? port IO_COM1 flags 0x10 irq 4

View File

@ -17,7 +17,6 @@ int pccard_alloc_intr __P((u_int imask, ointhand2_t *hand, int unit,
u_int *maskp, u_int *pcic_imask));
#endif
void pccard_remove_driver __P((struct pccard_device *));
int pcic_probe __P((void)); /* XXX should be linker set */
enum beepstate { BEEP_ON, BEEP_OFF };

View File

@ -504,8 +504,6 @@ pccard_alloc_slot(struct slot_ctrl *ctrl)
ctrl->maxmem = NUM_MEM_WINDOWS;
if (ctrl->maxio > NUM_IO_WINDOWS)
ctrl->maxio = NUM_IO_WINDOWS;
printf("pcic: pccard bridge %s (%d mem & %d I/O windows)\n",
ctrl->name, ctrl->maxmem, ctrl->maxio);
}
callout_handle_init(&slt->insert_ch);
callout_handle_init(&slt->poff_ch);
@ -573,7 +571,7 @@ allocate_driver(struct slot *slt, struct dev_desc *desc)
struct pccard_device *drv;
device_t pccarddev;
char devnam[128];
int err, irq = 0, s;
int err, irq = 0;
pccarddev = devclass_get_device(pccard_devclass, 0);
snprintf(devnam, sizeof(devnam), "pccard-%s", desc->name);

View File

@ -86,7 +86,7 @@ pccard_add_children(device_t dev, int busno)
static int
pccard_probe(device_t dev)
{
device_set_desc(dev, "PC Card bus -- KLUDGE version");
device_set_desc(dev, "PC Card bus -- kludge version");
return pccard_add_children(dev, device_get_unit(dev));
}
@ -162,171 +162,6 @@ static driver_t pccard_driver = {
1, /* no softc */
};
DRIVER_MODULE(pccard, nexus, pccard_driver, pccard_devclass, 0, 0);
/* ============================================================ */
static int
pccnbk_probe(device_t dev)
{
char devnam[128];
const char *name;
struct pccard_devinfo *devi = device_get_ivars(dev);
if (devi) {
name = device_get_name(dev);
snprintf(devnam, sizeof(devnam), "pccard-%s",
devi->drv->name);
if (!name || strcmp(name, devnam) != 0)
return ENXIO;
device_set_desc(dev, devi->drv->name);
return 0;
}
return ENXIO;
}
static int
pccnbk_attach(device_t dev)
{
struct pccard_devinfo *devi = device_get_ivars(dev);
struct pccard_device *drv;
struct slot *slt;
int err;
int s;
slt = devi->slt;
drv = devi->drv;
devi->next = slt->devices;
slt->devices = devi;
s = splhigh();
err = drv->enable(devi);
splx(s);
/*
* If the enable functions returns no error, then the
* device has been successfully installed. If so, then
* attach it to the slot, otherwise free it and return
* the error. We assume that when we free the device,
* it will also set 'running' to off.
*/
if (err) {
printf("pccard: %s%d Enable failed %d\n", devi->drv->name,
devi->isahd.id_unit, err);
pccard_remove_device(devi);
}
return(err);
}
/*
* Allocate resources for this device in the rman system.
*/
int
pccnbk_alloc_resources(device_t dev)
{
struct pccard_devinfo *devi = device_get_ivars(dev);
int rid;
u_long start;
u_long end;
u_long count;
start = devi->isahd.id_iobase;
count = devi->isahd.id_iosize;
end = start + count - 1;
rid = 0;
devi->iorv = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
SYS_RES_IOPORT, &rid, start, end, count, RF_ACTIVE);
if (!devi->iorv) {
printf("Cannot allocate ports 0x%lx-0x%lx\n", start, end);
return (ENOMEM);
}
rid = 0;
start = end = ffs(devi->isahd.id_irq) - 1;
count = 1;
devi->irqrv = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
SYS_RES_IRQ, &rid, start, end, count, RF_ACTIVE);
if (!devi->irqrv) {
return (ENOMEM);
}
return(0);
}
void
pccnbk_release_resources(device_t dev)
{
struct pccard_devinfo *devi = device_get_ivars(dev);
u_long start;
u_long end;
u_long count;
start = devi->isahd.id_iobase;
count = devi->isahd.id_iosize;
end = start + count - 1;
if (devi->iorv) {
BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
SYS_RES_IOPORT, 0, devi->iorv);
devi->iorv = NULL;
}
if (devi->irqrv) {
BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, SYS_RES_IRQ,
0, devi->irqrv);
devi->irqrv = NULL;
}
}
static device_method_t pccnbk_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pccnbk_probe),
DEVMETHOD(device_attach, pccnbk_attach),
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_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_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),
{ 0, 0 }
};
void
pccnbk_wrap_old_driver(struct pccard_device *drv)
{
char devnam[128];
char *nm;
driver_t *driver;
snprintf(devnam, sizeof(devnam), "pccard-%s", drv->name);
driver = malloc(sizeof(driver_t), M_DEVBUF, M_NOWAIT);
if (!driver)
return;
bzero(driver, sizeof(driver_t));
/* XXX May create a memory leak for load/unload :-( XXX */
nm = malloc(strlen(devnam) + 1, M_DEVBUF, M_NOWAIT);
strcpy(nm, devnam);
driver->name = nm;
driver->methods = pccnbk_methods;
driver->softc = sizeof(struct pccard_device);
driver->priv = drv;
devclass_add_driver(pccard_devclass, driver);
drv->driver = driver;
}
#if 0
static devclass_t pccnbk_devclass;
static driver_t pccnbk_driver = {
"pccnbk",
pccnbk_methods,
1, /* no softc */
};
DRIVER_MODULE(pccnbk, pccard, pccnbk_driver, pccnbk_devclass, 0, 0);
#endif
DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
DRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
DRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);

View File

@ -75,11 +75,8 @@ static void pcic_mapirq __P((struct slot *, int));
static timeout_t pcictimeout;
static struct callout_handle pcictimeout_ch
= CALLOUT_HANDLE_INITIALIZER(&pcictimeout_ch);
static int pcic_modevent __P((module_t, int, void *));
static int pcic_unload __P((void));
static int pcic_memory(struct slot *, int);
static int pcic_io(struct slot *, int);
static u_int build_freelist(u_int);
/*
* Per-slot data table.
@ -206,84 +203,6 @@ int unregister_pcic_intr(int intr, ointhand2_t handler)
#endif /* APIC_IO */
/*
* Loadable kernel module interface.
*/
/*
* Module handler that processes loads and unloads.
* Once the module is loaded, the probe routine
* is called to install the slots (if any).
*/
static int
pcic_modevent(module_t mod, int what, void *arg)
{
int err = 0; /* default = success*/
static int pcic_started = 0;
switch (what) {
case MOD_LOAD:
/*
* Call the probe routine to find the slots. If
* no slots exist, then don't bother loading the module.
* XXX but this is not appropriate as a static module.
*/
if (pcic_probe())
pcic_started = 1;
break;
case MOD_UNLOAD:
/*
* Attempt to unload the slot driver.
*/
if (pcic_started) {
printf("Unloading PCIC driver\n");
err = pcic_unload();
pcic_started = 0;
}
break; /* Success*/
default: /* we only care about load/unload; ignore shutdown */
break;
}
return(err);
}
static moduledata_t pcic_mod = {
"pcic",
pcic_modevent,
0
};
/* After configure() has run.. bring on the new bus system! */
DECLARE_MODULE(pcic, pcic_mod, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE);
/*
* pcic_unload - Called when unloading a kernel module.
* Disables interrupts and resets PCIC.
*/
static int
pcic_unload()
{
int slot;
struct pcic_slot *sp = pcic_slots;
untimeout(pcictimeout, 0, pcictimeout_ch);
if (pcic_irq) {
for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, sp++) {
if (sp->slt)
sp->putb(sp, PCIC_STAT_INT, 0);
}
unregister_pcic_intr(pcic_irq, pcicintr);
}
pccard_remove_controller(&cinfo);
return(0);
}
#if 0
static void
pcic_dump_attributes(unsigned char *scratch, int maxlen)
@ -308,43 +227,6 @@ pcic_dump_attributes(unsigned char *scratch, int maxlen)
}
#endif
static void
nullfunc(int arg)
{
/* empty */
}
static u_int
build_freelist(u_int pcic_mask)
{
int irq;
u_int mask, freemask;
/* No free IRQs (yet). */
freemask = 0;
/* Walk through all of the IRQ's and find any that aren't allocated. */
for (irq = 1; irq < ICU_LEN; irq++) {
/*
* If the PCIC controller can't generate it, don't
* bother checking to see if it it's free.
*/
mask = 1 << irq;
if (!(mask & pcic_mask)) continue;
/* See if the IRQ is free. */
if (register_pcic_intr(irq, 0, 0, nullfunc, NULL, irq) == 0) {
/* Give it back, but add it to the mask */
INTRMASK(freemask, mask);
unregister_pcic_intr(irq, nullfunc);
}
}
#ifdef PCIC_DEBUG
printf("Freelist of IRQ's <0x%x>\n", freemask);
#endif
return freemask;
}
/*
* entry point from main code to map/unmap memory context.
*/
@ -571,18 +453,22 @@ printf("Map I/O 0x%x (size 0x%x) on Window %d\n", ip->start, ip->size, win);
* of slot 1. Assume it's the only PCIC whose vendor ID is 0x84,
* contact Nate Williams <nate@FreeBSD.org> if incorrect.
*/
int
pcic_probe(void)
static int
pcic_probe(device_t dev)
{
int slotnum, validslots = 0;
u_int free_irqs, desired_irq;
struct slot *slt;
struct pcic_slot *sp;
unsigned char c;
int i;
static int maybe_vlsi = 0;
if (device_get_unit(dev) != 0)
return ENXIO;
/* Determine the list of free interrupts */
free_irqs = build_freelist(PCIC_INT_MASK_ALLOWED);
free_irqs = PCIC_INT_MASK_ALLOWED;
/*
* Initialise controller information structure.
@ -749,6 +635,7 @@ pcic_probe(void)
cinfo.name = "Unknown!";
break;
}
device_set_desc(dev, cinfo.name);
/*
* OK it seems we have a PCIC or lookalike.
* Allocate a slot and initialise the data structures.
@ -765,7 +652,6 @@ pcic_probe(void)
* then attempt to get one.
*/
if (pcic_irq == 0) {
pcic_imask = soft_imask;
/* See if the user has requested a specific IRQ */
@ -851,7 +737,12 @@ pcic_probe(void)
#endif /* PC98 */
if (validslots && pcic_irq <= 0)
pcictimeout_ch = timeout(pcictimeout, 0, hz/2);
return(validslots);
if (validslots) {
for (i = 0; i < validslots; i++) {
device_add_child(dev, NULL, -1, NULL);
}
}
return(validslots ? 0 : ENXIO);
}
/*
@ -1181,3 +1072,34 @@ pcic_resume(struct slot *slt)
setb(sp, PCIC_MISC2, PCIC_LPDM_EN);
}
}
static device_method_t pcic_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pcic_probe),
DEVMETHOD(device_attach, bus_generic_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, 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),
{ 0, 0 }
};
devclass_t pcic_devclass;
static driver_t pcic_driver = {
"pcic",
pcic_methods,
1, /* no softc */
};
DRIVER_MODULE(pcic, isa, pcic_driver, pcic_devclass, 0, 0);