1*1767006bSBryan Cantrill /*
2*1767006bSBryan Cantrill * This file and its contents are supplied under the terms of the
3*1767006bSBryan Cantrill * Common Development and Distribution License ("CDDL"), version 1.0.
4*1767006bSBryan Cantrill * You may only use this file in accordance with the terms of version
5*1767006bSBryan Cantrill * 1.0 of the CDDL.
6*1767006bSBryan Cantrill *
7*1767006bSBryan Cantrill * A full copy of the text of the CDDL should have accompanied this
8*1767006bSBryan Cantrill * source. A copy of the CDDL is also available via the Internet at
9*1767006bSBryan Cantrill * http://www.illumos.org/license/CDDL.
10*1767006bSBryan Cantrill */
11*1767006bSBryan Cantrill
12*1767006bSBryan Cantrill /*
13*1767006bSBryan Cantrill * Copyright (c) 2015 Joyent, Inc. All rights reserved.
14*1767006bSBryan Cantrill */
15*1767006bSBryan Cantrill
16*1767006bSBryan Cantrill /*
17*1767006bSBryan Cantrill * Support for the eventfd facility, a Linux-borne facility for user-generated
18*1767006bSBryan Cantrill * file descriptor-based events.
19*1767006bSBryan Cantrill */
20*1767006bSBryan Cantrill
21*1767006bSBryan Cantrill #include <sys/ddi.h>
22*1767006bSBryan Cantrill #include <sys/sunddi.h>
23*1767006bSBryan Cantrill #include <sys/eventfd.h>
24*1767006bSBryan Cantrill #include <sys/conf.h>
25*1767006bSBryan Cantrill #include <sys/vmem.h>
26*1767006bSBryan Cantrill #include <sys/sysmacros.h>
27*1767006bSBryan Cantrill #include <sys/filio.h>
28*1767006bSBryan Cantrill #include <sys/stat.h>
29*1767006bSBryan Cantrill #include <sys/file.h>
30*1767006bSBryan Cantrill
31*1767006bSBryan Cantrill struct eventfd_state;
32*1767006bSBryan Cantrill typedef struct eventfd_state eventfd_state_t;
33*1767006bSBryan Cantrill
34*1767006bSBryan Cantrill struct eventfd_state {
35*1767006bSBryan Cantrill kmutex_t efd_lock; /* lock protecting state */
36*1767006bSBryan Cantrill boolean_t efd_semaphore; /* boolean: sema. semantics */
37*1767006bSBryan Cantrill kcondvar_t efd_cv; /* condvar */
38*1767006bSBryan Cantrill pollhead_t efd_pollhd; /* poll head */
39*1767006bSBryan Cantrill uint64_t efd_value; /* value */
40*1767006bSBryan Cantrill eventfd_state_t *efd_next; /* next state on global list */
41*1767006bSBryan Cantrill };
42*1767006bSBryan Cantrill
43*1767006bSBryan Cantrill /*
44*1767006bSBryan Cantrill * Internal global variables.
45*1767006bSBryan Cantrill */
46*1767006bSBryan Cantrill static kmutex_t eventfd_lock; /* lock protecting state */
47*1767006bSBryan Cantrill static dev_info_t *eventfd_devi; /* device info */
48*1767006bSBryan Cantrill static vmem_t *eventfd_minor; /* minor number arena */
49*1767006bSBryan Cantrill static void *eventfd_softstate; /* softstate pointer */
50*1767006bSBryan Cantrill static eventfd_state_t *eventfd_state; /* global list of state */
51*1767006bSBryan Cantrill
52*1767006bSBryan Cantrill /*ARGSUSED*/
53*1767006bSBryan Cantrill static int
eventfd_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)54*1767006bSBryan Cantrill eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
55*1767006bSBryan Cantrill {
56*1767006bSBryan Cantrill eventfd_state_t *state;
57*1767006bSBryan Cantrill major_t major = getemajor(*devp);
58*1767006bSBryan Cantrill minor_t minor = getminor(*devp);
59*1767006bSBryan Cantrill
60*1767006bSBryan Cantrill if (minor != EVENTFDMNRN_EVENTFD)
61*1767006bSBryan Cantrill return (ENXIO);
62*1767006bSBryan Cantrill
63*1767006bSBryan Cantrill mutex_enter(&eventfd_lock);
64*1767006bSBryan Cantrill
65*1767006bSBryan Cantrill minor = (minor_t)(uintptr_t)vmem_alloc(eventfd_minor, 1,
66*1767006bSBryan Cantrill VM_BESTFIT | VM_SLEEP);
67*1767006bSBryan Cantrill
68*1767006bSBryan Cantrill if (ddi_soft_state_zalloc(eventfd_softstate, minor) != DDI_SUCCESS) {
69*1767006bSBryan Cantrill vmem_free(eventfd_minor, (void *)(uintptr_t)minor, 1);
70*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
71*1767006bSBryan Cantrill return (NULL);
72*1767006bSBryan Cantrill }
73*1767006bSBryan Cantrill
74*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
75*1767006bSBryan Cantrill *devp = makedevice(major, minor);
76*1767006bSBryan Cantrill
77*1767006bSBryan Cantrill state->efd_next = eventfd_state;
78*1767006bSBryan Cantrill eventfd_state = state;
79*1767006bSBryan Cantrill
80*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
81*1767006bSBryan Cantrill
82*1767006bSBryan Cantrill return (0);
83*1767006bSBryan Cantrill }
84*1767006bSBryan Cantrill
85*1767006bSBryan Cantrill /*ARGSUSED*/
86*1767006bSBryan Cantrill static int
eventfd_read(dev_t dev,uio_t * uio,cred_t * cr)87*1767006bSBryan Cantrill eventfd_read(dev_t dev, uio_t *uio, cred_t *cr)
88*1767006bSBryan Cantrill {
89*1767006bSBryan Cantrill eventfd_state_t *state;
90*1767006bSBryan Cantrill minor_t minor = getminor(dev);
91*1767006bSBryan Cantrill uint64_t val, oval;
92*1767006bSBryan Cantrill int err;
93*1767006bSBryan Cantrill
94*1767006bSBryan Cantrill if (uio->uio_resid < sizeof (val))
95*1767006bSBryan Cantrill return (EINVAL);
96*1767006bSBryan Cantrill
97*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
98*1767006bSBryan Cantrill
99*1767006bSBryan Cantrill mutex_enter(&state->efd_lock);
100*1767006bSBryan Cantrill
101*1767006bSBryan Cantrill while (state->efd_value == 0) {
102*1767006bSBryan Cantrill if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
103*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
104*1767006bSBryan Cantrill return (EAGAIN);
105*1767006bSBryan Cantrill }
106*1767006bSBryan Cantrill
107*1767006bSBryan Cantrill if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
108*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
109*1767006bSBryan Cantrill return (EINTR);
110*1767006bSBryan Cantrill }
111*1767006bSBryan Cantrill }
112*1767006bSBryan Cantrill
113*1767006bSBryan Cantrill /*
114*1767006bSBryan Cantrill * We have a non-zero value and we own the lock; our behavior now
115*1767006bSBryan Cantrill * depends on whether or not EFD_SEMAPHORE was set when the eventfd
116*1767006bSBryan Cantrill * was created.
117*1767006bSBryan Cantrill */
118*1767006bSBryan Cantrill val = oval = state->efd_value;
119*1767006bSBryan Cantrill
120*1767006bSBryan Cantrill if (state->efd_semaphore) {
121*1767006bSBryan Cantrill state->efd_value--;
122*1767006bSBryan Cantrill val = 1;
123*1767006bSBryan Cantrill } else {
124*1767006bSBryan Cantrill state->efd_value = 0;
125*1767006bSBryan Cantrill }
126*1767006bSBryan Cantrill
127*1767006bSBryan Cantrill err = uiomove(&val, sizeof (val), UIO_READ, uio);
128*1767006bSBryan Cantrill
129*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
130*1767006bSBryan Cantrill
131*1767006bSBryan Cantrill if (oval == EVENTFD_VALMAX) {
132*1767006bSBryan Cantrill cv_broadcast(&state->efd_cv);
133*1767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
134*1767006bSBryan Cantrill }
135*1767006bSBryan Cantrill
136*1767006bSBryan Cantrill return (err);
137*1767006bSBryan Cantrill }
138*1767006bSBryan Cantrill
139*1767006bSBryan Cantrill /*ARGSUSED*/
140*1767006bSBryan Cantrill static int
eventfd_write(dev_t dev,struct uio * uio,cred_t * credp)141*1767006bSBryan Cantrill eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
142*1767006bSBryan Cantrill {
143*1767006bSBryan Cantrill eventfd_state_t *state;
144*1767006bSBryan Cantrill minor_t minor = getminor(dev);
145*1767006bSBryan Cantrill uint64_t val, oval;
146*1767006bSBryan Cantrill int err;
147*1767006bSBryan Cantrill
148*1767006bSBryan Cantrill if (uio->uio_resid < sizeof (val))
149*1767006bSBryan Cantrill return (EINVAL);
150*1767006bSBryan Cantrill
151*1767006bSBryan Cantrill if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
152*1767006bSBryan Cantrill return (err);
153*1767006bSBryan Cantrill
154*1767006bSBryan Cantrill if (val > EVENTFD_VALMAX)
155*1767006bSBryan Cantrill return (EINVAL);
156*1767006bSBryan Cantrill
157*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
158*1767006bSBryan Cantrill
159*1767006bSBryan Cantrill mutex_enter(&state->efd_lock);
160*1767006bSBryan Cantrill
161*1767006bSBryan Cantrill while (val > EVENTFD_VALMAX - state->efd_value) {
162*1767006bSBryan Cantrill if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
163*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
164*1767006bSBryan Cantrill return (EAGAIN);
165*1767006bSBryan Cantrill }
166*1767006bSBryan Cantrill
167*1767006bSBryan Cantrill if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
168*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
169*1767006bSBryan Cantrill return (EINTR);
170*1767006bSBryan Cantrill }
171*1767006bSBryan Cantrill }
172*1767006bSBryan Cantrill
173*1767006bSBryan Cantrill /*
174*1767006bSBryan Cantrill * We now know that we can add the value without overflowing.
175*1767006bSBryan Cantrill */
176*1767006bSBryan Cantrill state->efd_value = (oval = state->efd_value) + val;
177*1767006bSBryan Cantrill
178*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
179*1767006bSBryan Cantrill
180*1767006bSBryan Cantrill if (oval == 0) {
181*1767006bSBryan Cantrill cv_broadcast(&state->efd_cv);
182*1767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
183*1767006bSBryan Cantrill }
184*1767006bSBryan Cantrill
185*1767006bSBryan Cantrill return (0);
186*1767006bSBryan Cantrill }
187*1767006bSBryan Cantrill
188*1767006bSBryan Cantrill /*ARGSUSED*/
189*1767006bSBryan Cantrill static int
eventfd_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)190*1767006bSBryan Cantrill eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
191*1767006bSBryan Cantrill struct pollhead **phpp)
192*1767006bSBryan Cantrill {
193*1767006bSBryan Cantrill eventfd_state_t *state;
194*1767006bSBryan Cantrill minor_t minor = getminor(dev);
195*1767006bSBryan Cantrill short revents = 0;
196*1767006bSBryan Cantrill
197*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
198*1767006bSBryan Cantrill
199*1767006bSBryan Cantrill mutex_enter(&state->efd_lock);
200*1767006bSBryan Cantrill
201*1767006bSBryan Cantrill if (state->efd_value > 0)
202*1767006bSBryan Cantrill revents |= POLLRDNORM | POLLIN;
203*1767006bSBryan Cantrill
204*1767006bSBryan Cantrill if (state->efd_value < EVENTFD_VALMAX)
205*1767006bSBryan Cantrill revents |= POLLWRNORM | POLLOUT;
206*1767006bSBryan Cantrill
207*1767006bSBryan Cantrill if (!(*reventsp = revents & events) && !anyyet)
208*1767006bSBryan Cantrill *phpp = &state->efd_pollhd;
209*1767006bSBryan Cantrill
210*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
211*1767006bSBryan Cantrill
212*1767006bSBryan Cantrill return (0);
213*1767006bSBryan Cantrill }
214*1767006bSBryan Cantrill
215*1767006bSBryan Cantrill /*ARGSUSED*/
216*1767006bSBryan Cantrill static int
eventfd_ioctl(dev_t dev,int cmd,intptr_t arg,int md,cred_t * cr,int * rv)217*1767006bSBryan Cantrill eventfd_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv)
218*1767006bSBryan Cantrill {
219*1767006bSBryan Cantrill eventfd_state_t *state;
220*1767006bSBryan Cantrill minor_t minor = getminor(dev);
221*1767006bSBryan Cantrill
222*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
223*1767006bSBryan Cantrill
224*1767006bSBryan Cantrill switch (cmd) {
225*1767006bSBryan Cantrill case EVENTFDIOC_SEMAPHORE: {
226*1767006bSBryan Cantrill mutex_enter(&state->efd_lock);
227*1767006bSBryan Cantrill state->efd_semaphore ^= 1;
228*1767006bSBryan Cantrill mutex_exit(&state->efd_lock);
229*1767006bSBryan Cantrill
230*1767006bSBryan Cantrill return (0);
231*1767006bSBryan Cantrill }
232*1767006bSBryan Cantrill
233*1767006bSBryan Cantrill default:
234*1767006bSBryan Cantrill break;
235*1767006bSBryan Cantrill }
236*1767006bSBryan Cantrill
237*1767006bSBryan Cantrill return (ENOTTY);
238*1767006bSBryan Cantrill }
239*1767006bSBryan Cantrill
240*1767006bSBryan Cantrill /*ARGSUSED*/
241*1767006bSBryan Cantrill static int
eventfd_close(dev_t dev,int flag,int otyp,cred_t * cred_p)242*1767006bSBryan Cantrill eventfd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
243*1767006bSBryan Cantrill {
244*1767006bSBryan Cantrill eventfd_state_t *state, **sp;
245*1767006bSBryan Cantrill minor_t minor = getminor(dev);
246*1767006bSBryan Cantrill
247*1767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
248*1767006bSBryan Cantrill
249*1767006bSBryan Cantrill if (state->efd_pollhd.ph_list != NULL) {
250*1767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLERR);
251*1767006bSBryan Cantrill pollhead_clean(&state->efd_pollhd);
252*1767006bSBryan Cantrill }
253*1767006bSBryan Cantrill
254*1767006bSBryan Cantrill mutex_enter(&eventfd_lock);
255*1767006bSBryan Cantrill
256*1767006bSBryan Cantrill /*
257*1767006bSBryan Cantrill * Remove our state from our global list.
258*1767006bSBryan Cantrill */
259*1767006bSBryan Cantrill for (sp = &eventfd_state; *sp != state; sp = &((*sp)->efd_next))
260*1767006bSBryan Cantrill VERIFY(*sp != NULL);
261*1767006bSBryan Cantrill
262*1767006bSBryan Cantrill *sp = (*sp)->efd_next;
263*1767006bSBryan Cantrill
264*1767006bSBryan Cantrill ddi_soft_state_free(eventfd_softstate, minor);
265*1767006bSBryan Cantrill vmem_free(eventfd_minor, (void *)(uintptr_t)minor, 1);
266*1767006bSBryan Cantrill
267*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
268*1767006bSBryan Cantrill
269*1767006bSBryan Cantrill return (0);
270*1767006bSBryan Cantrill }
271*1767006bSBryan Cantrill
272*1767006bSBryan Cantrill static int
eventfd_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)273*1767006bSBryan Cantrill eventfd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
274*1767006bSBryan Cantrill {
275*1767006bSBryan Cantrill switch (cmd) {
276*1767006bSBryan Cantrill case DDI_ATTACH:
277*1767006bSBryan Cantrill break;
278*1767006bSBryan Cantrill
279*1767006bSBryan Cantrill case DDI_RESUME:
280*1767006bSBryan Cantrill return (DDI_SUCCESS);
281*1767006bSBryan Cantrill
282*1767006bSBryan Cantrill default:
283*1767006bSBryan Cantrill return (DDI_FAILURE);
284*1767006bSBryan Cantrill }
285*1767006bSBryan Cantrill
286*1767006bSBryan Cantrill mutex_enter(&eventfd_lock);
287*1767006bSBryan Cantrill
288*1767006bSBryan Cantrill if (ddi_soft_state_init(&eventfd_softstate,
289*1767006bSBryan Cantrill sizeof (eventfd_state_t), 0) != 0) {
290*1767006bSBryan Cantrill cmn_err(CE_NOTE, "/dev/eventfd failed to create soft state");
291*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
292*1767006bSBryan Cantrill return (DDI_FAILURE);
293*1767006bSBryan Cantrill }
294*1767006bSBryan Cantrill
295*1767006bSBryan Cantrill if (ddi_create_minor_node(devi, "eventfd", S_IFCHR,
296*1767006bSBryan Cantrill EVENTFDMNRN_EVENTFD, DDI_PSEUDO, NULL) == DDI_FAILURE) {
297*1767006bSBryan Cantrill cmn_err(CE_NOTE, "/dev/eventfd couldn't create minor node");
298*1767006bSBryan Cantrill ddi_soft_state_fini(&eventfd_softstate);
299*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
300*1767006bSBryan Cantrill return (DDI_FAILURE);
301*1767006bSBryan Cantrill }
302*1767006bSBryan Cantrill
303*1767006bSBryan Cantrill ddi_report_dev(devi);
304*1767006bSBryan Cantrill eventfd_devi = devi;
305*1767006bSBryan Cantrill
306*1767006bSBryan Cantrill eventfd_minor = vmem_create("eventfd_minor", (void *)EVENTFDMNRN_CLONE,
307*1767006bSBryan Cantrill UINT32_MAX - EVENTFDMNRN_CLONE, 1, NULL, NULL, NULL, 0,
308*1767006bSBryan Cantrill VM_SLEEP | VMC_IDENTIFIER);
309*1767006bSBryan Cantrill
310*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
311*1767006bSBryan Cantrill
312*1767006bSBryan Cantrill return (DDI_SUCCESS);
313*1767006bSBryan Cantrill }
314*1767006bSBryan Cantrill
315*1767006bSBryan Cantrill /*ARGSUSED*/
316*1767006bSBryan Cantrill static int
eventfd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)317*1767006bSBryan Cantrill eventfd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
318*1767006bSBryan Cantrill {
319*1767006bSBryan Cantrill switch (cmd) {
320*1767006bSBryan Cantrill case DDI_DETACH:
321*1767006bSBryan Cantrill break;
322*1767006bSBryan Cantrill
323*1767006bSBryan Cantrill case DDI_SUSPEND:
324*1767006bSBryan Cantrill return (DDI_SUCCESS);
325*1767006bSBryan Cantrill
326*1767006bSBryan Cantrill default:
327*1767006bSBryan Cantrill return (DDI_FAILURE);
328*1767006bSBryan Cantrill }
329*1767006bSBryan Cantrill
330*1767006bSBryan Cantrill mutex_enter(&eventfd_lock);
331*1767006bSBryan Cantrill vmem_destroy(eventfd_minor);
332*1767006bSBryan Cantrill
333*1767006bSBryan Cantrill ddi_remove_minor_node(eventfd_devi, NULL);
334*1767006bSBryan Cantrill eventfd_devi = NULL;
335*1767006bSBryan Cantrill
336*1767006bSBryan Cantrill ddi_soft_state_fini(&eventfd_softstate);
337*1767006bSBryan Cantrill mutex_exit(&eventfd_lock);
338*1767006bSBryan Cantrill
339*1767006bSBryan Cantrill return (DDI_SUCCESS);
340*1767006bSBryan Cantrill }
341*1767006bSBryan Cantrill
342*1767006bSBryan Cantrill /*ARGSUSED*/
343*1767006bSBryan Cantrill static int
eventfd_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)344*1767006bSBryan Cantrill eventfd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
345*1767006bSBryan Cantrill {
346*1767006bSBryan Cantrill int error;
347*1767006bSBryan Cantrill
348*1767006bSBryan Cantrill switch (infocmd) {
349*1767006bSBryan Cantrill case DDI_INFO_DEVT2DEVINFO:
350*1767006bSBryan Cantrill *result = (void *)eventfd_devi;
351*1767006bSBryan Cantrill error = DDI_SUCCESS;
352*1767006bSBryan Cantrill break;
353*1767006bSBryan Cantrill case DDI_INFO_DEVT2INSTANCE:
354*1767006bSBryan Cantrill *result = (void *)0;
355*1767006bSBryan Cantrill error = DDI_SUCCESS;
356*1767006bSBryan Cantrill break;
357*1767006bSBryan Cantrill default:
358*1767006bSBryan Cantrill error = DDI_FAILURE;
359*1767006bSBryan Cantrill }
360*1767006bSBryan Cantrill return (error);
361*1767006bSBryan Cantrill }
362*1767006bSBryan Cantrill
363*1767006bSBryan Cantrill static struct cb_ops eventfd_cb_ops = {
364*1767006bSBryan Cantrill eventfd_open, /* open */
365*1767006bSBryan Cantrill eventfd_close, /* close */
366*1767006bSBryan Cantrill nulldev, /* strategy */
367*1767006bSBryan Cantrill nulldev, /* print */
368*1767006bSBryan Cantrill nodev, /* dump */
369*1767006bSBryan Cantrill eventfd_read, /* read */
370*1767006bSBryan Cantrill eventfd_write, /* write */
371*1767006bSBryan Cantrill eventfd_ioctl, /* ioctl */
372*1767006bSBryan Cantrill nodev, /* devmap */
373*1767006bSBryan Cantrill nodev, /* mmap */
374*1767006bSBryan Cantrill nodev, /* segmap */
375*1767006bSBryan Cantrill eventfd_poll, /* poll */
376*1767006bSBryan Cantrill ddi_prop_op, /* cb_prop_op */
377*1767006bSBryan Cantrill 0, /* streamtab */
378*1767006bSBryan Cantrill D_NEW | D_MP /* Driver compatibility flag */
379*1767006bSBryan Cantrill };
380*1767006bSBryan Cantrill
381*1767006bSBryan Cantrill static struct dev_ops eventfd_ops = {
382*1767006bSBryan Cantrill DEVO_REV, /* devo_rev */
383*1767006bSBryan Cantrill 0, /* refcnt */
384*1767006bSBryan Cantrill eventfd_info, /* get_dev_info */
385*1767006bSBryan Cantrill nulldev, /* identify */
386*1767006bSBryan Cantrill nulldev, /* probe */
387*1767006bSBryan Cantrill eventfd_attach, /* attach */
388*1767006bSBryan Cantrill eventfd_detach, /* detach */
389*1767006bSBryan Cantrill nodev, /* reset */
390*1767006bSBryan Cantrill &eventfd_cb_ops, /* driver operations */
391*1767006bSBryan Cantrill NULL, /* bus operations */
392*1767006bSBryan Cantrill nodev, /* dev power */
393*1767006bSBryan Cantrill ddi_quiesce_not_needed, /* quiesce */
394*1767006bSBryan Cantrill };
395*1767006bSBryan Cantrill
396*1767006bSBryan Cantrill static struct modldrv modldrv = {
397*1767006bSBryan Cantrill &mod_driverops, /* module type (this is a pseudo driver) */
398*1767006bSBryan Cantrill "eventfd support", /* name of module */
399*1767006bSBryan Cantrill &eventfd_ops, /* driver ops */
400*1767006bSBryan Cantrill };
401*1767006bSBryan Cantrill
402*1767006bSBryan Cantrill static struct modlinkage modlinkage = {
403*1767006bSBryan Cantrill MODREV_1,
404*1767006bSBryan Cantrill (void *)&modldrv,
405*1767006bSBryan Cantrill NULL
406*1767006bSBryan Cantrill };
407*1767006bSBryan Cantrill
408*1767006bSBryan Cantrill int
_init(void)409*1767006bSBryan Cantrill _init(void)
410*1767006bSBryan Cantrill {
411*1767006bSBryan Cantrill return (mod_install(&modlinkage));
412*1767006bSBryan Cantrill }
413*1767006bSBryan Cantrill
414*1767006bSBryan Cantrill int
_info(struct modinfo * modinfop)415*1767006bSBryan Cantrill _info(struct modinfo *modinfop)
416*1767006bSBryan Cantrill {
417*1767006bSBryan Cantrill return (mod_info(&modlinkage, modinfop));
418*1767006bSBryan Cantrill }
419*1767006bSBryan Cantrill
420*1767006bSBryan Cantrill int
_fini(void)421*1767006bSBryan Cantrill _fini(void)
422*1767006bSBryan Cantrill {
423*1767006bSBryan Cantrill return (mod_remove(&modlinkage));
424*1767006bSBryan Cantrill }
425