dev - Add kq support to usbmisc devices
authorSamuel J. Greear <sjg@thesjg.com>
Wed, 7 Jul 2010 15:46:01 +0000 (15:46 +0000)
committerSamuel J. Greear <sjg@thesjg.com>
Wed, 7 Jul 2010 15:46:01 +0000 (15:46 +0000)
* ugen, uhid, ums and uscanner

sys/dev/usbmisc/ugen/ugen.c
sys/dev/usbmisc/uhid/uhid.c
sys/dev/usbmisc/ums/ums.c
sys/dev/usbmisc/uscanner/uscanner.c

index 8588c92..fcce4b0 100644 (file)
@@ -64,6 +64,7 @@
 #include <sys/select.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -140,17 +141,23 @@ d_read_t  ugenread;
 d_write_t ugenwrite;
 d_ioctl_t ugenioctl;
 d_poll_t  ugenpoll;
+d_kqfilter_t ugenkqfilter;
+
+static void ugen_filt_detach(struct knote *);
+static int ugen_filt_read(struct knote *, long);
+static int ugen_filt_write(struct knote *, long);
 
 #define UGEN_CDEV_MAJOR        114
 
 static struct dev_ops ugen_ops = {
-       { "ugen", UGEN_CDEV_MAJOR, 0 },
+       { "ugen", UGEN_CDEV_MAJOR, D_KQFILTER },
        .d_open =       ugenopen,
        .d_close =      ugenclose,
        .d_read =       ugenread,
        .d_write =      ugenwrite,
        .d_ioctl =      ugenioctl,
        .d_poll =       ugenpoll,
+       .d_kqfilter =   ugenkqfilter
 };
 
 static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
@@ -1501,5 +1508,147 @@ ugenpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops ugen_filtops_read =
+       { 1, NULL, ugen_filt_detach, ugen_filt_read };
+static struct filterops ugen_filtops_write =
+       { 1, NULL, ugen_filt_detach, ugen_filt_write };
+
+int
+ugenkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct klist *klist;
+        struct ugen_softc *sc;
+        struct ugen_endpoint *sce;
+
+        sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+
+       ap->a_result = 1;
+
+       if (sc->sc_dying)
+               return (0);
+
+        /* Do not allow filter on a control endpoint */
+        if (UGENENDPOINT(dev) == USB_CONTROL_ENDPOINT)
+               return (0);
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+               kn->kn_fop = &ugen_filtops_read;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       case EVFILT_WRITE:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+               kn->kn_fop = &ugen_filtops_write;
+               kn->kn_hook = (caddr_t)dev;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       if (sce->edesc != NULL || sce->pipeh != NULL) {
+               crit_enter();
+               klist = &sce->rsel.si_note;
+               SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+               crit_exit();
+       }
+
+       return (0);
+}
+
+static void
+ugen_filt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+        struct ugen_softc *sc;
+        struct ugen_endpoint *sce;
+       struct klist *klist;
+
+        sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+               break;
+       case EVFILT_WRITE:
+               sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+               break;
+       default:
+               return;
+       }
+
+       if (sce->edesc != NULL || sce->pipeh != NULL) {
+               crit_enter();
+               klist = &sce->rsel.si_note;
+               SLIST_REMOVE(klist, kn, knote, kn_selnext);
+               crit_exit();
+       }
+}
+
+static int
+ugen_filt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct ugen_softc *sc;
+       struct ugen_endpoint *sce;
+       int ready = 0;
+
+       sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+       sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
+
+       switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+       case UE_INTERRUPT:
+               if (sce->q.c_cc > 0)
+                       ready = 1;
+               break;
+       case UE_ISOCHRONOUS:
+               if (sce->cur != sce->fill)
+                       ready = 1;
+               break;
+       case UE_BULK:
+               ready = 1;
+               break;
+       default:
+               break;
+       }
+
+       return (ready);
+}
+
+static int
+ugen_filt_write(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct ugen_softc *sc;
+       struct ugen_endpoint *sce;
+       int ready = 0;
+
+       sc = devclass_get_softc(ugen_devclass, UGENUNIT(dev));
+       sce = &sc->sc_endpoints[UGENENDPOINT(dev)][OUT];
+
+       switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
+       case UE_INTERRUPT:
+               if (sce->q.c_cc > 0)
+                       ready = 1;
+               break;
+       case UE_ISOCHRONOUS:
+               if (sce->cur != sce->fill)
+                       ready = 1;
+               break;
+       case UE_BULK:
+               ready = 1;
+               break;
+       default:
+               break;
+       }
+
+       return (ready);
+}
+
 DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
 
