Annotation of sys/dev/hotplug.c, Revision 1.1.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