Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Feb 2014 08:57:38 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r262550 - head/sys/dev/usb
Message-ID:  <201402270857.s1R8vcif037031@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Thu Feb 27 08:57:37 2014
New Revision: 262550
URL: http://svnweb.freebsd.org/changeset/base/262550

Log:
  Add support for kqfilter to USB character devices.
  
  Submitted by:	Kohji Okuno <okuno.kohji@jp.panasonic.com>
  MFC after:	2 weeks

Modified:
  head/sys/dev/usb/usb_dev.c

Modified: head/sys/dev/usb/usb_dev.c
==============================================================================
--- head/sys/dev/usb/usb_dev.c	Thu Feb 27 08:21:28 2014	(r262549)
+++ head/sys/dev/usb/usb_dev.c	Thu Feb 27 08:57:37 2014	(r262550)
@@ -124,6 +124,7 @@ static d_ioctl_t usb_ioctl;
 static d_read_t usb_read;
 static d_write_t usb_write;
 static d_poll_t usb_poll;
+static d_kqfilter_t usb_kqfilter;
 
 static d_ioctl_t usb_static_ioctl;
 
@@ -141,7 +142,8 @@ struct cdevsw usb_devsw = {
 	.d_flags = D_TRACKCLOSE,
 	.d_read = usb_read,
 	.d_write = usb_write,
-	.d_poll = usb_poll
+	.d_poll = usb_poll,
+	.d_kqfilter = usb_kqfilter,
 };
 
 static struct cdev* usb_dev = NULL;
@@ -509,6 +511,7 @@ usb_fifo_create(struct usb_cdev_privdata
 		f->fifo_index = n + USB_FIFO_TX;
 		f->dev_ep_index = e;
 		f->priv_mtx = &udev->device_mtx;
+		knlist_init_mtx(&f->selinfo.si_note, f->priv_mtx);
 		f->priv_sc0 = ep;
 		f->methods = &usb_ugen_methods;
 		f->iface_index = ep->iface_index;
@@ -536,6 +539,7 @@ usb_fifo_create(struct usb_cdev_privdata
 		f->fifo_index = n + USB_FIFO_RX;
 		f->dev_ep_index = e;
 		f->priv_mtx = &udev->device_mtx;
+		knlist_init_mtx(&f->selinfo.si_note, f->priv_mtx);
 		f->priv_sc0 = ep;
 		f->methods = &usb_ugen_methods;
 		f->iface_index = ep->iface_index;
@@ -774,7 +778,12 @@ usb_fifo_close(struct usb_fifo *f, int f
 	mtx_lock(f->priv_mtx);
 
 	/* clear current cdev private data pointer */
+	mtx_lock(&usb_ref_lock);
 	f->curr_cpd = NULL;
+	mtx_unlock(&usb_ref_lock);
+
+	/* check if we are watched by kevent */
+	KNOTE_LOCKED(&f->selinfo.si_note, 0);
 
 	/* check if we are selected */
 	if (f->flag_isselect) {
@@ -1117,6 +1126,162 @@ done:
 	return (err);
 }
 
+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;
+
+	DPRINTFN(2, "\n");
+
+	f = kn->kn_hook;
+
+	mtx_assert(f->priv_mtx, MA_OWNED);
+
+	cpd = f->curr_cpd;
+	if (cpd == NULL) {
+		m = (void *)1;
+	} else if (f->fs_ep_max == 0) {
+		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;
+		}
+	}
+	return (m ? 1 : 0);
+}
+
+static int
+usb_filter_read(struct knote *kn, long hint)
+{
+	struct usb_cdev_privdata* cpd;
+	struct usb_fifo *f;
+	struct usb_mbuf *m;
+
+	DPRINTFN(2, "\n");
+
+	f = kn->kn_hook;
+
+	mtx_assert(f->priv_mtx, MA_OWNED);
+
+	cpd = f->curr_cpd;
+	if (cpd == NULL) {
+		m = (void *)1;
+	} else if (f->fs_ep_max == 0) {
+		if (f->flag_iserror) {
+			/* we have an 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);
+
+			/* start reading data, if any */
+			if (m == NULL)
+				(f->methods->f_start_read) (f);
+		}
+	} else {
+		if (f->flag_iscomplete) {
+			m = (void *)1;
+		} else {
+			m = NULL;
+		}
+	}
+	return (m ? 1 : 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;
+
+	DPRINTFN(2, "\n");
+
+	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);
+		mtx_unlock(f->priv_mtx);
+	}
+
+	usb_unref_device(cpd, &refs);
+	return (err);
+}
+
 /* ARGSUSED */
 static int
 usb_poll(struct cdev* dev, int events, struct thread* td)
@@ -1184,7 +1349,7 @@ usb_poll(struct cdev* dev, int events, s
 
 		if (!refs.is_usbfs) {
 			if (f->flag_iserror) {
-				/* we have and error */
+				/* we have an error */
 				m = (void *)1;
 			} else {
 				if (f->queue_data == NULL) {
@@ -1581,6 +1746,8 @@ usb_fifo_wakeup(struct usb_fifo *f)
 {
 	usb_fifo_signal(f);
 
+	KNOTE_LOCKED(&f->selinfo.si_note, 0);
+
 	if (f->flag_isselect) {
 		selwakeup(&f->selinfo);
 		f->flag_isselect = 0;
@@ -1709,6 +1876,7 @@ usb_fifo_attach(struct usb_device *udev,
 	f_tx->fifo_index = n + USB_FIFO_TX;
 	f_tx->dev_ep_index = -1;
 	f_tx->priv_mtx = priv_mtx;
+	knlist_init_mtx(&f_tx->selinfo.si_note, priv_mtx);
 	f_tx->priv_sc0 = priv_sc;
 	f_tx->methods = pm;
 	f_tx->iface_index = iface_index;
@@ -1717,6 +1885,7 @@ usb_fifo_attach(struct usb_device *udev,
 	f_rx->fifo_index = n + USB_FIFO_RX;
 	f_rx->dev_ep_index = -1;
 	f_rx->priv_mtx = priv_mtx;
+	knlist_init_mtx(&f_rx->selinfo.si_note, priv_mtx);
 	f_rx->priv_sc0 = priv_sc;
 	f_rx->methods = pm;
 	f_rx->iface_index = iface_index;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402270857.s1R8vcif037031>