index 8818eac..f69d443 100644 (file)
@@ -64,6 +64,7 @@
 #include <sys/proc.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -132,17 +133,23 @@ d_read_t  uhidread;
 d_write_t      uhidwrite;
 d_ioctl_t      uhidioctl;
 d_poll_t       uhidpoll;
+d_kqfilter_t   uhidkqfilter;
+
+static void uhidfilt_detach(struct knote *);
+static int uhidfilt_read(struct knote *, long);
+static int uhidfilt_write(struct knote *, long);
 
 #define                UHID_CDEV_MAJOR 122
 
 static struct dev_ops uhid_ops = {
-       { "uhid", UHID_CDEV_MAJOR, 0 },
+       { "uhid", UHID_CDEV_MAJOR, D_KQFILTER },
        .d_open =       uhidopen,
        .d_close =      uhidclose,
        .d_read =       uhidread,
        .d_write =      uhidwrite,
        .d_ioctl =      uhidioctl,
        .d_poll =       uhidpoll,
+       .d_kqfilter =   uhidkqfilter
 };
 
 static void uhid_intr(usbd_xfer_handle, usbd_private_handle,
@@ -691,5 +698,87 @@ uhidpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops uhidfiltops_read =
+       { 1, NULL, uhidfilt_detach, uhidfilt_read };
+static struct filterops uhidfiltops_write =
+       { 1, NULL, uhidfilt_detach, uhidfilt_write };
+
+int
+uhidkqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct uhid_softc *sc;
+       struct klist *klist;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       if (sc->sc_dying) {
+               ap->a_result = 1;
+               return (0);
+       }
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &uhidfiltops_read;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       case EVFILT_WRITE:
+               kn->kn_fop = &uhidfiltops_write;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+uhidfilt_detach(struct knote *kn)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct uhid_softc *sc;
+       struct klist *klist;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       crit_enter();
+       klist = &sc->sc_rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+uhidfilt_read(struct knote *kn, long hint)
+{
+       cdev_t dev = (cdev_t)kn->kn_hook;
+       struct uhid_softc *sc;
+       int ready = 0;
+
+       sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
+
+       crit_enter();
+       if (sc->sc_q.c_cc > 0)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
+static int
+uhidfilt_write(struct knote *kn, long hint)
+{
+       return (1);
+}
+
 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
 
index 01bd6f4..dae6af5 100644 (file)
@@ -56,6 +56,7 @@
 #include <sys/select.h>
 #include <sys/vnode.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
 
@@ -141,16 +142,21 @@ static d_close_t ums_close;
 static d_read_t  ums_read;
 static d_ioctl_t ums_ioctl;
 static d_poll_t  ums_poll;
+static d_kqfilter_t ums_kqfilter;
+
+static void ums_filt_detach(struct knote *);
+static int ums_filt(struct knote *, long);
 
 #define UMS_CDEV_MAJOR 111
 
 static struct dev_ops ums_ops = {
-       { "ums", UMS_CDEV_MAJOR, 0 },
+       { "ums", UMS_CDEV_MAJOR, D_KQFILTER },
        .d_open =       ums_open,
        .d_close =      ums_close,
        .d_read =       ums_read,
        .d_ioctl =      ums_ioctl,
        .d_poll =       ums_poll,
+       .d_kqfilter =   ums_kqfilter
 };
 
 static device_probe_t ums_match;
@@ -697,6 +703,64 @@ ums_poll(struct dev_poll_args *ap)
        return (0);
 }
 
+static struct filterops ums_filtops =
+       { 1, NULL, ums_filt_detach, ums_filt };
+
+static int
+ums_kqfilter(struct dev_kqfilter_args *ap)
+{
+       cdev_t dev = ap->a_head.a_dev;
+       struct knote *kn = ap->a_kn;
+       struct ums_softc *sc;
+       struct klist *klist;
+
+       ap->a_result = 0;
+
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
+               kn->kn_fop = &ums_filtops;
+               kn->kn_hook = (caddr_t)sc;
+               break;
+       default:
+               ap->a_result = 1;
+               return (0);
+       }
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+       crit_exit();
+
+       return (0);
+}
+
+static void
+ums_filt_detach(struct knote *kn)
+{
+       struct ums_softc *sc = (struct ums_softc *)kn->kn_hook;
+       struct klist *klist;
+
+       crit_enter();
+       klist = &sc->rsel.si_note;
+       SLIST_REMOVE(klist, kn, knote, kn_selnext);
+       crit_exit();
+}
+
+static int
+ums_filt(struct knote *kn, long hint)
+{
+       struct ums_softc *sc = (struct ums_softc *)kn->kn_hook;
+       int ready = 0;
+
+       crit_enter();
+       if (sc->qcount)
+               ready = 1;
+       crit_exit();
+
+       return (ready);
+}
+
 int
 ums_ioctl(struct dev_ioctl_args *ap)
 {
index 9175a14..f5179ba 100644 (file)
@@ -61,6 +61,7 @@
 #include <sys/select.h>
 #include <sys/proc.h>
 #include <sys/poll.h>
+#include <sys/event.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
@@ -255,16 +256,18 @@ d_close_t uscannerclose;
 d_read_t  uscannerread;
 d_write_t uscannerwrite;
 d_poll_t  uscannerpoll;
+d_kqfilter_t uscannerkqfilter;
 
 #define USCANNER_CDEV_MAJOR    156
 
 static struct dev_ops uscanner_ops = {
-       { "uscanner", USCANNER_CDEV_MAJOR, 0 },
+       { "uscanner", USCANNER_CDEV_MAJOR, D_KQFILTER },
        .d_open =       uscanneropen,
        .d_close =      uscannerclose,
        .d_read =       uscannerread,
        .d_write =      uscannerwrite,
        .d_poll =       uscannerpoll,
+       .d_kqfilter =   uscannerkqfilter
 };
 
 static int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
@@ -669,5 +672,38 @@ uscannerpoll(struct dev_poll_args *ap)
        return (0);
 }
 
+static void
+uscannerfilt_detach(struct knote *kn) {}
+
+static int
+uscannerfilt(struct knote *kn, long hint)
+{
+       /*
+        * We have no easy way of determining if a read will
+        * yield any data or a write will happen.
+        * Pretend they will.
+        */
+       return (1);
+}
+
+static struct filterops uscannerfiltops =
+       { 1, NULL, uscannerfilt_detach, uscannerfilt };
+
+int
+uscannerkqfilter(struct dev_kqfilter_args *ap)
+{
+/* XXX
+       cdev_t dev = ap->a_head.a_dev;
+       struct uscanner_softc *sc = devclass_get_softc(uscanner_devclass, USCANNERUNIT(dev));
+
+       if (sc->sc_dying)
+               return (EIO);
+*/
+
+       ap->a_result = 0;
+       ap->a_kn->kn_fop = &uscannerfiltops;
+       return (0);
+}
+
 DRIVER_MODULE(uscanner, uhub, uscanner_driver, uscanner_devclass, usbd_driver_load, 0);