Implement /dev/cardbus%d.cis, same thing as /dev/pccard%d.cis. There

are some rough edges with this still, but it seems to work well enough
to commit.
This commit is contained in:
imp 2005-12-29 01:43:47 +00:00
parent 10c2623c78
commit 2d3e88cd9e
6 changed files with 270 additions and 72 deletions

View File

@ -489,6 +489,7 @@ dev/buslogic/bt_mca.c optional bt mca
dev/buslogic/bt_pci.c optional bt pci
dev/cardbus/cardbus.c optional cardbus
dev/cardbus/cardbus_cis.c optional cardbus
dev/cardbus/cardbus_device.c optional cardbus
dev/ciss/ciss.c optional ciss
dev/cm/smc90cx6.c optional cm
dev/cnw/if_cnw.c optional cnw pccard

View File

@ -406,13 +406,20 @@ cardbus_probe(device_t cbdev)
static int
cardbus_attach(device_t cbdev)
{
struct cardbus_softc *sc = device_get_softc(cbdev);
sc->sc_dev = cbdev;
cardbus_device_create(sc);
return 0;
}
static int
cardbus_detach(device_t cbdev)
{
struct cardbus_softc *sc = device_get_softc(cbdev);
cardbus_detach_card(cbdev);
cardbus_device_destroy(sc);
return 0;
}

View File

