Index: sys/dev/drm2/drmP.h =================================================================== --- sys/dev/drm2/drmP.h +++ sys/dev/drm2/drmP.h @@ -418,6 +418,9 @@ int event_space; struct drm_prime_file_private prime; + + struct selinfo kevent_selinfo; + struct mtx kevent_mtx; }; /** @@ -1195,6 +1198,7 @@ int drm_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size, struct vm_object **obj_res, int nprot); d_poll_t drm_poll; +int drm_kqfilter(struct cdev *kdev, struct knote *kn); /* Memory management support (drm_memory.h) */ extern void drm_free_agp(DRM_AGP_MEM * handle, int pages); Index: sys/dev/drm2/drm_fops.c =================================================================== --- sys/dev/drm2/drm_fops.c +++ sys/dev/drm2/drm_fops.c @@ -207,6 +207,9 @@ INIT_LIST_HEAD(&priv->event_list); priv->event_space = 4096; /* set aside 4k for event buffer */ + mtx_init(&priv->kevent_mtx, "drm kevent lock", NULL, MTX_DEF); + knlist_init_mtx(&priv->kevent_selinfo.si_note, &priv->kevent_mtx); + if (dev->driver->driver_features & DRIVER_GEM) drm_gem_open(dev, priv); @@ -552,6 +555,10 @@ wakeup(&file_priv->event_space); selwakeup(&file_priv->event_poll); + + mtx_lock(&file_priv->kevent_mtx); + KNOTE_LOCKED(&file_priv->kevent_selinfo.si_note, 1); + mtx_unlock(&file_priv->kevent_mtx); } int @@ -601,3 +608,69 @@ return (ENODEV); } } + +static void +drm_kqfilter_detach(struct knote *kn) +{ + struct drm_file *file_priv = kn->kn_hook; + knlist_remove(&file_priv->kevent_selinfo.si_note, kn, 0); +} + +static int +drm_kqfilter_read(struct knote *kn, long hint) +{ + struct drm_file *file_priv = kn->kn_hook; + struct drm_device *dev = file_priv->minor->dev; + struct drm_pending_event *e = NULL; + struct drm_pending_event *et = NULL; + ssize_t ret = 0; + mtx_lock(&dev->event_lock); + list_for_each_entry_safe(e, et, &file_priv->event_list, link) { + ret += e->event->length; + } + mtx_unlock(&dev->event_lock); + kn->kn_data = ret; + return (ret > 0); +} + +static struct filterops drm_kqfiltops_read = { + .f_isfd = 1, + .f_detach = drm_kqfilter_detach, + .f_event = drm_kqfilter_read, +}; + +int +drm_kqfilter(struct cdev *kdev, struct knote *kn) +{ + struct drm_file *file_priv; + struct drm_device *dev; + int error; + + error = devfs_get_cdevpriv((void **)&file_priv); + if (error != 0) { + DRM_ERROR("can't find authenticator\n"); + return (EINVAL); + } + + dev = drm_get_device_from_kdev(kdev); + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &drm_kqfiltops_read; + error = 0; + break; + default: + error = EOPNOTSUPP; + break; + } + + if (error == 0) { + mtx_lock(&file_priv->kevent_mtx); + kn->kn_hook = file_priv; + knlist_add(&file_priv->kevent_selinfo.si_note, kn, 1); + mtx_unlock(&file_priv->kevent_mtx); + } + + return (error); +} +EXPORT_SYMBOL(drm_kqfilter); Index: sys/dev/drm2/drm_stub.c =================================================================== --- sys/dev/drm2/drm_stub.c +++ sys/dev/drm2/drm_stub.c @@ -80,7 +80,8 @@ .d_poll = drm_poll, .d_mmap_single = drm_mmap_single, .d_name = "drm", - .d_flags = D_TRACKCLOSE + .d_flags = D_TRACKCLOSE, + .d_kqfilter = drm_kqfilter, }; static int drm_minor_get_id(struct drm_device *dev, int type)