version 1.19, 2008/06/24 10:24:21 |
version 1.19.4.2, 2009/04/28 07:36:59 |
Line 35 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 35 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/conf.h> |
#include <sys/conf.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/event.h> |
#include <sys/event.h> |
#include <sys/malloc.h> |
|
#include <sys/kmem.h> |
#include <sys/kmem.h> |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/fcntl.h> |
#include <sys/fcntl.h> |
#include <sys/file.h> |
#include <sys/file.h> |
#include <sys/filedesc.h> |
#include <sys/filedesc.h> |
|
#include <sys/select.h> |
|
#include <sys/poll.h> |
#include <sys/drvctlio.h> |
#include <sys/drvctlio.h> |
#include <sys/devmon.h> |
#include <sys/devmon.h> |
|
#include <sys/stat.h> |
|
#include <sys/kauth.h> |
|
|
struct drvctl_event { |
struct drvctl_event { |
TAILQ_ENTRY(drvctl_event) dce_link; |
TAILQ_ENTRY(drvctl_event) dce_link; |
Line 55 static struct drvctl_queue drvctl_eventq |
|
Line 58 static struct drvctl_queue drvctl_eventq |
|
static kcondvar_t drvctl_cond; |
static kcondvar_t drvctl_cond; |
static kmutex_t drvctl_lock; |
static kmutex_t drvctl_lock; |
static int drvctl_nopen = 0, drvctl_eventcnt = 0; |
static int drvctl_nopen = 0, drvctl_eventcnt = 0; |
|
static struct selinfo drvctl_rdsel; |
|
|
#define DRVCTL_EVENTQ_DEPTH 64 /* arbitrary queue limit */ |
#define DRVCTL_EVENTQ_DEPTH 64 /* arbitrary queue limit */ |
|
|
Line 72 static int drvctl_read(struct file *, of |
|
Line 76 static int drvctl_read(struct file *, of |
|
static int drvctl_write(struct file *, off_t *, struct uio *, |
static int drvctl_write(struct file *, off_t *, struct uio *, |
kauth_cred_t, int); |
kauth_cred_t, int); |
static int drvctl_ioctl(struct file *, u_long, void *); |
static int drvctl_ioctl(struct file *, u_long, void *); |
|
static int drvctl_poll(struct file *, int); |
|
static int drvctl_stat(struct file *, struct stat *); |
static int drvctl_close(struct file *); |
static int drvctl_close(struct file *); |
|
|
static const struct fileops drvctl_fileops = { |
static const struct fileops drvctl_fileops = { |
drvctl_read, |
.fo_read = drvctl_read, |
drvctl_write, |
.fo_write = drvctl_write, |
drvctl_ioctl, |
.fo_ioctl = drvctl_ioctl, |
fnullop_fcntl, |
.fo_fcntl = fnullop_fcntl, |
fnullop_poll, |
.fo_poll = drvctl_poll, |
fbadop_stat, |
.fo_stat = drvctl_stat, |
drvctl_close, |
.fo_close = drvctl_close, |
fnullop_kqfilter |
.fo_kqfilter = fnullop_kqfilter, |
|
.fo_drain = fnullop_drain, |
}; |
}; |
|
|
#define MAXLOCATORS 100 |
#define MAXLOCATORS 100 |
Line 96 drvctl_init(void) |
|
Line 103 drvctl_init(void) |
|
TAILQ_INIT(&drvctl_eventq); |
TAILQ_INIT(&drvctl_eventq); |
mutex_init(&drvctl_lock, MUTEX_DEFAULT, IPL_NONE); |
mutex_init(&drvctl_lock, MUTEX_DEFAULT, IPL_NONE); |
cv_init(&drvctl_cond, "devmon"); |
cv_init(&drvctl_cond, "devmon"); |
|
selinit(&drvctl_rdsel); |
} |
} |
|
|
void |
void |
devmon_insert(const char *event, prop_dictionary_t ev) |
devmon_insert(const char *event, prop_dictionary_t ev) |
{ |
{ |
struct drvctl_event *dce, *odce;; |
struct drvctl_event *dce, *odce; |
|
|
mutex_enter(&drvctl_lock); |
mutex_enter(&drvctl_lock); |
|
|
Line 136 devmon_insert(const char *event, prop_di |
|
Line 144 devmon_insert(const char *event, prop_di |
|
TAILQ_INSERT_TAIL(&drvctl_eventq, dce, dce_link); |
TAILQ_INSERT_TAIL(&drvctl_eventq, dce, dce_link); |
++drvctl_eventcnt; |
++drvctl_eventcnt; |
cv_broadcast(&drvctl_cond); |
cv_broadcast(&drvctl_cond); |
|
selnotify(&drvctl_rdsel, 0, 0); |
|
|
mutex_exit(&drvctl_lock); |
mutex_exit(&drvctl_lock); |
} |
} |
Line 191 listdevbyname(struct devlistargs *l) |
|
Line 200 listdevbyname(struct devlistargs *l) |
|
deviter_t di; |
deviter_t di; |
int cnt = 0, idx, error = 0; |
int cnt = 0, idx, error = 0; |
|
|
if ((d = device_find_by_xname(l->l_devname)) == NULL) |
if (*l->l_devname == '\0') |
|
d = (device_t)NULL; |
|
else if (memchr(l->l_devname, 0, sizeof(l->l_devname)) == NULL) |
|
return EINVAL; |
|
else if ((d = device_find_by_xname(l->l_devname)) == NULL) |
return ENXIO; |
return ENXIO; |
|
|
for (child = deviter_first(&di, 0); child != NULL; |
for (child = deviter_first(&di, 0); child != NULL; |
Line 300 drvctl_ioctl(struct file *fp, u_long cmd |
|
Line 313 drvctl_ioctl(struct file *fp, u_long cmd |
|
int res; |
int res; |
char *ifattr; |
char *ifattr; |
int *locs; |
int *locs; |
|
size_t locs_sz = 0; /* XXXgcc */ |
|
|
switch (cmd) { |
switch (cmd) { |
case DRVSUSPENDDEV: |
case DRVSUSPENDDEV: |
Line 330 drvctl_ioctl(struct file *fp, u_long cmd |
|
Line 344 drvctl_ioctl(struct file *fp, u_long cmd |
|
if (d->numlocators) { |
if (d->numlocators) { |
if (d->numlocators > MAXLOCATORS) |
if (d->numlocators > MAXLOCATORS) |
return (EINVAL); |
return (EINVAL); |
locs = malloc(d->numlocators * sizeof(int), M_DEVBUF, |
locs_sz = d->numlocators * sizeof(int); |
M_WAITOK); |
locs = kmem_alloc(locs_sz, KM_SLEEP); |
res = copyin(d->locators, locs, |
res = copyin(d->locators, locs, locs_sz); |
d->numlocators * sizeof(int)); |
|
if (res) { |
if (res) { |
free(locs, M_DEVBUF); |
kmem_free(locs, locs_sz); |
return (res); |
return (res); |
} |
} |
} else |
} else |
locs = 0; |
locs = NULL; |
res = rescanbus(d->busname, ifattr, d->numlocators, locs); |
res = rescanbus(d->busname, ifattr, d->numlocators, locs); |
if (locs) |
if (locs) |
free(locs, M_DEVBUF); |
kmem_free(locs, locs_sz); |
#undef d |
#undef d |
break; |
break; |
case DRVCTLCOMMAND: |
case DRVCTLCOMMAND: |
Line 360 drvctl_ioctl(struct file *fp, u_long cmd |
|
Line 373 drvctl_ioctl(struct file *fp, u_long cmd |
|
} |
} |
|
|
static int |
static int |
|
drvctl_stat(struct file *fp, struct stat *st) |
|
{ |
|
(void)memset(st, 0, sizeof(*st)); |
|
st->st_uid = kauth_cred_geteuid(fp->f_cred); |
|
st->st_gid = kauth_cred_getegid(fp->f_cred); |
|
return 0; |
|
} |
|
|
|
static int |
|
drvctl_poll(struct file *fp, int events) |
|
{ |
|
int revents = 0; |
|
|
|
if (!TAILQ_EMPTY(&drvctl_eventq)) |
|
revents |= events & (POLLIN | POLLRDNORM); |
|
else |
|
selrecord(curlwp, &drvctl_rdsel); |
|
|
|
return revents; |
|
} |
|
|
|
static int |
drvctl_close(struct file *fp) |
drvctl_close(struct file *fp) |
{ |
{ |
struct drvctl_event *dce; |
struct drvctl_event *dce; |