From owner-svn-src-stable-9@FreeBSD.ORG Fri Mar 14 09:13:54 2014 Return-Path: Delivered-To: svn-src-stable-9@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 5F3CFB6B; Fri, 14 Mar 2014 09:13:54 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 3FB15B55; Fri, 14 Mar 2014 09:13:54 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s2E9Dsff094228; Fri, 14 Mar 2014 09:13:54 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s2E9Dsof094227; Fri, 14 Mar 2014 09:13:54 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201403140913.s2E9Dsof094227@svn.freebsd.org> From: Hans Petter Selasky Date: Fri, 14 Mar 2014 09:13:54 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r263163 - stable/9/sys/dev/usb X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-9@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for only the 9-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Mar 2014 09:13:54 -0000 Author: hselasky Date: Fri Mar 14 09:13:53 2014 New Revision: 263163 URL: http://svnweb.freebsd.org/changeset/base/263163 Log: MFC r262550, r262551 and r262554: Add support for kqfilter to USB character devices. Modified: stable/9/sys/dev/usb/usb_dev.c Directory Properties: stable/9/sys/ (props changed) stable/9/sys/dev/ (props changed) Modified: stable/9/sys/dev/usb/usb_dev.c ============================================================================== --- stable/9/sys/dev/usb/usb_dev.c Fri Mar 14 09:11:09 2014 (r263162) +++ stable/9/sys/dev/usb/usb_dev.c Fri Mar 14 09:13:53 2014 (r263163) @@ -105,7 +105,7 @@ static void usb_dev_uninit(void *); static int usb_fifo_uiomove(struct usb_fifo *, void *, int, struct uio *); static void usb_fifo_check_methods(struct usb_fifo_methods *); -static struct usb_fifo *usb_fifo_alloc(void); +static struct usb_fifo *usb_fifo_alloc(struct mtx *); static struct usb_endpoint *usb_dev_get_ep(struct usb_device *, uint8_t, uint8_t); static void usb_loc_fill(struct usb_fs_privdata *, @@ -120,6 +120,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; @@ -137,7 +138,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; @@ -364,15 +366,17 @@ usb_unref_device(struct usb_cdev_privdat } static struct usb_fifo * -usb_fifo_alloc(void) +usb_fifo_alloc(struct mtx *mtx) { struct usb_fifo *f; f = malloc(sizeof(*f), M_USBDEV, M_WAITOK | M_ZERO); - if (f) { + if (f != NULL) { cv_init(&f->cv_io, "FIFO-IO"); cv_init(&f->cv_drain, "FIFO-DRAIN"); + f->priv_mtx = mtx; f->refcount = 1; + knlist_init_mtx(&f->selinfo.si_note, mtx); } return (f); } @@ -496,7 +500,7 @@ usb_fifo_create(struct usb_cdev_privdata DPRINTFN(5, "dev_get_endpoint returned NULL\n"); return (EINVAL); } - f = usb_fifo_alloc(); + f = usb_fifo_alloc(&udev->device_mtx); if (f == NULL) { DPRINTFN(5, "could not alloc tx fifo\n"); return (ENOMEM); @@ -504,7 +508,6 @@ usb_fifo_create(struct usb_cdev_privdata /* update some fields */ f->fifo_index = n + USB_FIFO_TX; f->dev_ep_index = e; - f->priv_mtx = &udev->device_mtx; f->priv_sc0 = ep; f->methods = &usb_ugen_methods; f->iface_index = ep->iface_index; @@ -523,7 +526,7 @@ usb_fifo_create(struct usb_cdev_privdata DPRINTFN(5, "dev_get_endpoint returned NULL\n"); return (EINVAL); } - f = usb_fifo_alloc(); + f = usb_fifo_alloc(&udev->device_mtx); if (f == NULL) { DPRINTFN(5, "could not alloc rx fifo\n"); return (ENOMEM); @@ -531,7 +534,6 @@ usb_fifo_create(struct usb_cdev_privdata /* update some fields */ f->fifo_index = n + USB_FIFO_RX; f->dev_ep_index = e; - f->priv_mtx = &udev->device_mtx; f->priv_sc0 = ep; f->methods = &usb_ugen_methods; f->iface_index = ep->iface_index; @@ -616,6 +618,10 @@ usb_fifo_free(struct usb_fifo *f) cv_destroy(&f->cv_io); cv_destroy(&f->cv_drain); + knlist_clear(&f->selinfo.si_note, 0); + seldrain(&f->selinfo); + knlist_destroy(&f->selinfo.si_note); + free(f, M_USBDEV); } @@ -770,7 +776,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) { @@ -1113,6 +1124,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) @@ -1180,7 +1347,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) { @@ -1577,6 +1744,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; @@ -1692,8 +1861,8 @@ usb_fifo_attach(struct usb_device *udev, break; } - f_tx = usb_fifo_alloc(); - f_rx = usb_fifo_alloc(); + f_tx = usb_fifo_alloc(priv_mtx); + f_rx = usb_fifo_alloc(priv_mtx); if ((f_tx == NULL) || (f_rx == NULL)) { usb_fifo_free(f_tx); @@ -1704,7 +1873,6 @@ 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; f_tx->priv_sc0 = priv_sc; f_tx->methods = pm; f_tx->iface_index = iface_index; @@ -1712,7 +1880,6 @@ 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; f_rx->priv_sc0 = priv_sc; f_rx->methods = pm; f_rx->iface_index = iface_index;