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