Skip site navigation (1)Skip section navigation (2)
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>