xref: /titanic_51/usr/src/uts/common/io/eventfd.c (revision 1767006bb066ef500b90b432fba79d63d0d09b36)
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
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
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
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
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
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
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
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
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
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
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
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
421*1767006bSBryan Cantrill _fini(void)
422*1767006bSBryan Cantrill {
423*1767006bSBryan Cantrill 	return (mod_remove(&modlinkage));
424*1767006bSBryan Cantrill }
425