11767006bSBryan Cantrill /*
21767006bSBryan Cantrill * This file and its contents are supplied under the terms of the
31767006bSBryan Cantrill * Common Development and Distribution License ("CDDL"), version 1.0.
41767006bSBryan Cantrill * You may only use this file in accordance with the terms of version
51767006bSBryan Cantrill * 1.0 of the CDDL.
61767006bSBryan Cantrill *
71767006bSBryan Cantrill * A full copy of the text of the CDDL should have accompanied this
81767006bSBryan Cantrill * source. A copy of the CDDL is also available via the Internet at
91767006bSBryan Cantrill * http://www.illumos.org/license/CDDL.
101767006bSBryan Cantrill */
111767006bSBryan Cantrill
121767006bSBryan Cantrill /*
1380d5689fSPatrick Mooney * Copyright 2017 Joyent, Inc.
141767006bSBryan Cantrill */
151767006bSBryan Cantrill
161767006bSBryan Cantrill /*
171767006bSBryan Cantrill * Support for the eventfd facility, a Linux-borne facility for user-generated
181767006bSBryan Cantrill * file descriptor-based events.
191767006bSBryan Cantrill */
201767006bSBryan Cantrill
211767006bSBryan Cantrill #include <sys/ddi.h>
221767006bSBryan Cantrill #include <sys/sunddi.h>
231767006bSBryan Cantrill #include <sys/eventfd.h>
241767006bSBryan Cantrill #include <sys/conf.h>
251767006bSBryan Cantrill #include <sys/vmem.h>
261767006bSBryan Cantrill #include <sys/sysmacros.h>
271767006bSBryan Cantrill #include <sys/filio.h>
281767006bSBryan Cantrill #include <sys/stat.h>
291767006bSBryan Cantrill #include <sys/file.h>
301767006bSBryan Cantrill
311767006bSBryan Cantrill struct eventfd_state;
321767006bSBryan Cantrill typedef struct eventfd_state eventfd_state_t;
331767006bSBryan Cantrill
341767006bSBryan Cantrill struct eventfd_state {
351767006bSBryan Cantrill kmutex_t efd_lock; /* lock protecting state */
361767006bSBryan Cantrill boolean_t efd_semaphore; /* boolean: sema. semantics */
371767006bSBryan Cantrill kcondvar_t efd_cv; /* condvar */
381767006bSBryan Cantrill pollhead_t efd_pollhd; /* poll head */
391767006bSBryan Cantrill uint64_t efd_value; /* value */
40860884ebSPatrick Mooney size_t efd_bwriters; /* count of blocked writers */
411767006bSBryan Cantrill eventfd_state_t *efd_next; /* next state on global list */
421767006bSBryan Cantrill };
431767006bSBryan Cantrill
441767006bSBryan Cantrill /*
451767006bSBryan Cantrill * Internal global variables.
461767006bSBryan Cantrill */
471767006bSBryan Cantrill static kmutex_t eventfd_lock; /* lock protecting state */
481767006bSBryan Cantrill static dev_info_t *eventfd_devi; /* device info */
491767006bSBryan Cantrill static vmem_t *eventfd_minor; /* minor number arena */
501767006bSBryan Cantrill static void *eventfd_softstate; /* softstate pointer */
511767006bSBryan Cantrill static eventfd_state_t *eventfd_state; /* global list of state */
521767006bSBryan Cantrill
531767006bSBryan Cantrill /*ARGSUSED*/
541767006bSBryan Cantrill static int
eventfd_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)551767006bSBryan Cantrill eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
561767006bSBryan Cantrill {
571767006bSBryan Cantrill eventfd_state_t *state;
581767006bSBryan Cantrill major_t major = getemajor(*devp);
591767006bSBryan Cantrill minor_t minor = getminor(*devp);
601767006bSBryan Cantrill
611767006bSBryan Cantrill if (minor != EVENTFDMNRN_EVENTFD)
621767006bSBryan Cantrill return (ENXIO);
631767006bSBryan Cantrill
641767006bSBryan Cantrill mutex_enter(&eventfd_lock);
651767006bSBryan Cantrill
661767006bSBryan Cantrill minor = (minor_t)(uintptr_t)vmem_alloc(eventfd_minor, 1,
671767006bSBryan Cantrill VM_BESTFIT | VM_SLEEP);
681767006bSBryan Cantrill
691767006bSBryan Cantrill if (ddi_soft_state_zalloc(eventfd_softstate, minor) != DDI_SUCCESS) {
701767006bSBryan Cantrill vmem_free(eventfd_minor, (void *)(uintptr_t)minor, 1);
711767006bSBryan Cantrill mutex_exit(&eventfd_lock);
72*3deeb0a9SToomas Soome return (ENXIO);
731767006bSBryan Cantrill }
741767006bSBryan Cantrill
751767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
761767006bSBryan Cantrill *devp = makedevice(major, minor);
771767006bSBryan Cantrill
781767006bSBryan Cantrill state->efd_next = eventfd_state;
791767006bSBryan Cantrill eventfd_state = state;
801767006bSBryan Cantrill
811767006bSBryan Cantrill mutex_exit(&eventfd_lock);
821767006bSBryan Cantrill
831767006bSBryan Cantrill return (0);
841767006bSBryan Cantrill }
851767006bSBryan Cantrill
861767006bSBryan Cantrill /*ARGSUSED*/
871767006bSBryan Cantrill static int
eventfd_read(dev_t dev,uio_t * uio,cred_t * cr)881767006bSBryan Cantrill eventfd_read(dev_t dev, uio_t *uio, cred_t *cr)
891767006bSBryan Cantrill {
901767006bSBryan Cantrill eventfd_state_t *state;
911767006bSBryan Cantrill minor_t minor = getminor(dev);
921767006bSBryan Cantrill uint64_t val, oval;
931767006bSBryan Cantrill int err;
941767006bSBryan Cantrill
951767006bSBryan Cantrill if (uio->uio_resid < sizeof (val))
961767006bSBryan Cantrill return (EINVAL);
971767006bSBryan Cantrill
981767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
991767006bSBryan Cantrill
1001767006bSBryan Cantrill mutex_enter(&state->efd_lock);
1011767006bSBryan Cantrill
1021767006bSBryan Cantrill while (state->efd_value == 0) {
1031767006bSBryan Cantrill if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
1041767006bSBryan Cantrill mutex_exit(&state->efd_lock);
1051767006bSBryan Cantrill return (EAGAIN);
1061767006bSBryan Cantrill }
1071767006bSBryan Cantrill
1081767006bSBryan Cantrill if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
1091767006bSBryan Cantrill mutex_exit(&state->efd_lock);
1101767006bSBryan Cantrill return (EINTR);
1111767006bSBryan Cantrill }
1121767006bSBryan Cantrill }
1131767006bSBryan Cantrill
1141767006bSBryan Cantrill /*
1151767006bSBryan Cantrill * We have a non-zero value and we own the lock; our behavior now
1161767006bSBryan Cantrill * depends on whether or not EFD_SEMAPHORE was set when the eventfd
1171767006bSBryan Cantrill * was created.
1181767006bSBryan Cantrill */
1191767006bSBryan Cantrill val = oval = state->efd_value;
1201767006bSBryan Cantrill
1211767006bSBryan Cantrill if (state->efd_semaphore) {
1221767006bSBryan Cantrill state->efd_value--;
1231767006bSBryan Cantrill val = 1;
1241767006bSBryan Cantrill } else {
1251767006bSBryan Cantrill state->efd_value = 0;
1261767006bSBryan Cantrill }
1271767006bSBryan Cantrill
1281767006bSBryan Cantrill err = uiomove(&val, sizeof (val), UIO_READ, uio);
1291767006bSBryan Cantrill
130860884ebSPatrick Mooney /*
131860884ebSPatrick Mooney * Wake any writers blocked on this eventfd as this read operation may
132860884ebSPatrick Mooney * have created adequate capacity for their values.
133860884ebSPatrick Mooney */
134860884ebSPatrick Mooney if (state->efd_bwriters != 0) {
135860884ebSPatrick Mooney cv_broadcast(&state->efd_cv);
136860884ebSPatrick Mooney }
1371767006bSBryan Cantrill mutex_exit(&state->efd_lock);
1381767006bSBryan Cantrill
139860884ebSPatrick Mooney /*
140860884ebSPatrick Mooney * It is necessary to emit POLLOUT events only when the eventfd
141860884ebSPatrick Mooney * transitions from EVENTFD_VALMAX to a lower value. At all other
142860884ebSPatrick Mooney * times, it is already considered writable by poll.
143860884ebSPatrick Mooney */
1441767006bSBryan Cantrill if (oval == EVENTFD_VALMAX) {
1451767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
1461767006bSBryan Cantrill }
1471767006bSBryan Cantrill
1481767006bSBryan Cantrill return (err);
1491767006bSBryan Cantrill }
1501767006bSBryan Cantrill
1511767006bSBryan Cantrill /*ARGSUSED*/
1521767006bSBryan Cantrill static int
eventfd_write(dev_t dev,struct uio * uio,cred_t * credp)1531767006bSBryan Cantrill eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
1541767006bSBryan Cantrill {
1551767006bSBryan Cantrill eventfd_state_t *state;
1561767006bSBryan Cantrill minor_t minor = getminor(dev);
1571767006bSBryan Cantrill uint64_t val, oval;
1581767006bSBryan Cantrill int err;
1591767006bSBryan Cantrill
1601767006bSBryan Cantrill if (uio->uio_resid < sizeof (val))
1611767006bSBryan Cantrill return (EINVAL);
1621767006bSBryan Cantrill
1631767006bSBryan Cantrill if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
1641767006bSBryan Cantrill return (err);
1651767006bSBryan Cantrill
1661767006bSBryan Cantrill if (val > EVENTFD_VALMAX)
1671767006bSBryan Cantrill return (EINVAL);
1681767006bSBryan Cantrill
1691767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
1701767006bSBryan Cantrill
1711767006bSBryan Cantrill mutex_enter(&state->efd_lock);
1721767006bSBryan Cantrill
1731767006bSBryan Cantrill while (val > EVENTFD_VALMAX - state->efd_value) {
1741767006bSBryan Cantrill if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
1751767006bSBryan Cantrill mutex_exit(&state->efd_lock);
1761767006bSBryan Cantrill return (EAGAIN);
1771767006bSBryan Cantrill }
1781767006bSBryan Cantrill
179860884ebSPatrick Mooney state->efd_bwriters++;
1801767006bSBryan Cantrill if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
181860884ebSPatrick Mooney state->efd_bwriters--;
1821767006bSBryan Cantrill mutex_exit(&state->efd_lock);
1831767006bSBryan Cantrill return (EINTR);
1841767006bSBryan Cantrill }
185860884ebSPatrick Mooney state->efd_bwriters--;
1861767006bSBryan Cantrill }
1871767006bSBryan Cantrill
1881767006bSBryan Cantrill /*
1891767006bSBryan Cantrill * We now know that we can add the value without overflowing.
1901767006bSBryan Cantrill */
1911767006bSBryan Cantrill state->efd_value = (oval = state->efd_value) + val;
1921767006bSBryan Cantrill
193860884ebSPatrick Mooney /*
194860884ebSPatrick Mooney * If the value was previously "empty", notify blocked readers that
195860884ebSPatrick Mooney * data is available.
196860884ebSPatrick Mooney */
197860884ebSPatrick Mooney if (oval == 0) {
198860884ebSPatrick Mooney cv_broadcast(&state->efd_cv);
199860884ebSPatrick Mooney }
2001767006bSBryan Cantrill mutex_exit(&state->efd_lock);
2011767006bSBryan Cantrill
202860884ebSPatrick Mooney /*
203860884ebSPatrick Mooney * Notify pollers as well if the eventfd is now readable.
204860884ebSPatrick Mooney */
2051767006bSBryan Cantrill if (oval == 0) {
2061767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
2071767006bSBryan Cantrill }
2081767006bSBryan Cantrill
2091767006bSBryan Cantrill return (0);
2101767006bSBryan Cantrill }
2111767006bSBryan Cantrill
2121767006bSBryan Cantrill /*ARGSUSED*/
2131767006bSBryan Cantrill static int
eventfd_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)2141767006bSBryan Cantrill eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
2151767006bSBryan Cantrill struct pollhead **phpp)
2161767006bSBryan Cantrill {
2171767006bSBryan Cantrill eventfd_state_t *state;
2181767006bSBryan Cantrill minor_t minor = getminor(dev);
2191767006bSBryan Cantrill short revents = 0;
2201767006bSBryan Cantrill
2211767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
2221767006bSBryan Cantrill
2231767006bSBryan Cantrill mutex_enter(&state->efd_lock);
2241767006bSBryan Cantrill
2251767006bSBryan Cantrill if (state->efd_value > 0)
2261767006bSBryan Cantrill revents |= POLLRDNORM | POLLIN;
2271767006bSBryan Cantrill
2281767006bSBryan Cantrill if (state->efd_value < EVENTFD_VALMAX)
2291767006bSBryan Cantrill revents |= POLLWRNORM | POLLOUT;
2301767006bSBryan Cantrill
23180d5689fSPatrick Mooney *reventsp = revents & events;
23280d5689fSPatrick Mooney if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
2331767006bSBryan Cantrill *phpp = &state->efd_pollhd;
23480d5689fSPatrick Mooney }
2351767006bSBryan Cantrill
2361767006bSBryan Cantrill mutex_exit(&state->efd_lock);
2371767006bSBryan Cantrill
2381767006bSBryan Cantrill return (0);
2391767006bSBryan Cantrill }
2401767006bSBryan Cantrill
2411767006bSBryan Cantrill /*ARGSUSED*/
2421767006bSBryan Cantrill static int
eventfd_ioctl(dev_t dev,int cmd,intptr_t arg,int md,cred_t * cr,int * rv)2431767006bSBryan Cantrill eventfd_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv)
2441767006bSBryan Cantrill {
2451767006bSBryan Cantrill eventfd_state_t *state;
2461767006bSBryan Cantrill minor_t minor = getminor(dev);
2471767006bSBryan Cantrill
2481767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
2491767006bSBryan Cantrill
2501767006bSBryan Cantrill switch (cmd) {
2511767006bSBryan Cantrill case EVENTFDIOC_SEMAPHORE: {
2521767006bSBryan Cantrill mutex_enter(&state->efd_lock);
2531767006bSBryan Cantrill state->efd_semaphore ^= 1;
2541767006bSBryan Cantrill mutex_exit(&state->efd_lock);
2551767006bSBryan Cantrill
2561767006bSBryan Cantrill return (0);
2571767006bSBryan Cantrill }
2581767006bSBryan Cantrill
2591767006bSBryan Cantrill default:
2601767006bSBryan Cantrill break;
2611767006bSBryan Cantrill }
2621767006bSBryan Cantrill
2631767006bSBryan Cantrill return (ENOTTY);
2641767006bSBryan Cantrill }
2651767006bSBryan Cantrill
2661767006bSBryan Cantrill /*ARGSUSED*/
2671767006bSBryan Cantrill static int
eventfd_close(dev_t dev,int flag,int otyp,cred_t * cred_p)2681767006bSBryan Cantrill eventfd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
2691767006bSBryan Cantrill {
2701767006bSBryan Cantrill eventfd_state_t *state, **sp;
2711767006bSBryan Cantrill minor_t minor = getminor(dev);
2721767006bSBryan Cantrill
2731767006bSBryan Cantrill state = ddi_get_soft_state(eventfd_softstate, minor);
2741767006bSBryan Cantrill
2751767006bSBryan Cantrill if (state->efd_pollhd.ph_list != NULL) {
2761767006bSBryan Cantrill pollwakeup(&state->efd_pollhd, POLLERR);
2771767006bSBryan Cantrill pollhead_clean(&state->efd_pollhd);
2781767006bSBryan Cantrill }
2791767006bSBryan Cantrill
2801767006bSBryan Cantrill mutex_enter(&eventfd_lock);
2811767006bSBryan Cantrill
2821767006bSBryan Cantrill /*
2831767006bSBryan Cantrill * Remove our state from our global list.
2841767006bSBryan Cantrill */
2851767006bSBryan Cantrill for (sp = &eventfd_state; *sp != state; sp = &((*sp)->efd_next))
2861767006bSBryan Cantrill VERIFY(*sp != NULL);
2871767006bSBryan Cantrill
2881767006bSBryan Cantrill *sp = (*sp)->efd_next;
2891767006bSBryan Cantrill
2901767006bSBryan Cantrill ddi_soft_state_free(eventfd_softstate, minor);
2911767006bSBryan Cantrill vmem_free(eventfd_minor, (void *)(uintptr_t)minor, 1);
2921767006bSBryan Cantrill
2931767006bSBryan Cantrill mutex_exit(&eventfd_lock);
2941767006bSBryan Cantrill
2951767006bSBryan Cantrill return (0);
2961767006bSBryan Cantrill }
2971767006bSBryan Cantrill
2981767006bSBryan Cantrill static int
eventfd_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)2991767006bSBryan Cantrill eventfd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
3001767006bSBryan Cantrill {
3011767006bSBryan Cantrill switch (cmd) {
3021767006bSBryan Cantrill case DDI_ATTACH:
3031767006bSBryan Cantrill break;
3041767006bSBryan Cantrill
3051767006bSBryan Cantrill case DDI_RESUME:
3061767006bSBryan Cantrill return (DDI_SUCCESS);
3071767006bSBryan Cantrill
3081767006bSBryan Cantrill default:
3091767006bSBryan Cantrill return (DDI_FAILURE);
3101767006bSBryan Cantrill }
3111767006bSBryan Cantrill
3121767006bSBryan Cantrill mutex_enter(&eventfd_lock);
3131767006bSBryan Cantrill
3141767006bSBryan Cantrill if (ddi_soft_state_init(&eventfd_softstate,
3151767006bSBryan Cantrill sizeof (eventfd_state_t), 0) != 0) {
3161767006bSBryan Cantrill cmn_err(CE_NOTE, "/dev/eventfd failed to create soft state");
3171767006bSBryan Cantrill mutex_exit(&eventfd_lock);
3181767006bSBryan Cantrill return (DDI_FAILURE);
3191767006bSBryan Cantrill }
3201767006bSBryan Cantrill
3211767006bSBryan Cantrill if (ddi_create_minor_node(devi, "eventfd", S_IFCHR,
322*3deeb0a9SToomas Soome EVENTFDMNRN_EVENTFD, DDI_PSEUDO, 0) == DDI_FAILURE) {
3231767006bSBryan Cantrill cmn_err(CE_NOTE, "/dev/eventfd couldn't create minor node");
3241767006bSBryan Cantrill ddi_soft_state_fini(&eventfd_softstate);
3251767006bSBryan Cantrill mutex_exit(&eventfd_lock);
3261767006bSBryan Cantrill return (DDI_FAILURE);
3271767006bSBryan Cantrill }
3281767006bSBryan Cantrill
3291767006bSBryan Cantrill ddi_report_dev(devi);
3301767006bSBryan Cantrill eventfd_devi = devi;
3311767006bSBryan Cantrill
3321767006bSBryan Cantrill eventfd_minor = vmem_create("eventfd_minor", (void *)EVENTFDMNRN_CLONE,
3331767006bSBryan Cantrill UINT32_MAX - EVENTFDMNRN_CLONE, 1, NULL, NULL, NULL, 0,
3341767006bSBryan Cantrill VM_SLEEP | VMC_IDENTIFIER);
3351767006bSBryan Cantrill
3361767006bSBryan Cantrill mutex_exit(&eventfd_lock);
3371767006bSBryan Cantrill
3381767006bSBryan Cantrill return (DDI_SUCCESS);
3391767006bSBryan Cantrill }
3401767006bSBryan Cantrill
3411767006bSBryan Cantrill /*ARGSUSED*/
3421767006bSBryan Cantrill static int
eventfd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3431767006bSBryan Cantrill eventfd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3441767006bSBryan Cantrill {
3451767006bSBryan Cantrill switch (cmd) {
3461767006bSBryan Cantrill case DDI_DETACH:
3471767006bSBryan Cantrill break;
3481767006bSBryan Cantrill
3491767006bSBryan Cantrill case DDI_SUSPEND:
3501767006bSBryan Cantrill return (DDI_SUCCESS);
3511767006bSBryan Cantrill
3521767006bSBryan Cantrill default:
3531767006bSBryan Cantrill return (DDI_FAILURE);
3541767006bSBryan Cantrill }
3551767006bSBryan Cantrill
3561767006bSBryan Cantrill mutex_enter(&eventfd_lock);
3571767006bSBryan Cantrill vmem_destroy(eventfd_minor);
3581767006bSBryan Cantrill
3591767006bSBryan Cantrill ddi_remove_minor_node(eventfd_devi, NULL);
3601767006bSBryan Cantrill eventfd_devi = NULL;
3611767006bSBryan Cantrill
3621767006bSBryan Cantrill ddi_soft_state_fini(&eventfd_softstate);
3631767006bSBryan Cantrill mutex_exit(&eventfd_lock);
3641767006bSBryan Cantrill
3651767006bSBryan Cantrill return (DDI_SUCCESS);
3661767006bSBryan Cantrill }
3671767006bSBryan Cantrill
3681767006bSBryan Cantrill /*ARGSUSED*/
3691767006bSBryan Cantrill static int
eventfd_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)3701767006bSBryan Cantrill eventfd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3711767006bSBryan Cantrill {
3721767006bSBryan Cantrill int error;
3731767006bSBryan Cantrill
3741767006bSBryan Cantrill switch (infocmd) {
3751767006bSBryan Cantrill case DDI_INFO_DEVT2DEVINFO:
3761767006bSBryan Cantrill *result = (void *)eventfd_devi;
3771767006bSBryan Cantrill error = DDI_SUCCESS;
3781767006bSBryan Cantrill break;
3791767006bSBryan Cantrill case DDI_INFO_DEVT2INSTANCE:
3801767006bSBryan Cantrill *result = (void *)0;
3811767006bSBryan Cantrill error = DDI_SUCCESS;
3821767006bSBryan Cantrill break;
3831767006bSBryan Cantrill default:
3841767006bSBryan Cantrill error = DDI_FAILURE;
3851767006bSBryan Cantrill }
3861767006bSBryan Cantrill return (error);
3871767006bSBryan Cantrill }
3881767006bSBryan Cantrill
3891767006bSBryan Cantrill static struct cb_ops eventfd_cb_ops = {
3901767006bSBryan Cantrill eventfd_open, /* open */
3911767006bSBryan Cantrill eventfd_close, /* close */
3921767006bSBryan Cantrill nulldev, /* strategy */
3931767006bSBryan Cantrill nulldev, /* print */
3941767006bSBryan Cantrill nodev, /* dump */
3951767006bSBryan Cantrill eventfd_read, /* read */
3961767006bSBryan Cantrill eventfd_write, /* write */
3971767006bSBryan Cantrill eventfd_ioctl, /* ioctl */
3981767006bSBryan Cantrill nodev, /* devmap */
3991767006bSBryan Cantrill nodev, /* mmap */
4001767006bSBryan Cantrill nodev, /* segmap */
4011767006bSBryan Cantrill eventfd_poll, /* poll */
4021767006bSBryan Cantrill ddi_prop_op, /* cb_prop_op */
4031767006bSBryan Cantrill 0, /* streamtab */
4041767006bSBryan Cantrill D_NEW | D_MP /* Driver compatibility flag */
4051767006bSBryan Cantrill };
4061767006bSBryan Cantrill
4071767006bSBryan Cantrill static struct dev_ops eventfd_ops = {
4081767006bSBryan Cantrill DEVO_REV, /* devo_rev */
4091767006bSBryan Cantrill 0, /* refcnt */
4101767006bSBryan Cantrill eventfd_info, /* get_dev_info */
4111767006bSBryan Cantrill nulldev, /* identify */
4121767006bSBryan Cantrill nulldev, /* probe */
4131767006bSBryan Cantrill eventfd_attach, /* attach */
4141767006bSBryan Cantrill eventfd_detach, /* detach */
4151767006bSBryan Cantrill nodev, /* reset */
4161767006bSBryan Cantrill &eventfd_cb_ops, /* driver operations */
4171767006bSBryan Cantrill NULL, /* bus operations */
4181767006bSBryan Cantrill nodev, /* dev power */
4191767006bSBryan Cantrill ddi_quiesce_not_needed, /* quiesce */
4201767006bSBryan Cantrill };
4211767006bSBryan Cantrill
4221767006bSBryan Cantrill static struct modldrv modldrv = {
4231767006bSBryan Cantrill &mod_driverops, /* module type (this is a pseudo driver) */
4241767006bSBryan Cantrill "eventfd support", /* name of module */
4251767006bSBryan Cantrill &eventfd_ops, /* driver ops */
4261767006bSBryan Cantrill };
4271767006bSBryan Cantrill
4281767006bSBryan Cantrill static struct modlinkage modlinkage = {
4291767006bSBryan Cantrill MODREV_1,
4301767006bSBryan Cantrill (void *)&modldrv,
4311767006bSBryan Cantrill NULL
4321767006bSBryan Cantrill };
4331767006bSBryan Cantrill
4341767006bSBryan Cantrill int
_init(void)4351767006bSBryan Cantrill _init(void)
4361767006bSBryan Cantrill {
4371767006bSBryan Cantrill return (mod_install(&modlinkage));
4381767006bSBryan Cantrill }
4391767006bSBryan Cantrill
4401767006bSBryan Cantrill int
_info(struct modinfo * modinfop)4411767006bSBryan Cantrill _info(struct modinfo *modinfop)
4421767006bSBryan Cantrill {
4431767006bSBryan Cantrill return (mod_info(&modlinkage, modinfop));
4441767006bSBryan Cantrill }
4451767006bSBryan Cantrill
4461767006bSBryan Cantrill int
_fini(void)4471767006bSBryan Cantrill _fini(void)
4481767006bSBryan Cantrill {
4491767006bSBryan Cantrill return (mod_remove(&modlinkage));
4501767006bSBryan Cantrill }
451