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>