Annotation of sys/dev/hotplug.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hotplug.c,v 1.8 2006/05/28 16:43:49 mk Exp $ */
! 2: /*
! 3: * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /*
! 19: * Device attachment and detachment notifications.
! 20: */
! 21:
! 22: #include <sys/param.h>
! 23: #include <sys/systm.h>
! 24: #include <sys/conf.h>
! 25: #include <sys/device.h>
! 26: #include <sys/fcntl.h>
! 27: #include <sys/hotplug.h>
! 28: #include <sys/ioctl.h>
! 29: #include <sys/poll.h>
! 30: #include <sys/vnode.h>
! 31:
! 32: #define HOTPLUG_MAXEVENTS 16
! 33:
! 34: static int opened;
! 35: static struct hotplug_event evqueue[HOTPLUG_MAXEVENTS];
! 36: static int evqueue_head, evqueue_tail, evqueue_count;
! 37: static struct selinfo hotplug_sel;
! 38:
! 39: void filt_hotplugrdetach(struct knote *);
! 40: int filt_hotplugread(struct knote *, long);
! 41:
! 42: struct filterops hotplugread_filtops =
! 43: { 1, NULL, filt_hotplugrdetach, filt_hotplugread};
! 44:
! 45: #define EVQUEUE_NEXT(p) (p == HOTPLUG_MAXEVENTS - 1 ? 0 : p + 1)
! 46:
! 47:
! 48: int hotplug_put_event(struct hotplug_event *);
! 49: int hotplug_get_event(struct hotplug_event *);
! 50:
! 51: void hotplugattach(int);
! 52:
! 53: void
! 54: hotplugattach(int count)
! 55: {
! 56: opened = 0;
! 57: evqueue_head = 0;
! 58: evqueue_tail = 0;
! 59: evqueue_count = 0;
! 60: }
! 61:
! 62: void
! 63: hotplug_device_attach(enum devclass class, char *name)
! 64: {
! 65: struct hotplug_event he;
! 66:
! 67: he.he_type = HOTPLUG_DEVAT;
! 68: he.he_devclass = class;
! 69: strlcpy(he.he_devname, name, sizeof(he.he_devname));
! 70: hotplug_put_event(&he);
! 71: }
! 72:
! 73: void
! 74: hotplug_device_detach(enum devclass class, char *name)
! 75: {
! 76: struct hotplug_event he;
! 77:
! 78: he.he_type = HOTPLUG_DEVDT;
! 79: he.he_devclass = class;
! 80: strlcpy(he.he_devname, name, sizeof(he.he_devname));
! 81: hotplug_put_event(&he);
! 82: }
! 83:
! 84: int
! 85: hotplug_put_event(struct hotplug_event *he)
! 86: {
! 87: if (evqueue_count == HOTPLUG_MAXEVENTS && opened) {
! 88: printf("hotplug: event lost, queue full\n");
! 89: return (1);
! 90: }
! 91:
! 92: evqueue[evqueue_head] = *he;
! 93: evqueue_head = EVQUEUE_NEXT(evqueue_head);
! 94: if (evqueue_count == HOTPLUG_MAXEVENTS)
! 95: evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
! 96: else
! 97: evqueue_count++;
! 98: wakeup(&evqueue);
! 99: selwakeup(&hotplug_sel);
! 100: KNOTE(&hotplug_sel.si_note, 0);
! 101: return (0);
! 102: }
! 103:
! 104: int
! 105: hotplug_get_event(struct hotplug_event *he)
! 106: {
! 107: int s;
! 108:
! 109: if (evqueue_count == 0)
! 110: return (1);
! 111:
! 112: s = splbio();
! 113: *he = evqueue[evqueue_tail];
! 114: evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
! 115: evqueue_count--;
! 116: splx(s);
! 117: return (0);
! 118: }
! 119:
! 120: int
! 121: hotplugopen(dev_t dev, int flag, int mode, struct proc *p)
! 122: {
! 123: if (minor(dev) != 0)
! 124: return (ENXIO);
! 125: if ((flag & FWRITE))
! 126: return (EPERM);
! 127: if (opened)
! 128: return (EBUSY);
! 129: opened = 1;
! 130: return (0);
! 131: }
! 132:
! 133: int
! 134: hotplugclose(dev_t dev, int flag, int mode, struct proc *p)
! 135: {
! 136: struct hotplug_event he;
! 137:
! 138: while (hotplug_get_event(&he) == 0)
! 139: ;
! 140: opened = 0;
! 141: return (0);
! 142: }
! 143:
! 144: int
! 145: hotplugread(dev_t dev, struct uio *uio, int flags)
! 146: {
! 147: struct hotplug_event he;
! 148: int error;
! 149:
! 150: if (uio->uio_resid != sizeof(he))
! 151: return (EINVAL);
! 152:
! 153: again:
! 154: if (hotplug_get_event(&he) == 0)
! 155: return (uiomove(&he, sizeof(he), uio));
! 156: if (flags & IO_NDELAY)
! 157: return (EAGAIN);
! 158:
! 159: error = tsleep(evqueue, PRIBIO | PCATCH, "htplev", 0);
! 160: if (error)
! 161: return (error);
! 162: goto again;
! 163: }
! 164:
! 165: int
! 166: hotplugioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 167: {
! 168: switch (cmd) {
! 169: case FIOASYNC:
! 170: /* ignore */
! 171: case FIONBIO:
! 172: /* handled in the upper fs layer */
! 173: break;
! 174: default:
! 175: return (ENOTTY);
! 176: }
! 177:
! 178: return (0);
! 179: }
! 180:
! 181: int
! 182: hotplugpoll(dev_t dev, int events, struct proc *p)
! 183: {
! 184: int revents = 0;
! 185:
! 186: if (events & (POLLIN | POLLRDNORM)) {
! 187: if (evqueue_count > 0)
! 188: revents |= events & (POLLIN | POLLRDNORM);
! 189: else
! 190: selrecord(p, &hotplug_sel);
! 191: }
! 192:
! 193: return (revents);
! 194: }
! 195:
! 196: int
! 197: hotplugkqfilter(dev_t dev, struct knote *kn)
! 198: {
! 199: struct klist *klist;
! 200: int s;
! 201:
! 202: switch (kn->kn_filter) {
! 203: case EVFILT_READ:
! 204: klist = &hotplug_sel.si_note;
! 205: kn->kn_fop = &hotplugread_filtops;
! 206: break;
! 207: default:
! 208: return (1);
! 209: }
! 210:
! 211: s = splbio();
! 212: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
! 213: splx(s);
! 214: return (0);
! 215: }
! 216:
! 217: void
! 218: filt_hotplugrdetach(struct knote *kn)
! 219: {
! 220: int s;
! 221:
! 222: s = splbio();
! 223: SLIST_REMOVE(&hotplug_sel.si_note, kn, knote, kn_selnext);
! 224: splx(s);
! 225: }
! 226:
! 227: int
! 228: filt_hotplugread(struct knote *kn, long hint)
! 229: {
! 230: kn->kn_data = evqueue_count;
! 231:
! 232: return (evqueue_count > 0);
! 233: }
CVSweb