Overhaul of CIS parsing, next step: keep a cached copy of the CIS,
read before we configure the card, so we can implement /dev/cardbus*.cis. Also, do this on a per-child basis, so we now have a different name than before. I think i'll have to fix that for some legacy tools to keep working. I can now do a dumpcis on my running atheros card and have it still work!
This commit is contained in:
parent
30dda99b96
commit
a7de0b74a7
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003 M. Warner Losh. All Rights Reserved.
|
* Copyright (c) 2003-2008 M. Warner Losh. All Rights Reserved.
|
||||||
* Copyright (c) 2000,2001 Jonathan Chen. All rights reserved.
|
* Copyright (c) 2000,2001 Jonathan Chen. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -99,20 +99,18 @@ cardbus_probe(device_t cbdev)
|
|||||||
static int
|
static int
|
||||||
cardbus_attach(device_t cbdev)
|
cardbus_attach(device_t cbdev)
|
||||||
{
|
{
|
||||||
struct cardbus_softc *sc = device_get_softc(cbdev);
|
struct cardbus_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(cbdev);
|
||||||
sc->sc_dev = cbdev;
|
sc->sc_dev = cbdev;
|
||||||
cardbus_device_create(sc);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cardbus_detach(device_t cbdev)
|
cardbus_detach(device_t cbdev)
|
||||||
{
|
{
|
||||||
struct cardbus_softc *sc = device_get_softc(cbdev);
|
|
||||||
|
|
||||||
cardbus_detach_card(cbdev);
|
cardbus_detach_card(cbdev);
|
||||||
cardbus_device_destroy(sc);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +163,9 @@ cardbus_attach_card(device_t cbdev)
|
|||||||
int bus, domain, slot, func;
|
int bus, domain, slot, func;
|
||||||
int cardattached = 0;
|
int cardattached = 0;
|
||||||
int cardbusfunchigh = 0;
|
int cardbusfunchigh = 0;
|
||||||
|
struct cardbus_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(cbdev);
|
||||||
cardbus_detach_card(cbdev); /* detach existing cards */
|
cardbus_detach_card(cbdev); /* detach existing cards */
|
||||||
POWER_ENABLE_SOCKET(brdev, cbdev);
|
POWER_ENABLE_SOCKET(brdev, cbdev);
|
||||||
domain = pcib_get_domain(cbdev);
|
domain = pcib_get_domain(cbdev);
|
||||||
@ -192,6 +192,7 @@ cardbus_attach_card(device_t cbdev)
|
|||||||
dinfo->pci.cfg.dev = child;
|
dinfo->pci.cfg.dev = child;
|
||||||
resource_list_init(&dinfo->pci.resources);
|
resource_list_init(&dinfo->pci.resources);
|
||||||
device_set_ivars(child, dinfo);
|
device_set_ivars(child, dinfo);
|
||||||
|
cardbus_device_create(sc, dinfo, cbdev, child);
|
||||||
if (cardbus_do_cis(cbdev, child) != 0)
|
if (cardbus_do_cis(cbdev, child) != 0)
|
||||||
DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n"));
|
DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n"));
|
||||||
pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
|
pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
|
||||||
@ -235,6 +236,7 @@ cardbus_detach_card(device_t cbdev)
|
|||||||
if (status == DS_ATTACHED || status == DS_BUSY)
|
if (status == DS_ATTACHED || status == DS_BUSY)
|
||||||
device_detach(devlist[tmp]);
|
device_detach(devlist[tmp]);
|
||||||
cardbus_release_all_resources(cbdev, dinfo);
|
cardbus_release_all_resources(cbdev, dinfo);
|
||||||
|
cardbus_device_destroy(dinfo);
|
||||||
device_delete_child(cbdev, devlist[tmp]);
|
device_delete_child(cbdev, devlist[tmp]);
|
||||||
pci_freecfg((struct pci_devinfo *)dinfo);
|
pci_freecfg((struct pci_devinfo *)dinfo);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
|
* Copyright (c) 2005-2008, M. Warner Losh
|
||||||
* Copyright (c) 2000,2001 Jonathan Chen.
|
* Copyright (c) 2000,2001 Jonathan Chen.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2005, M. Warner Losh
|
* Copyright (c) 2005-2008, M. Warner Losh
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -63,26 +63,6 @@ static struct cdevsw cardbus_cdevsw = {
|
|||||||
.d_name = "cardbus"
|
.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
|
static int
|
||||||
cardbus_build_cis(device_t cbdev, device_t child, int id,
|
cardbus_build_cis(device_t cbdev, device_t child, int id,
|
||||||
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
|
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
|
||||||
@ -115,7 +95,8 @@ cardbus_build_cis(device_t cbdev, device_t child, int id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cardbus_device_buffer_cis(device_t parent, device_t child)
|
cardbus_device_buffer_cis(device_t parent, device_t child,
|
||||||
|
struct cis_buffer *cbp)
|
||||||
{
|
{
|
||||||
struct cardbus_softc *sc;
|
struct cardbus_softc *sc;
|
||||||
struct tuple_callbacks cb[] = {
|
struct tuple_callbacks cb[] = {
|
||||||
@ -123,46 +104,44 @@ cardbus_device_buffer_cis(device_t parent, device_t child)
|
|||||||
};
|
};
|
||||||
|
|
||||||
sc = device_get_softc(parent);
|
sc = device_get_softc(parent);
|
||||||
return (cardbus_parse_cis(parent, child, cb, &sc->sc_cis));
|
return (cardbus_parse_cis(parent, child, cb, cbp));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi,
|
||||||
|
device_t parent, device_t child)
|
||||||
|
{
|
||||||
|
uint32_t minor;
|
||||||
|
|
||||||
|
cardbus_device_buffer_cis(parent, child, &devi->sc_cis);
|
||||||
|
minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func;
|
||||||
|
devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
|
||||||
|
"cardbus%d.%d.cis", device_get_unit(sc->sc_dev),
|
||||||
|
devi->pci.cfg.func);
|
||||||
|
/* XXX need cardbus%d.cis compat layer here ? */
|
||||||
|
devi->sc_cisdev->si_drv1 = devi;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cardbus_device_destroy(struct cardbus_devinfo *devi)
|
||||||
|
{
|
||||||
|
if (devi->sc_cisdev)
|
||||||
|
destroy_dev(devi->sc_cisdev);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
|
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
sc->sc_cis.len = 0;
|
|
||||||
if (cnt == 0) {
|
|
||||||
free(kids, M_TEMP);
|
|
||||||
sc->sc_cis_open++;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
child = kids[0];
|
|
||||||
free(kids, M_TEMP);
|
|
||||||
err = cardbus_device_buffer_cis(parent, child);
|
|
||||||
if (err)
|
|
||||||
return (err);
|
|
||||||
sc->sc_cis_open++;
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
|
cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
|
||||||
{
|
{
|
||||||
struct cardbus_softc *sc;
|
|
||||||
|
|
||||||
sc = dev->si_drv1;
|
|
||||||
sc->sc_cis_open = 0;
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +155,12 @@ cardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
|||||||
static int
|
static int
|
||||||
cardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
|
cardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||||
{
|
{
|
||||||
struct cardbus_softc *sc;
|
struct cardbus_devinfo *devi;
|
||||||
|
|
||||||
sc = dev->si_drv1;
|
devi = dev->si_drv1;
|
||||||
/* EOF */
|
/* EOF */
|
||||||
if (uio->uio_offset >= sc->sc_cis.len)
|
if (uio->uio_offset >= devi->sc_cis.len)
|
||||||
return (0);
|
return (0);
|
||||||
return (uiomove(sc->sc_cis.buffer + uio->uio_offset,
|
return (uiomove(devi->sc_cis.buffer + uio->uio_offset,
|
||||||
MIN(uio->uio_resid, sc->sc_cis.len - uio->uio_offset), uio));
|
MIN(uio->uio_resid, devi->sc_cis.len - uio->uio_offset), uio));
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
|
* Copyright (c) 2008, M. Warner Losh
|
||||||
* Copyright (c) 2000,2001 Jonathan Chen.
|
* Copyright (c) 2000,2001 Jonathan Chen.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -29,6 +30,21 @@
|
|||||||
/*
|
/*
|
||||||
* Structure definitions for the Cardbus Bus driver
|
* Structure definitions for the Cardbus Bus driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Static copy of the CIS buffer. Technically, you aren't supposed
|
||||||
|
* to do this. In practice, however, it works well.
|
||||||
|
*/
|
||||||
|
struct cis_buffer
|
||||||
|
{
|
||||||
|
size_t len; /* Actual length of the CIS */
|
||||||
|
uint8_t buffer[2040]; /* small enough to be 2k */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per child information for the PCI device. Cardbus layers on some
|
||||||
|
* additional data.
|
||||||
|
*/
|
||||||
struct cardbus_devinfo
|
struct cardbus_devinfo
|
||||||
{
|
{
|
||||||
struct pci_devinfo pci;
|
struct pci_devinfo pci;
|
||||||
@ -43,36 +59,33 @@ struct cardbus_devinfo
|
|||||||
} lan;
|
} lan;
|
||||||
} funce;
|
} funce;
|
||||||
uint32_t fepresent; /* bit mask of funce values present */
|
uint32_t fepresent; /* bit mask of funce values present */
|
||||||
|
struct cdev *sc_cisdev;
|
||||||
|
struct cis_buffer sc_cis;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cis_buffer
|
/*
|
||||||
{
|
* Per cardbus soft info. Not sure why we even keep this around...
|
||||||
size_t len; /* Actual length of the CIS */
|
*/
|
||||||
uint8_t buffer[2040]; /* small enough to be 2k */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cardbus_softc
|
struct cardbus_softc
|
||||||
{
|
{
|
||||||
device_t sc_dev;
|
device_t sc_dev;
|
||||||
/* The following fields should in be in struct cardbus_devinfo */
|
|
||||||
struct cdev *sc_cisdev;
|
|
||||||
struct cis_buffer sc_cis;
|
|
||||||
int sc_cis_open;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per node callback structures.
|
||||||
|
*/
|
||||||
struct tuple_callbacks;
|
struct tuple_callbacks;
|
||||||
|
|
||||||
typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
|
typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
|
||||||
uint8_t *tupledata, uint32_t start, uint32_t *off,
|
uint8_t *tupledata, uint32_t start, uint32_t *off,
|
||||||
struct tuple_callbacks *info, void *);
|
struct tuple_callbacks *info, void *);
|
||||||
|
|
||||||
struct tuple_callbacks {
|
struct tuple_callbacks {
|
||||||
int id;
|
int id;
|
||||||
char *name;
|
char *name;
|
||||||
tuple_cb *func;
|
tuple_cb *func;
|
||||||
};
|
};
|
||||||
|
|
||||||
int cardbus_device_create(struct cardbus_softc *);
|
int cardbus_device_create(struct cardbus_softc *sc,
|
||||||
int cardbus_device_destroy(struct cardbus_softc *);
|
struct cardbus_devinfo *devi, device_t parent, device_t child);
|
||||||
|
int cardbus_device_destroy(struct cardbus_devinfo *devi);
|
||||||
int cardbus_parse_cis(device_t cbdev, device_t child,
|
int cardbus_parse_cis(device_t cbdev, device_t child,
|
||||||
struct tuple_callbacks *callbacks, void *);
|
struct tuple_callbacks *callbacks, void *);
|
||||||
|
Loading…
Reference in New Issue
Block a user