Subject: Re: lkm for pci device
To: None <cube@cubidou.net>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: tech-kern
Date: 07/03/2004 14:54:34
This is a multipart MIME message.

--==_Exmh_6371615997500
Content-Type: text/plain; charset=us-ascii


cube@cubidou.net said:
> I guess the idea behind pci_find_device() was "does such a device
> exist?". 

If you ask me, pci_find_device() should die completely. It doesn't
fit into the autoconf framework.
There is almost everything there to have driver LKMs plug in smoothly.
In the PCI case, it is just that the bus enumeration code should
keep track which devices are already handled by drivers (a simple
bitmask per bus would do it), and that pci_enumerate_bus() could
be a bit friendlier to LKMs.
I'll append a proof-of-concept driver skeleton which hooks a PCI
driver into the autoconf framework and causes a rescan of the bus.
There are still some hacks in it:
-It doesn't probe for any specific hardware, this would be done
 in mist_match() like in every real driver.
-For that reason, mistpcimatch() has this static variable to match
 only once. A real driver would match multiple times of course.
 (This can be controlled by locators like for static drivers.)
-That static "currentparent" is a hack which is needed because
 pci_enumerate_bus() doesn't pass this informations to callbacks.
 Can be easily fixed.

best regards
Matthias



--==_Exmh_6371615997500
Content-Type: text/plain ; name="mist.c"; charset=us-ascii
Content-Description: mist.c
Content-Disposition: attachment; filename="mist.c"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>

#include <sys/lkm.h>

#include <dev/pci/pcivar.h>

CFDRIVER_DECL(mist, DV_DULL, NULL);

static int pciloc[] = { -1, -1 }; /* device, function */
static struct cfparent pciparent = {
	"pci", 0, -1
};
static struct cfdata mist_cfdata[] = {
	{"mist", "mist", 0, FSTATE_STAR, pciloc, 0, &pciparent, 0},
	{ 0 }
};

struct mist_softc {
	struct device sc_dev;
};

static int mist_match(struct device *, struct cfdata *, void *);
static void mist_attach(struct device *, struct device *, void *);
static int mist_detach(struct device*, int);

CFATTACH_DECL(mist, sizeof(struct mist_softc),
	      mist_match, mist_attach, mist_detach, NULL);

MOD_MISC("mist");

int		mist_lkmentry(struct lkm_table *, int, int);
static int	mist_lkmload(struct lkm_table *, int);
static int	mist_lkmunload(struct lkm_table *, int);

int
mist_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
{

	DISPATCH(lkmtp, cmd, ver, mist_lkmload, mist_lkmunload, lkm_nofunc);
}

extern struct cftablelist allcftables;
struct cftable mist_cftable;

struct device *currentparent;
static int mistpcimatch(struct pci_attach_args *);

static int
mist_lkmload(struct lkm_table *lkmtp, int cmd)
{
	int error = 0;
	struct device *d;

	error = config_cfdriver_attach(&mist_cd);
	if (error) {
		aprint_error("%s: unable to register cfdriver\n",
		    mist_cd.cd_name);
		goto out;
	}

	error = config_cfattach_attach(mist_cd.cd_name, &mist_ca);
	if (error) {
		aprint_error("%s: unable to register cfattach\n",
		    mist_cd.cd_name);
		(void)config_cfdriver_detach(&mist_cd);
		goto out;
	}

	mist_cftable.ct_cfdata = mist_cfdata;
	TAILQ_INSERT_TAIL(&allcftables, &mist_cftable, ct_list);

	/* XXX */
	TAILQ_FOREACH(d, &alldevs, dv_list) {
		if (!strcmp(d->dv_cfdriver->cd_name, "pci")) {
			currentparent = d;
			pci_enumerate_bus((struct pci_softc *)d, mistpcimatch, 0);
		}
	}

out:
	return error;
}

static int
mist_lkmunload(struct lkm_table *lkmtp, int cmd)
{
	int error, i;

	for (i = 0; i < mist_cd.cd_ndevs; i++)
		if (mist_cd.cd_devs[i] != NULL &&
		    (error = config_detach(mist_cd.cd_devs[i], 0)) != 0) {
			aprint_error("%s: unable to detach instance\n",
			    ((struct device *)mist_cd.cd_devs[i])->dv_xname);
			return error;
		}

	TAILQ_REMOVE(&allcftables, &mist_cftable, ct_list);

	if ((error = config_cfattach_detach(mist_cd.cd_name, &mist_ca)) != 0) {
		aprint_error("%s: unable to deregister cfattach\n",
		    mist_cd.cd_name);
		return error;
	}

	if ((error = config_cfdriver_detach(&mist_cd)) != 0) {
		aprint_error("%s: unable to deregister cfdriver\n",
		    mist_cd.cd_name);
		return error;
	}

	return (0);
}

static int
mistpcimatch(struct pci_attach_args *aa)
{
	static int matched;

	if (!matched) {
		matched = 1;
		config_found(currentparent, (void *)aa, 0);
		return (1);
	}
	return (0);
	
}

static int
mist_match(struct device *self, struct cfdata *cfdata, void *arg)
{

		return (100);
}

static void
mist_attach(struct device *parent, struct device *self, void *aux)
{

	printf("\n%s mist_attach\n", self->dv_xname);
}

static int
mist_detach(struct device* self, int flags)
{

	printf("%s mist_detach\n", self->dv_xname);
	return (0);
}

--==_Exmh_6371615997500--