[BACK]Return to kern_drvctl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

File: [cvs.NetBSD.org] / src / sys / kern / kern_drvctl.c (download)

Revision 1.2, Thu Aug 25 15:06:28 2005 UTC (18 years, 7 months ago) by drochner
Branch: MAIN
CVS Tags: yamt-vop-base3, yamt-vop-base2, yamt-vop-base, yamt-vop, yamt-readahead-pervnode, yamt-readahead-perfile, yamt-readahead-base3, yamt-readahead-base2, yamt-readahead-base, yamt-readahead, thorpej-vnode-attr-base, thorpej-vnode-attr, ktrace-lwp-base
Changes since 1.1: +5 -5 lines

Replace the "locnames", attached to cfdata, which was solely good for
userconf, by more complete information (including default values) about
interface attributes, attached to the drivers which provide them.

/* $NetBSD: kern_drvctl.c,v 1.2 2005/08/25 15:06:28 drochner Exp $ */

/*
 * Copyright (c) 2004
 * 	Matthias Drochner.  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, 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>
__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.2 2005/08/25 15:06:28 drochner Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/event.h>
#include <sys/malloc.h>
#include <sys/ioctl.h>
#include <sys/drvctlio.h>

dev_type_ioctl(drvctlioctl);

const struct cdevsw drvctl_cdevsw = {
	nullopen, nullclose, nullread, nullwrite, drvctlioctl,
	nostop, notty, nopoll, nommap, nokqfilter,
};

void drvctlattach(int);

#define MAXLOCATORS 100

static int
detachdevbyname(const char *devname)
{
	struct device *d;

	TAILQ_FOREACH(d, &alldevs, dv_list) {
		if (!strcmp(devname, d->dv_xname)) {
#ifndef XXXFULLRISK
			/*
			 * If the parent cannot be notified, it might keep
			 * pointers to the detached device.
			 * There might be a private notification mechanism,
			 * but better play save here.
			 */
			if (d->dv_parent &&
			    !d->dv_parent->dv_cfattach->ca_childdetached)
				return (ENOTSUP);
#endif
			return (config_detach(d, 0));
		}
	}

	return (ENXIO);
}

static int
rescanbus(const char *busname, const char *ifattr,
	  int numlocators, const int *locators)
{
	int i;
	struct device *d;
	const struct cfiattrdata * const *ap;

	/* XXX there should be a way to get limits and defaults (per device)
	   from config generated data */
	int locs[MAXLOCATORS];
	for (i = 0; i < MAXLOCATORS; i++)
		locs[i] = -1;

	for (i = 0; i < numlocators;i++)
		locs[i] = locators[i];

	TAILQ_FOREACH(d, &alldevs, dv_list) {
		if (!strcmp(busname, d->dv_xname)) {
			/*
			 * must support rescan, and must have something
			 * to attach to
			 */
			if (!d->dv_cfattach->ca_rescan ||
			    !d->dv_cfdriver->cd_attrs)
				return (ENODEV);

			/* allow to omit attribute if there is exactly one */
			if (!ifattr) {
				if (d->dv_cfdriver->cd_attrs[1])
					return (EINVAL);
				ifattr = d->dv_cfdriver->cd_attrs[0]->ci_name;
			} else {
				/* check for valid attribute passed */
				for (ap = d->dv_cfdriver->cd_attrs; *ap; ap++)
					if (!strcmp((*ap)->ci_name, ifattr))
						break;
				if (!*ap)
					return (EINVAL);
			}

			return (*d->dv_cfattach->ca_rescan)(d, ifattr, locs);
		}
	}

	return (ENXIO);
}

int
drvctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	int res;
	char *ifattr;
	int *locs;

	switch (cmd) {
	case DRVDETACHDEV:
#define d ((struct devdetachargs *)data)
		res = detachdevbyname(d->devname);
#undef d
		break;
	case DRVRESCANBUS:
#define d ((struct devrescanargs *)data)
		d->busname[sizeof(d->busname) - 1] = '\0';

		/* XXX better copyin? */
		if (d->ifattr[0]) {
			d->ifattr[sizeof(d->ifattr) - 1] = '\0';
			ifattr = d->ifattr;
		} else
			ifattr = 0;

		if (d->numlocators) {
			if (d->numlocators > MAXLOCATORS)
				return (EINVAL);
			locs = malloc(d->numlocators * sizeof(int), M_DEVBUF,
				      M_WAITOK);
			res = copyin(d->locators, locs,
				     d->numlocators * sizeof(int));
			if (res)
				return (res);
		} else
			locs = 0;
		res = rescanbus(d->busname, ifattr, d->numlocators, locs);
		if (locs)
			free(locs, M_DEVBUF);
#undef d
			break;
		default:
			return (EPASSTHROUGH);
	}
	return (res);
}

void
drvctlattach(int arg)
{
}