This source file includes following definitions.
- hotplugattach
- hotplug_device_attach
- hotplug_device_detach
- hotplug_put_event
- hotplug_get_event
- hotplugopen
- hotplugclose
- hotplugread
- hotplugioctl
- hotplugpoll
- hotplugkqfilter
- filt_hotplugrdetach
- filt_hotplugread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
171 case FIONBIO:
172
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 }