/*
* 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.
*/
if (drvctl_nopen == 0) {
prop_object_release(ev);
mutex_exit(&drvctl_lock);
return 0;
}
/* Fill in mandatory member */
if (!prop_dictionary_set_string_nocopy(ev, "event", event)) {
prop_object_release(ev);
mutex_exit(&drvctl_lock);
return 0;
}
static int
detachdevbyname(const char *devname)
{
device_t d;
deviter_t di;
int error;
KASSERT(KERNEL_LOCKED_P());
for (d = deviter_first(&di, DEVITER_F_RW);
d != NULL;
d = deviter_next(&di)) {
if (strcmp(device_xname(d), devname) == 0)
break;
}
if (d == NULL) {
error = ENXIO;
goto out;
}
#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 it safe here.
*/
if (device_parent(d) &&
!device_cfattach(device_parent(d))->ca_childdetached) {
error = ENOTSUP;
goto out;
}
#endif
static int
rescanbus(const char *busname, const char *ifattr,
int numlocators, const int *locators)
{
int i, rc;
device_t d;
const struct cfiattrdata * const *ap;
KASSERT(KERNEL_LOCKED_P());
/* 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];
if ((d = device_find_by_xname(busname)) == NULL)
return ENXIO;
/*
* must support rescan, and must have something
* to attach to
*/
if (!device_cfattach(d)->ca_rescan ||
!device_cfdriver(d)->cd_attrs)
return ENODEV;
/* rescan all ifattrs if none is specified */
if (!ifattr) {
rc = 0;
for (ap = device_cfdriver(d)->cd_attrs; *ap; ap++) {
rc = (*device_cfattach(d)->ca_rescan)(d,
(*ap)->ci_name, locs);
if (rc)
break;
}
} else {
/* check for valid attribute passed */
for (ap = device_cfdriver(d)->cd_attrs; *ap; ap++)
if (!strcmp((*ap)->ci_name, ifattr))
break;
if (!*ap)
return EINVAL;
rc = (*device_cfattach(d)->ca_rescan)(d, ifattr, locs);
}
config_deferred(NULL);
return rc;
}
static int
drvctl_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
int flags)
{
return ENODEV;
}
static int
drvctl_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
int flags)
{
return ENODEV;
}
static int
drvctl_ioctl(struct file *fp, u_long cmd, void *data)
{
int res;
char *ifattr;
int *locs;
size_t locs_sz = 0; /* XXXgcc */
KERNEL_LOCK(1, NULL);
switch (cmd) {
case DRVSUSPENDDEV:
case DRVRESUMEDEV:
#define d ((struct devpmargs *)data)
res = pmdevbyname(cmd, d);
#undef d
break;
case DRVLISTDEV:
res = listdevbyname((struct devlistargs *)data);
break;
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';