diff options
author | imp <imp@FreeBSD.org> | 2005-12-29 01:43:47 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2005-12-29 01:43:47 +0000 |
commit | 2d3e88cd9e999219b2101e65b3390d628941126e (patch) | |
tree | bf533208984821e83f178063f9eae3f952f8b8a9 /sys/dev/cardbus | |
parent | 10c2623c78422d9bb6f770ec6ab49b3f21dca64e (diff) | |
download | FreeBSD-src-2d3e88cd9e999219b2101e65b3390d628941126e.zip FreeBSD-src-2d3e88cd9e999219b2101e65b3390d628941126e.tar.gz |
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.
Diffstat (limited to 'sys/dev/cardbus')
-rw-r--r-- | sys/dev/cardbus/cardbus.c | 7 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbus_cis.c | 120 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbus_device.c | 180 | ||||
-rw-r--r-- | sys/dev/cardbus/cardbusvar.h | 32 |
4 files changed, 268 insertions, 71 deletions
diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index 49bc7fd..3611543 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -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; } diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index 4d7b973..552d32d 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -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; diff --git a/sys/dev/cardbus/cardbus_device.c b/sys/dev/cardbus/cardbus_device.c new file mode 100644 index 0000000..c03a18a --- /dev/null +++ b/sys/dev/cardbus/cardbus_device.c @@ -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)); +} diff --git a/sys/dev/cardbus/cardbusvar.h b/sys/dev/cardbus/cardbusvar.h index edb98bb..4cbc3c4 100644 --- a/sys/dev/cardbus/cardbusvar.h +++ b/sys/dev/cardbus/cardbusvar.h @@ -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 *); |