Date: Thu, 27 Feb 2014 14:26:15 +0900 (JST) From: Kohji Okuno <okuno.kohji@jp.panasonic.com> To: freebsd-current@FreeBSD.org Cc: okuno.kohji@jp.panasonic.com Subject: kqueue for usb_dev Message-ID: <20140227.142615.924807465819500067.okuno.kohji@jp.panasonic.com>
next in thread | raw e-mail | index | archive | help
----Next_Part(Thu_Feb_27_14_26_15_2014_503)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi,
I tried add kqueue I/F to usb_dev.c. I attached my patch.
What do you think about my patch?
Best regards,
Kohji Okuno
----Next_Part(Thu_Feb_27_14_26_15_2014_503)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="usb_dev_kqueue.patch"
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c
index f086a3c..4334be7 100644
--- a/sys/dev/usb/usb_dev.c
+++ b/sys/dev/usb/usb_dev.c
@@ -120,6 +120,9 @@ static d_ioctl_t usb_ioctl;
static d_read_t usb_read;
static d_write_t usb_write;
static d_poll_t usb_poll;
+#if 1
+static d_kqfilter_t usb_kqfilter;
+#endif
static d_ioctl_t usb_static_ioctl;
@@ -138,6 +141,10 @@ struct cdevsw usb_devsw = {
.d_read = usb_read,
.d_write = usb_write,
.d_poll = usb_poll
+#if 1
+ ,
+ .d_kqfilter = usb_kqfilter
+#endif
};
static struct cdev* usb_dev = NULL;
@@ -505,6 +512,9 @@ usb_fifo_create(struct usb_cdev_privdata *cpd,
f->fifo_index = n + USB_FIFO_TX;
f->dev_ep_index = e;
f->priv_mtx = &udev->device_mtx;
+#if 1
+ knlist_init_mtx(&f->selinfo.si_note, f->priv_mtx);
+#endif
f->priv_sc0 = ep;
f->methods = &usb_ugen_methods;
f->iface_index = ep->iface_index;
@@ -532,6 +542,9 @@ usb_fifo_create(struct usb_cdev_privdata *cpd,
f->fifo_index = n + USB_FIFO_RX;
f->dev_ep_index = e;
f->priv_mtx = &udev->device_mtx;
+#if 1
+ knlist_init_mtx(&f->selinfo.si_note, f->priv_mtx);
+#endif
f->priv_sc0 = ep;
f->methods = &usb_ugen_methods;
f->iface_index = ep->iface_index;
@@ -712,6 +725,11 @@ usb_fifo_open(struct usb_cdev_privdata *cpd,
/* reset select flag */
f->flag_isselect = 0;
+#if 1
+ /* reset kevent flag */
+ f->flag_iskevent = 0;
+#endif
+
/* reset flushing flag */
f->flag_flushing = 0;
@@ -772,6 +790,13 @@ usb_fifo_close(struct usb_fifo *f, int fflags)
/* clear current cdev private data pointer */
f->curr_cpd = NULL;
+#if 1
+ /* check if we are watched by kevent */
+ if (f->flag_iskevent) {
+ KNOTE_LOCKED(&f->selinfo.si_note, 0);
+ f->flag_iskevent = 0;
+ }
+#endif
/* check if we are selected */
if (f->flag_isselect) {
selwakeup(&f->selinfo);
@@ -1113,6 +1138,179 @@ done:
return (err);
}
+#if 1
+static void
+usb_filter_detach(struct knote *kn)
+{
+ struct usb_fifo *f = kn->kn_hook;
+ knlist_remove(&f->selinfo.si_note, kn, 0);
+}
+
+static int
+usb_filter_write(struct knote *kn, long hint)
+{
+ struct usb_cdev_privdata* cpd;
+ struct usb_fifo *f;
+ struct usb_mbuf *m;
+ int is_usbfs = 0;
+
+ f = kn->kn_hook;
+ cpd = f->curr_cpd;
+ if (cpd == NULL) {
+ return (1);
+ }
+
+ if (f->fs_ep_max != 0) {
+ is_usbfs = 1;
+ }
+
+ if (!is_usbfs) {
+ if (f->flag_iserror) {
+ /* we got an error */
+ m = (void *)1;
+ } else {
+ if (f->queue_data == NULL) {
+ /*
+ * start write transfer, if not
+ * already started
+ */
+ (f->methods->f_start_write) (f);
+ }
+ /* check if any packets are available */
+ USB_IF_POLL(&f->free_q, m);
+ }
+ } else {
+ if (f->flag_iscomplete) {
+ m = (void *)1;
+ } else {
+ m = NULL;
+ }
+ }
+
+ if (m) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+static int
+usb_filter_read(struct knote *kn, long hint)
+{
+ struct usb_cdev_privdata* cpd;
+ struct usb_fifo *f;
+ struct usb_mbuf *m;
+ int is_usbfs = 0;
+
+ f = kn->kn_hook;
+ cpd = f->curr_cpd;
+ if (cpd == NULL) {
+ return (1);
+ }
+
+ if (f->fs_ep_max != 0) {
+ is_usbfs = 1;
+ }
+
+ if (!is_usbfs) {
+ if (f->flag_iserror) {
+ /* we have and error */
+ m = (void *)1;
+ } else {
+ if (f->queue_data == NULL) {
+ /*
+ * start read transfer, if not
+ * already started
+ */
+ (f->methods->f_start_read) (f);
+ }
+ /* check if any packets are available */
+ USB_IF_POLL(&f->used_q, m);
+ }
+ } else {
+ if (f->flag_iscomplete) {
+ m = (void *)1;
+ } else {
+ m = NULL;
+ }
+ }
+
+ if (m) {
+ return (1);
+ } else {
+ if (!is_usbfs) {
+ /* start reading data */
+ (f->methods->f_start_read) (f);
+ }
+ return (0);
+ }
+}
+
+static struct filterops usb_filtops_write =
+{
+ .f_isfd = 1,
+ .f_detach = usb_filter_detach,
+ .f_event = usb_filter_write,
+};
+
+static struct filterops usb_filtops_read =
+{
+ .f_isfd = 1,
+ .f_detach = usb_filter_detach,
+ .f_event = usb_filter_read,
+};
+
+
+/* ARGSUSED */
+static int
+usb_kqfilter(struct cdev* dev, struct knote *kn)
+{
+ struct usb_cdev_refdata refs;
+ struct usb_cdev_privdata* cpd;
+ struct usb_fifo *f;
+ int fflags;
+ int err = EINVAL;
+
+ if (devfs_get_cdevpriv((void **)&cpd) != 0 ||
+ usb_ref_device(cpd, &refs, 0) != 0)
+ return (ENXIO);
+
+ fflags = cpd->fflags;
+
+ /* Figure out who needs service */
+ switch (kn->kn_filter) {
+ case EVFILT_WRITE:
+ if (fflags & FWRITE) {
+ f = refs.txfifo;
+ kn->kn_fop = &usb_filtops_write;
+ err = 0;
+ }
+ break;
+ case EVFILT_READ:
+ if (fflags & FREAD) {
+ f = refs.rxfifo;
+ kn->kn_fop = &usb_filtops_read;
+ err = 0;
+ }
+ break;
+ default:
+ err = EOPNOTSUPP;
+ break;
+ }
+
+ if (err == 0) {
+ kn->kn_hook = f;
+ mtx_lock(f->priv_mtx);
+ knlist_add(&f->selinfo.si_note, kn, 1);
+ f->flag_iskevent = 1;
+ mtx_unlock(f->priv_mtx);
+ }
+
+ usb_unref_device(cpd, &refs);
+ return (err);
+}
+#endif
+
/* ARGSUSED */
static int
usb_poll(struct cdev* dev, int events, struct thread* td)
@@ -1577,6 +1775,12 @@ usb_fifo_wakeup(struct usb_fifo *f)
{
usb_fifo_signal(f);
+#if 1
+ if (f->flag_iskevent) {
+ KNOTE_LOCKED(&f->selinfo.si_note, 0);
+ /* f->flag_iskevent = 0 */
+ }
+#endif
if (f->flag_isselect) {
selwakeup(&f->selinfo);
f->flag_isselect = 0;
@@ -1705,6 +1909,9 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
f_tx->fifo_index = n + USB_FIFO_TX;
f_tx->dev_ep_index = -1;
f_tx->priv_mtx = priv_mtx;
+#if 1
+ knlist_init_mtx(&f_tx->selinfo.si_note, f_rx->priv_mtx);
+#endif
f_tx->priv_sc0 = priv_sc;
f_tx->methods = pm;
f_tx->iface_index = iface_index;
@@ -1713,6 +1920,9 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
f_rx->fifo_index = n + USB_FIFO_RX;
f_rx->dev_ep_index = -1;
f_rx->priv_mtx = priv_mtx;
+#if 1
+ knlist_init_mtx(&f_rx->selinfo.si_note, f_rx->priv_mtx);
+#endif
f_rx->priv_sc0 = priv_sc;
f_rx->methods = pm;
f_rx->iface_index = iface_index;
diff --git a/sys/dev/usb/usb_dev.h b/sys/dev/usb/usb_dev.h
index 9a7cf21..334c5f9 100644
--- a/sys/dev/usb/usb_dev.h
+++ b/sys/dev/usb/usb_dev.h
@@ -127,6 +127,9 @@ struct usb_fifo {
uint8_t flag_iscomplete; /* set if a USB transfer is complete */
uint8_t flag_iserror; /* set if FIFO error happened */
uint8_t flag_isselect; /* set if FIFO is selected */
+#if 1
+ uint8_t flag_iskevent; /* set if FIFO is watched by kevent */
+#endif
uint8_t flag_flushing; /* set if FIFO is flushing data */
uint8_t flag_short; /* set if short_ok or force_short
* transfer flags should be set */
----Next_Part(Thu_Feb_27_14_26_15_2014_503)----
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20140227.142615.924807465819500067.okuno.kohji>
