MFp4: Make the iicbus fully hinted. We no longer automatically add

some devices (and not others).  To get instances onto the iicbus, one
now needs hints or an identify routine.  We also do not probe the bus
for devices because many iic devices cannot be safely probed (and when
they can, the probe order turns out to be somewhat difficult to get
right).

# I'm not 100% sure that the iicsmb removal is right.  Please contact me if
# this causes difficulty.
This commit is contained in:
Warner Losh 2007-03-23 23:08:28 +00:00
parent 99a1402117
commit d4fa68402e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167856
2 changed files with 123 additions and 51 deletions

View file

@ -249,9 +249,8 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
if (!sc)
return (EINVAL);
if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev,
(flags & O_NONBLOCK) ? IIC_DONTWAIT :
(IIC_WAIT | IIC_INTR))))
if ((error = iicbus_request_bus(parent, iicdev,
(flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR))))
return (error);
switch (cmd) {
@ -314,7 +313,7 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
if (!(m->flags & IIC_M_RD))
copyin(usrbufs[i], m->buf, m->len);
}
error = iicbus_transfer(parent, (struct iic_msg *)buf, d->nmsgs);
error = iicbus_transfer(iicdev, (struct iic_msg *)buf, d->nmsgs);
/* Copyout all read segments, free up kernel buffers */
for (i = 0; i < d->nmsgs; i++) {
m = &((struct iic_msg *)buf)[i];
@ -328,7 +327,7 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
error = ENOTTY;
}
iicbus_release_bus(device_get_parent(iicdev), iicdev);
iicbus_release_bus(parent, iicdev);
if (buf != NULL)
free(buf, M_TEMP);

View file

@ -34,52 +34,18 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
#include "iicbus_if.h"
#define DEVTOIICBUS(dev) ((struct iicbus_device*)device_get_ivars(dev))
devclass_t iicbus_devclass;
/* See comments below for why auto-scanning is a bad idea. */
#define SCAN_IICBUS 0
/*
* Device methods
*/
static int iicbus_probe(device_t);
static int iicbus_attach(device_t);
static int iicbus_detach(device_t);
static int iicbus_add_child(device_t dev, int order, const char *name, int unit);
static device_method_t iicbus_methods[] = {
/* device interface */
DEVMETHOD(device_probe, iicbus_probe),
DEVMETHOD(device_attach, iicbus_attach),
DEVMETHOD(device_detach, iicbus_detach),
/* bus interface */
DEVMETHOD(bus_add_child, iicbus_add_child),
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(iicbus_transfer, iicbus_transfer_gen),
{ 0, 0 }
};
driver_t iicbus_driver = {
"iicbus",
iicbus_methods,
sizeof(struct iicbus_softc),
};
static int
iicbus_probe(device_t dev)
{
@ -121,7 +87,9 @@ iicbus_attach(device_t dev)
#if SCAN_IICBUS
unsigned char addr;
#endif
struct iicbus_softc *sc = IICBUS_SOFTC(dev);
sc->dev = dev;
iicbus_reset(dev, IIC_FASTEST, 0, NULL);
/* device probing is meaningless since the bus is supposed to be
@ -140,15 +108,13 @@ iicbus_attach(device_t dev)
}
printf("\n");
#endif
device_add_child(dev, "ic", -1);
device_add_child(dev, "iicsmb", -1);
device_add_child(dev, "ds1672", -1);
device_add_child(dev, "ad7418", -1);
#if 0
/* Always attach the iicsmb children */
BUS_ADD_CHILD(dev, 0, "iicsmb", -1);
/* attach any known device */
device_add_child(dev, "iic", -1);
#endif
BUS_ADD_CHILD(dev, 0, "iic", -1);
/* Attach the wired devices via hints */
bus_enumerate_hinted_children(dev);
/* Now probe and attach them */
bus_generic_attach(dev);
return (0);
}
@ -163,12 +129,89 @@ iicbus_detach(device_t dev)
}
static int
iicbus_print_child(device_t dev, device_t child)
{
struct iicbus_ivar *devi = IICBUS_IVAR(child);
int retval = 0;
retval += bus_print_child_header(dev, child);
if (devi->addr != 0)
retval += printf(" at addr %#x", devi->addr);
retval += bus_print_child_footer(dev, child);
return (retval);
}
static void
iicbus_probe_nomatch(device_t bus, device_t child)
{
struct iicbus_ivar *devi = IICBUS_IVAR(child);
device_printf(bus, "<unknown card>");
printf(" at addr %#x\n", devi->addr);
return;
}
static int
iicbus_child_location_str(device_t bus, device_t child, char *buf,
size_t buflen)
{
struct iicbus_ivar *devi = IICBUS_IVAR(child);
snprintf(buf, buflen, "addr=%#x", devi->addr);
return (0);
}
static int
iicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
size_t buflen)
{
*buf = '\0';
return (0);
}
static int
iicbus_read_ivar(device_t bus, device_t child, int which, u_char *result)
{
struct iicbus_ivar *devi = IICBUS_IVAR(child);
switch (which) {
default:
return (EINVAL);
case IICBUS_IVAR_ADDR:
*(uint32_t *)result = devi->addr;
break;
}
return (0);
}
static device_t
iicbus_add_child(device_t dev, int order, const char *name, int unit)
{
device_t child;
struct iicbus_ivar *devi;
device_add_child_ordered(dev, order, name, unit);
bus_generic_attach(dev);
return (0);
child = device_add_child_ordered(dev, order, name, unit);
if (child == NULL)
return (child);
devi = malloc(sizeof(struct iicbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
if (devi == NULL) {
device_delete_child(dev, child);
return (0);
}
device_set_ivars(child, devi);
return (child);
}
static void
iicbus_hinted_child(device_t bus, const char *dname, int dunit)
{
device_t child;
struct iicbus_ivar *devi;
child = BUS_ADD_CHILD(bus, 0, dname, dunit);
devi = IICBUS_IVAR(child);
resource_int_value(dname, dunit, "addr", &devi->addr);
}
int
@ -192,6 +235,36 @@ iicbus_null_repeated_start(device_t dev, u_char addr)
return (IIC_ENOTSUPP);
}
static device_method_t iicbus_methods[] = {
/* device interface */
DEVMETHOD(device_probe, iicbus_probe),
DEVMETHOD(device_attach, iicbus_attach),
DEVMETHOD(device_detach, iicbus_detach),
/* bus interface */
DEVMETHOD(bus_add_child, iicbus_add_child),
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_print_child, iicbus_print_child),
DEVMETHOD(bus_probe_nomatch, iicbus_probe_nomatch),
DEVMETHOD(bus_read_ivar, iicbus_read_ivar),
DEVMETHOD(bus_child_pnpinfo_str, iicbus_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, iicbus_child_location_str),
DEVMETHOD(bus_hinted_child, iicbus_hinted_child),
/* iicbus interface */
DEVMETHOD(iicbus_transfer, iicbus_transfer),
{ 0, 0 }
};
driver_t iicbus_driver = {
"iicbus",
iicbus_methods,
sizeof(struct iicbus_softc),
};
devclass_t iicbus_devclass;
DRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0);
DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0);
MODULE_VERSION(iicbus, IICBUS_MODVER);