@ -58,45 +58,33 @@ extern int cardbus_cis_debug;
#define DPRINTF(a) if (cardbus_cis_debug) printf a
#define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
struct tuple_callbacks;
typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks {
int id;
char *name;
tuple_cb *func;
};
static int decode_tuple_generic(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_funce(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_bar(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int decode_tuple_end(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info);
struct tuple_callbacks *info, void *);
static int cardbus_read_tuple_conf(device_t cbdev, device_t child,
uint32_t start, uint32_t *off, int *tupleid, int *len,
@ -113,9 +101,8 @@ static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child,
uint32_t *start, int *rid);
static int decode_tuple(device_t cbdev, device_t child, int tupleid,
int len, uint8_t *tupledata, uint32_t start,
uint32_t *off, struct tuple_callbacks *callbacks);
static int cardbus_parse_cis(device_t cbdev, device_t child,
struct tuple_callbacks *callbacks);
uint32_t *off, struct tuple_callbacks *callbacks,
void *);
#define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
@ -139,7 +126,7 @@ static char *funcnames[] = {
static int
decode_tuple_generic(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
int i;
@ -162,7 +149,7 @@ decode_tuple_generic(device_t cbdev, device_t child, int id,
static int
decode_tuple_linktarget(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
int i;
@ -180,7 +167,7 @@ decode_tuple_linktarget(device_t cbdev, device_t child, int id,
tupledata[2] != 'S') {
printf("Invalid data for CIS Link Target!\n");
decode_tuple_generic(cbdev, child, id, len, tupledata,
start, off, info);
start, off, info, argp);
return (EINVAL);
}
return (0);
@ -189,7 +176,7 @@ decode_tuple_linktarget(device_t cbdev, device_t child, int id,
static int
decode_tuple_vers_1(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
int i;
@ -212,7 +199,7 @@ decode_tuple_vers_1(device_t cbdev, device_t child, int id,
static int
decode_tuple_funcid(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
@ -225,7 +212,7 @@ decode_tuple_funcid(device_t cbdev, device_t child, int id,
printf("%s", funcnames[tupledata[i]]);
else
printf("Unknown(%d)", tupledata[i]);
if (i < len-1)
if (i < len - 1)
printf(", ");
}
printf("\n");
@ -238,7 +225,7 @@ decode_tuple_funcid(device_t cbdev, device_t child, int id,
static int
decode_tuple_manfid(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int i;
@ -260,7 +247,7 @@ decode_tuple_manfid(device_t cbdev, device_t child, int id,
static int
decode_tuple_funce(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int type, i;
@ -295,7 +282,7 @@ decode_tuple_funce(device_t cbdev, device_t child, int id,
static int
decode_tuple_bar(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
struct cardbus_devinfo *dinfo = device_get_ivars(child);
int type;
@ -390,17 +377,17 @@ decode_tuple_bar(device_t cbdev, device_t child, int id,
static int
decode_tuple_unhandled(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
/* Make this message suck less XXX */
printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
return (-1);
return (EINVAL);
}
static int
decode_tuple_end(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info)
struct tuple_callbacks *info, void *argp)
{
if (cardbus_cis_debug)
printf("CIS reading done\n");
@ -479,8 +466,9 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
{
if (res != (struct resource*)~0UL) {
bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
pci_write_config(child, rid, 0, 4);
PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
if (rid == PCIM_CIS_ASI_ROM)
pci_write_config(child, rid, pci_read_config(child,
rid, 4) & ~PCIR_BIOS, 4);
}
}
@ -488,14 +476,14 @@ static struct resource *
cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
int *rid)
{
uint32_t testval;
uint32_t size;
struct resource *res;
uint32_t space;
space = *start & PCIM_CIS_ASI_MASK;
switch (space) {
case PCIM_CIS_ASI_TUPLE:
if (cardbus_cis_debug)
device_printf(cbdev, "CIS in PCI config space\n");
/* CIS in PCI config space need no initialization */
return ((struct resource*)~0UL);
case PCIM_CIS_ASI_BAR0:
@ -505,9 +493,13 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
case PCIM_CIS_ASI_BAR4:
case PCIM_CIS_ASI_BAR5:
*rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
if (cardbus_cis_debug)
device_printf(cbdev, "CIS in BAR %#x\n", *rid);
break;
case PCIM_CIS_ASI_ROM:
*rid = PCIR_BIOS;
if (cardbus_cis_debug)
device_printf(cbdev, "CIS in option rom\n");
break;
default:
device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
@ -515,35 +507,19 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
return (NULL);
}
/* figure out how much space we need */
pci_write_config(child, *rid, 0xffffffff, 4);
testval = pci_read_config(child, *rid, 4);
/*
* This bit has a different meaning depending if we are dealing
* with a normal BAR or an Option ROM BAR.
*/
if (((testval & 0x1) == 0x1) && (*rid != PCIR_BIOS)) {
device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
return (NULL);
}
size = CARDBUS_MAPREG_MEM_SIZE(testval);
/* XXX Is this some kind of hack? */
if (size < 4096)
size = 4096;
/* allocate the memory space to read CIS */
res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
rman_make_alignment_flags(size) | RF_ACTIVE);
res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, 1,
rman_make_alignment_flags(4096) | RF_ACTIVE);
if (res == NULL) {
device_printf(cbdev, "Unable to allocate resource "
"to read CIS.\n");
return (NULL);
}
pci_write_config(child, *rid,
rman_get_start(res) | ((*rid == PCIR_BIOS) ? PCIM_BIOS_ENABLE : 0),
4);
PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
pci_write_config(child, *rid, rman_get_start(res), 4);
if (*rid == PCIR_BIOS)
pci_write_config(child, *rid,
rman_get_start(res) | PCIM_BIOS_ENABLE, 4);
/* Flip to the right ROM image if CIS is in ROM */
if (space == PCIM_CIS_ASI_ROM) {
@ -626,21 +602,21 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
static int
decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *callbacks)
struct tuple_callbacks *callbacks, void *argp)
{
int i;
for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
if (tupleid == callbacks[i].id)
return (callbacks[i].func(cbdev, child, tupleid, len,
tupledata, start, off, &callbacks[i]));
tupledata, start, off, &callbacks[i], argp));
}
return (callbacks[i].func(cbdev, child, tupleid, len,
tupledata, start, off, NULL));
tupledata, start, off, NULL, argp));
}
static int
int
cardbus_parse_cis(device_t cbdev, device_t child,
struct tuple_callbacks *callbacks)
struct tuple_callbacks *callbacks, void *argp)
{
uint8_t tupledata[MAXTUPLESIZE];
int tupleid;
@ -656,6 +632,8 @@ cardbus_parse_cis(device_t cbdev, device_t child,
device_printf(cbdev, "CIS pointer is 0!\n");
return (ENXIO);
}
if (cardbus_cis_debug)
device_printf(cbdev, "CIS pointer is %#x\n", start);
off = 0;
res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
if (res == NULL) {
@ -664,8 +642,8 @@ cardbus_parse_cis(device_t cbdev, device_t child,
}
do {
if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
&tupleid, &len, tupledata)) {
if (cardbus_read_tuple(cbdev, child, res, start, &off,
&tupleid, &len, tupledata) != 0) {
device_printf(cbdev, "Failed to read CIS.\n");
cardbus_read_tuple_finish(cbdev, child, rid, res);
return (ENXIO);
@ -678,7 +656,7 @@ cardbus_parse_cis(device_t cbdev, device_t child,
return (EINVAL);
}
expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
tupledata, start, &off, callbacks);
tupledata, start, &off, callbacks, argp);
if (expect_linktarget != 0) {
device_printf(cbdev, "Parsing failed with %d\n",
expect_linktarget);
@ -710,7 +688,7 @@ cardbus_do_cis(device_t cbdev, device_t child)
MAKETUPLE(GENERIC, generic),
};
ret = cardbus_parse_cis(cbdev, child, init_callbacks);
ret = cardbus_parse_cis(cbdev, child, init_callbacks, NULL);
if (ret < 0)
return (ret);
return 0;

View File

@ -0,0 +1,180 @@
/*-
* Copyright (c) 2005, 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 unmodified, 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.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <sys/pciio.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pci_private.h>
#include <dev/cardbus/cardbusreg.h>
#include <dev/cardbus/cardbusvar.h>
#include <dev/cardbus/cardbus_cis.h>
#include <dev/pccard/pccard_cis.h>
static d_open_t cardbus_open;
static d_close_t cardbus_close;
static d_read_t cardbus_read;
static d_ioctl_t cardbus_ioctl;
static struct cdevsw cardbus_cdevsw = {
.d_version = D_VERSION,
.d_open = cardbus_open,
.d_close = cardbus_close,
.d_read = cardbus_read,
.d_ioctl = cardbus_ioctl,
.d_name = "cardbus"
};
int
cardbus_device_create(struct cardbus_softc *sc)
{
uint32_t minor;
minor = device_get_unit(sc->sc_dev) << 16;
sc->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
"cardbus%u.cis", device_get_unit(sc->sc_dev));
sc->sc_cisdev->si_drv1 = sc;
return (0);
}
int
cardbus_device_destroy(struct cardbus_softc *sc)
{
if (sc->sc_cisdev)
destroy_dev(sc->sc_cisdev);
return (0);
}
static int
cardbus_build_cis(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info, void *argp)
{
struct cis_buffer *cis;
int i;
cis = (struct cis_buffer *)argp;
/*
* CISTPL_END is a special case, it has no length field.
*/
if (id == CISTPL_END) {
if (cis->len + 1 > sizeof(cis->buffer))
return (ENOSPC);
cis->buffer[cis->len++] = id;
return (0);
}
if (cis->len + 2 + len > sizeof(cis->buffer))
return (ENOSPC);
cis->buffer[cis->len++] = id;
cis->buffer[cis->len++] = len;
for (i = 0; i < len; i++)
cis->buffer[cis->len++] = tupledata[i];
return (0);
}
static int
cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
device_t parent, child;
device_t *kids;
int cnt, err;
struct cardbus_softc *sc;
struct tuple_callbacks cb[] = {
{CISTPL_GENERIC, "GENERIC", cardbus_build_cis}
};
sc = dev->si_drv1;
if (sc->sc_cis_open)
return (EBUSY);
parent = sc->sc_dev;
err = device_get_children(parent, &kids, &cnt);
if (err)
return err;
if (cnt == 0) {
free(kids, M_TEMP);
sc->sc_cis_open++;
sc->sc_cis = NULL;
return (0);
}
child = kids[0];
free(kids, M_TEMP);
sc->sc_cis = malloc(sizeof(*sc->sc_cis), M_TEMP, M_ZERO | M_WAITOK);
err = cardbus_parse_cis(parent, child, cb, sc->sc_cis);
if (err) {
free(sc->sc_cis, M_TEMP);
sc->sc_cis = NULL;
return (err);
}
sc->sc_cis_open++;
return (0);
}
static int
cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
{
struct cardbus_softc *sc;
sc = dev->si_drv1;
free(sc->sc_cis, M_TEMP);
sc->sc_cis = NULL;
sc->sc_cis_open = 0;
return (0);
}
static int
cardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct thread *td)
{
return (ENOTTY);
}
static int
cardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cardbus_softc *sc;
sc = dev->si_drv1;
/* EOF */
if (sc->sc_cis == NULL || uio->uio_offset > sc->sc_cis->len)
return (0);
return (uiomove(sc->sc_cis->buffer + uio->uio_offset,
MIN(uio->uio_resid, sc->sc_cis->len - uio->uio_offset), uio));
}

View File

@ -46,3 +46,35 @@ struct cardbus_devinfo
} funce;
uint32_t fepresent; /* bit mask of funce values present */
};
struct cis_buffer
{
size_t len; /* Actual length of the CIS */
uint8_t buffer[2040]; /* small enough to be 2k */
};
struct cardbus_softc
{
/* XXX need mutex XXX */
device_t sc_dev;
struct cdev *sc_cisdev;
struct cis_buffer *sc_cis;
int sc_cis_open;
};
struct tuple_callbacks;
typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info, void *);
struct tuple_callbacks {
int id;
char *name;
tuple_cb *func;
};
int cardbus_device_create(struct cardbus_softc *);
int cardbus_device_destroy(struct cardbus_softc *);
int cardbus_parse_cis(device_t cbdev, device_t child,
struct tuple_callbacks *callbacks, void *);

View File

@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../dev/cardbus
KMOD= cardbus
SRCS= cardbus.c cardbus_cis.c \
SRCS= cardbus.c cardbus_cis.c cardbus_device.c \
device_if.h bus_if.h card_if.h power_if.h pci_if.h pcib_if.h
.include <bsd.kmod.mk>