mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
54570134fe
controller found in many of the early NOTE98 machines that were produced. This controller is completely unlike the intel 82365, so I've separated it out from the main pcic driver.
733 lines
17 KiB
C
733 lines
17 KiB
C
/*
|
|
* 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;
|
|
|
|
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);
|
|
|
|
/*
|
|
* Initialise controller information structure.
|
|
*/
|
|
mecia_cinfo.ioctl = mecia_ioctl;
|
|
mecia_cinfo.mapmem = mecia_memory;
|
|
mecia_cinfo.mapio = mecia_io;
|
|
mecia_cinfo.power = mecia_power;
|
|
mecia_cinfo.mapirq = mecia_mapirq;
|
|
mecia_cinfo.reset = mecia_reset;
|
|
mecia_cinfo.disable = mecia_disable;
|
|
mecia_cinfo.resume = mecia_resume;
|
|
mecia_cinfo.maxmem = 1;
|
|
#if 0
|
|
mecia_cinfo.maxio = 1;
|
|
#else
|
|
mecia_cinfo.maxio = 2; /* fake for UE2212 LAN card */
|
|
#endif
|
|
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(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 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));
|
|
}
|
|
|
|
/*
|
|
* ioctl calls - Controller specific ioctls
|
|
*/
|
|
static int
|
|
mecia_ioctl(struct slot *slt, int cmd, caddr_t data)
|
|
{
|
|
return (ENOTTY);
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
selwakeup(&slt->selp);
|
|
}
|
|
|
|
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);
|