Module Name: src Committed By: mrg Date: Sat Mar 7 20:20:55 UTC 2015
Modified Files: src/sys/dev/usb: TODO.usbmp uatp.c ucycom.c uhid.c uhidev.c uhidev.h ukbd.c uyurex.c Log Message: properly protect uhid's sc_q member with sc_lock. should fix PR#49728. while here, remove D_MPSAFE from uhid* and all uhid users, as it really needs all the callers to be safe and they're not. XXX: pullup-7 To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/usb/TODO.usbmp cvs rdiff -u -r1.10 -r1.11 src/sys/dev/usb/uatp.c cvs rdiff -u -r1.41 -r1.42 src/sys/dev/usb/ucycom.c cvs rdiff -u -r1.92 -r1.93 src/sys/dev/usb/uhid.c cvs rdiff -u -r1.62 -r1.63 src/sys/dev/usb/uhidev.c cvs rdiff -u -r1.16 -r1.17 src/sys/dev/usb/uhidev.h cvs rdiff -u -r1.129 -r1.130 src/sys/dev/usb/ukbd.c cvs rdiff -u -r1.9 -r1.10 src/sys/dev/usb/uyurex.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/TODO.usbmp diff -u src/sys/dev/usb/TODO.usbmp:1.8 src/sys/dev/usb/TODO.usbmp:1.9 --- src/sys/dev/usb/TODO.usbmp:1.8 Sat Aug 2 15:50:16 2014 +++ src/sys/dev/usb/TODO.usbmp Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -$NetBSD: TODO.usbmp,v 1.8 2014/08/02 15:50:16 skrll Exp $ +$NetBSD: TODO.usbmp,v 1.9 2015/03/07 20:20:55 mrg Exp $ the majority of the USB MP device interface is documented in usbdivar.h. @@ -41,8 +41,8 @@ convert uhidev users to MPSAFE: - own cdevsw that isn't D_MPSAFE; need to check intr handlers uhid(4) - - needs some locking here (not completely tested changes) - - done + - D_MPSAFE not set as all users need it first. + - mostly done ukbd(4) ums(4) @@ -135,7 +135,7 @@ driver testing: STATUS - ral - rum - run - - urtw + - urtw working - urtwn - upgt - zyd Index: src/sys/dev/usb/uatp.c diff -u src/sys/dev/usb/uatp.c:1.10 src/sys/dev/usb/uatp.c:1.11 --- src/sys/dev/usb/uatp.c:1.10 Thu Jul 17 17:11:12 2014 +++ src/sys/dev/usb/uatp.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: uatp.c,v 1.10 2014/07/17 17:11:12 riastradh Exp $ */ +/* $NetBSD: uatp.c,v 1.11 2015/03/07 20:20:55 mrg Exp $ */ /*- * Copyright (c) 2011-2014 The NetBSD Foundation, Inc. @@ -146,7 +146,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uatp.c,v 1.10 2014/07/17 17:11:12 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uatp.c,v 1.11 2015/03/07 20:20:55 mrg Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -1350,8 +1350,7 @@ geyser34_initialize(struct uatp_softc *s DPRINTF(sc, UATP_DEBUG_MISC, ("initializing\n")); geyser34_enable_raw_mode(sc); - usb_init_task(&sc->sc_reset_task, &geyser34_reset_task, sc, - USB_TASKQ_MPSAFE); + usb_init_task(&sc->sc_reset_task, &geyser34_reset_task, sc, 0); } static int @@ -2012,7 +2011,7 @@ tap_debug(struct uatp_softc *sc, const c static void tap_initialize(struct uatp_softc *sc) { - callout_init(&sc->sc_untap_callout, CALLOUT_MPSAFE); + callout_init(&sc->sc_untap_callout, 0); callout_setfunc(&sc->sc_untap_callout, untap_callout, sc); mutex_init(&sc->sc_tap_mutex, MUTEX_DEFAULT, IPL_USB); cv_init(&sc->sc_tap_cv, "uatptap"); Index: src/sys/dev/usb/ucycom.c diff -u src/sys/dev/usb/ucycom.c:1.41 src/sys/dev/usb/ucycom.c:1.42 --- src/sys/dev/usb/ucycom.c:1.41 Sat Nov 15 19:26:37 2014 +++ src/sys/dev/usb/ucycom.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ucycom.c,v 1.41 2014/11/15 19:26:37 christos Exp $ */ +/* $NetBSD: ucycom.c,v 1.42 2015/03/07 20:20:55 mrg Exp $ */ /* * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.41 2014/11/15 19:26:37 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.42 2015/03/07 20:20:55 mrg Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1124,9 +1124,14 @@ ucycom_get_cfg(struct ucycom_softc *sc) Static void ucycom_cleanup(struct ucycom_softc *sc) { + uint8_t *obuf; + DPRINTF(("ucycom_cleanup: closing uhidev\n")); - if (sc->sc_obuf !=NULL) - free (sc->sc_obuf, M_USBDEV); + obuf = sc->sc_obuf; + sc->sc_obuf = NULL; uhidev_close(&sc->sc_hdev); + + if (obuf != NULL) + free (obuf, M_USBDEV); } Index: src/sys/dev/usb/uhid.c diff -u src/sys/dev/usb/uhid.c:1.92 src/sys/dev/usb/uhid.c:1.93 --- src/sys/dev/usb/uhid.c:1.92 Fri Jul 25 08:10:39 2014 +++ src/sys/dev/usb/uhid.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: uhid.c,v 1.92 2014/07/25 08:10:39 dholland Exp $ */ +/* $NetBSD: uhid.c,v 1.93 2015/03/07 20:20:55 mrg Exp $ */ /* * Copyright (c) 1998, 2004, 2008, 2012 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.92 2014/07/25 08:10:39 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.93 2015/03/07 20:20:55 mrg Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -91,7 +91,7 @@ struct uhid_softc { u_char *sc_obuf; - struct clist sc_q; + struct clist sc_q; /* protected by sc_lock */ struct selinfo sc_rsel; proc_t *sc_async; /* process that wants SIGIO */ void *sc_sih; @@ -127,7 +127,7 @@ const struct cdevsw uhid_cdevsw = { .d_mmap = nommap, .d_kqfilter = uhidkqfilter, .d_discard = nodiscard, - .d_flag = D_OTHER | D_MPSAFE + .d_flag = D_OTHER }; Static void uhid_intr(struct uhidev *, void *, u_int len); @@ -154,9 +154,9 @@ uhid_match(device_t parent, cfdata_t mat DPRINTF(("uhid_match: report=%d\n", uha->reportid)); if (match->cf_flags & 1) - return (UMATCH_HIGHEST); + return UMATCH_HIGHEST; else - return (UMATCH_IFACECLASS_GENERIC); + return UMATCH_IFACECLASS_GENERIC; } void @@ -172,7 +172,7 @@ uhid_attach(device_t parent, device_t se sc->sc_hdev.sc_intr = uhid_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; - sc->sc_sih = softint_establish(SOFTINT_MPSAFE | SOFTINT_CLOCK, + sc->sc_sih = softint_establish(SOFTINT_CLOCK, uhid_softintr, sc); uhidev_get_report_desc(uha->parent, &desc, &size); @@ -253,7 +253,7 @@ uhid_detach(device_t self, int flags) seldestroy(&sc->sc_rsel); softint_disestablish(sc->sc_sih); - return (0); + return 0; } void @@ -314,22 +314,31 @@ uhidopen(dev_t dev, int flag, int mode, DPRINTF(("uhidopen: sc=%p\n", sc)); if (sc->sc_dying) - return (ENXIO); + return ENXIO; mutex_enter(&sc->sc_access_lock); + + /* + * uhid interrupts aren't enabled yet, so setup sc_q now, as + * long as they're not already allocated. + */ + if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { + mutex_exit(&sc->sc_access_lock); + return EBUSY; + } + if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { + mutex_exit(&sc->sc_access_lock); + return ENOMEM; + } + error = uhidev_open(&sc->sc_hdev); if (error) { + clfree(&sc->sc_q); mutex_exit(&sc->sc_access_lock); - return (error); + return error; } mutex_exit(&sc->sc_access_lock); - if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { - mutex_enter(&sc->sc_access_lock); - uhidev_close(&sc->sc_hdev); - mutex_exit(&sc->sc_access_lock); - return (ENOMEM); - } sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); sc->sc_state &= ~UHID_IMMED; @@ -337,7 +346,7 @@ uhidopen(dev_t dev, int flag, int mode, sc->sc_async = NULL; mutex_exit(proc_lock); - return (0); + return 0; } int @@ -349,18 +358,24 @@ uhidclose(dev_t dev, int flag, int mode, DPRINTF(("uhidclose: sc=%p\n", sc)); - clfree(&sc->sc_q); - free(sc->sc_obuf, M_USBDEV); - mutex_enter(proc_lock); sc->sc_async = NULL; mutex_exit(proc_lock); mutex_enter(&sc->sc_access_lock); + + mutex_enter(&sc->sc_lock); + uhidev_stop(&sc->sc_hdev); + mutex_exit(&sc->sc_lock); + + clfree(&sc->sc_q); + free(sc->sc_obuf, M_USBDEV); + uhidev_close(&sc->sc_hdev); + mutex_exit(&sc->sc_access_lock); - return (0); + return 0; } int @@ -379,15 +394,15 @@ uhid_do_read(struct uhid_softc *sc, stru err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, buffer, sc->sc_isize + extra); if (err) - return (EIO); - return (uiomove(buffer+extra, sc->sc_isize, uio)); + return EIO; + return uiomove(buffer+extra, sc->sc_isize, uio); } mutex_enter(&sc->sc_lock); while (sc->sc_q.c_cc == 0) { if (flag & IO_NDELAY) { mutex_exit(&sc->sc_lock); - return (EWOULDBLOCK); + return EWOULDBLOCK; } sc->sc_state |= UHID_ASLP; DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); @@ -400,7 +415,6 @@ uhid_do_read(struct uhid_softc *sc, stru break; } } - mutex_exit(&sc->sc_lock); /* Transfer as many chunks as possible. */ while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { @@ -413,11 +427,14 @@ uhid_do_read(struct uhid_softc *sc, stru DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length)); /* Copy the data to the user process. */ + mutex_exit(&sc->sc_lock); if ((error = uiomove(buffer, length, uio)) != 0) - break; + return error; + mutex_enter(&sc->sc_lock); } - return (error); + mutex_exit(&sc->sc_lock); + return error; } int @@ -440,7 +457,7 @@ uhidread(dev_t dev, struct uio *uio, int if (--sc->sc_refcnt < 0) usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv); mutex_exit(&sc->sc_lock); - return (error); + return error; } int @@ -453,12 +470,12 @@ uhid_do_write(struct uhid_softc *sc, str DPRINTFN(1, ("uhidwrite\n")); if (sc->sc_dying) - return (EIO); + return EIO; size = sc->sc_osize; error = 0; if (uio->uio_resid != size) - return (EINVAL); + return EINVAL; error = uiomove(sc->sc_obuf, size, uio); if (!error) { err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, @@ -467,7 +484,7 @@ uhid_do_write(struct uhid_softc *sc, str error = EIO; } - return (error); + return error; } int @@ -490,7 +507,7 @@ uhidwrite(dev_t dev, struct uio *uio, in if (--sc->sc_refcnt < 0) usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv); mutex_exit(&sc->sc_lock); - return (error); + return error; } int @@ -507,7 +524,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); if (sc->sc_dying) - return (EIO); + return EIO; switch (cmd) { case FIONBIO: @@ -518,7 +535,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l mutex_enter(proc_lock); if (*(int *)addr) { if (sc->sc_async != NULL) - return (EBUSY); + return EBUSY; sc->sc_async = l->l_proc; DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", l->l_proc)); } else @@ -531,11 +548,11 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l mutex_enter(proc_lock); if (sc->sc_async == NULL) { mutex_exit(proc_lock); - return (EINVAL); + return EINVAL; } if (*(int *)addr != sc->sc_async->p_pgid) { mutex_exit(proc_lock); - return (EPERM); + return EPERM; } mutex_exit(proc_lock); break; @@ -544,12 +561,12 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l mutex_enter(proc_lock); if (sc->sc_async == NULL) { mutex_exit(proc_lock); - return (EINVAL); + return EINVAL; } if (-*(int *)addr != sc->sc_async->p_pgid && *(int *)addr != sc->sc_async->p_pid) { mutex_exit(proc_lock); - return (EPERM); + return EPERM; } mutex_exit(proc_lock); break; @@ -568,7 +585,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, buffer, sc->sc_isize + extra); if (err) - return (EOPNOTSUPP); + return EOPNOTSUPP; sc->sc_state |= UHID_IMMED; } else @@ -588,7 +605,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l size = sc->sc_fsize; break; default: - return (EINVAL); + return EINVAL; } extra = sc->sc_hdev.sc_report_id != 0; err = uhidev_get_report(&sc->sc_hdev, re->ucr_report, @@ -596,7 +613,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l if (extra) memcpy(re->ucr_data, re->ucr_data+1, size); if (err) - return (EIO); + return EIO; break; case USB_SET_REPORT: @@ -612,12 +629,12 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l size = sc->sc_fsize; break; default: - return (EINVAL); + return EINVAL; } err = uhidev_set_report(&sc->sc_hdev, re->ucr_report, re->ucr_data, size); if (err) - return (EIO); + return EIO; break; case USB_GET_REPORT_ID: @@ -647,14 +664,14 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l si->usd_string_index, si->usd_language_id, &si->usd_desc, &size); if (err) - return (EINVAL); + return EINVAL; break; } default: - return (EINVAL); + return EINVAL; } - return (0); + return 0; } int @@ -682,7 +699,7 @@ uhidioctl(dev_t dev, u_long cmd, void *a if (--sc->sc_refcnt < 0) usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv); mutex_exit(&sc->sc_lock); - return (error); + return error; } int @@ -709,7 +726,7 @@ uhidpoll(dev_t dev, int events, struct l } mutex_exit(&sc->sc_lock); - return (revents); + return revents; } static void @@ -746,7 +763,7 @@ uhidkqfilter(dev_t dev, struct knote *kn sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev)); if (sc->sc_dying) - return (ENXIO); + return ENXIO; switch (kn->kn_filter) { case EVFILT_READ: @@ -760,7 +777,7 @@ uhidkqfilter(dev_t dev, struct knote *kn break; default: - return (EINVAL); + return EINVAL; } kn->kn_hook = sc; @@ -769,5 +786,5 @@ uhidkqfilter(dev_t dev, struct knote *kn SLIST_INSERT_HEAD(klist, kn, kn_selnext); mutex_exit(&sc->sc_lock); - return (0); + return 0; } Index: src/sys/dev/usb/uhidev.c diff -u src/sys/dev/usb/uhidev.c:1.62 src/sys/dev/usb/uhidev.c:1.63 --- src/sys/dev/usb/uhidev.c:1.62 Sun Feb 8 19:22:45 2015 +++ src/sys/dev/usb/uhidev.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: uhidev.c,v 1.62 2015/02/08 19:22:45 jmcneill Exp $ */ +/* $NetBSD: uhidev.c,v 1.63 2015/03/07 20:20:55 mrg Exp $ */ /* * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.62 2015/02/08 19:22:45 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.63 2015/03/07 20:20:55 mrg Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -648,6 +648,30 @@ out1: } void +uhidev_stop(struct uhidev *scd) +{ + struct uhidev_softc *sc = scd->sc_parent; + + /* Disable interrupts. */ + if (sc->sc_opipe != NULL) { + usbd_abort_pipe(sc->sc_opipe); + usbd_close_pipe(sc->sc_opipe); + sc->sc_opipe = NULL; + } + + if (sc->sc_ipipe != NULL) { + usbd_abort_pipe(sc->sc_ipipe); + usbd_close_pipe(sc->sc_ipipe); + sc->sc_ipipe = NULL; + } + + if (sc->sc_ibuf != NULL) { + free(sc->sc_ibuf, M_USBDEV); + sc->sc_ibuf = NULL; + } +} + +void uhidev_close(struct uhidev *scd) { struct uhidev_softc *sc = scd->sc_parent; @@ -671,23 +695,8 @@ uhidev_close(struct uhidev *scd) sc->sc_oxfer = NULL; } - /* Disable interrupts. */ - if (sc->sc_opipe != NULL) { - usbd_abort_pipe(sc->sc_opipe); - usbd_close_pipe(sc->sc_opipe); - sc->sc_opipe = NULL; - } - - if (sc->sc_ipipe != NULL) { - usbd_abort_pipe(sc->sc_ipipe); - usbd_close_pipe(sc->sc_ipipe); - sc->sc_ipipe = NULL; - } - - if (sc->sc_ibuf != NULL) { - free(sc->sc_ibuf, M_USBDEV); - sc->sc_ibuf = NULL; - } + /* Possibly redundant, but properly handled */ + uhidev_stop(scd); } usbd_status Index: src/sys/dev/usb/uhidev.h diff -u src/sys/dev/usb/uhidev.h:1.16 src/sys/dev/usb/uhidev.h:1.17 --- src/sys/dev/usb/uhidev.h:1.16 Sun Feb 8 19:22:45 2015 +++ src/sys/dev/usb/uhidev.h Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: uhidev.h,v 1.16 2015/02/08 19:22:45 jmcneill Exp $ */ +/* $NetBSD: uhidev.h,v 1.17 2015/03/07 20:20:55 mrg Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -82,6 +82,7 @@ struct uhidev_attach_arg { void uhidev_get_report_desc(struct uhidev_softc *, void **, int *); int uhidev_open(struct uhidev *); +void uhidev_stop(struct uhidev *); void uhidev_close(struct uhidev *); usbd_status uhidev_set_report(struct uhidev *, int, void *, int); usbd_status uhidev_get_report(struct uhidev *, int, void *, int); Index: src/sys/dev/usb/ukbd.c diff -u src/sys/dev/usb/ukbd.c:1.129 src/sys/dev/usb/ukbd.c:1.130 --- src/sys/dev/usb/ukbd.c:1.129 Thu Sep 26 07:25:31 2013 +++ src/sys/dev/usb/ukbd.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: ukbd.c,v 1.129 2013/09/26 07:25:31 skrll Exp $ */ +/* $NetBSD: ukbd.c,v 1.130 2015/03/07 20:20:55 mrg Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.129 2013/09/26 07:25:31 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.130 2015/03/07 20:20:55 mrg Exp $"); #ifdef _KERNEL_OPT #include "opt_ukbd.h" @@ -478,8 +478,7 @@ ukbd_attach(device_t parent, device_t se callout_init(&sc->sc_delay, 0); - usb_init_task(&sc->sc_ledtask, ukbd_set_leds_task, sc, - USB_TASKQ_MPSAFE); + usb_init_task(&sc->sc_ledtask, ukbd_set_leds_task, sc, 0); /* Flash the leds; no real purpose, just shows we're alive. */ ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS Index: src/sys/dev/usb/uyurex.c diff -u src/sys/dev/usb/uyurex.c:1.9 src/sys/dev/usb/uyurex.c:1.10 --- src/sys/dev/usb/uyurex.c:1.9 Sat Jan 5 23:34:21 2013 +++ src/sys/dev/usb/uyurex.c Sat Mar 7 20:20:55 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: uyurex.c,v 1.9 2013/01/05 23:34:21 christos Exp $ */ +/* $NetBSD: uyurex.c,v 1.10 2015/03/07 20:20:55 mrg Exp $ */ /* $OpenBSD: uyurex.c,v 1.3 2010/03/04 03:47:22 deraadt Exp $ */ /* @@ -22,7 +22,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uyurex.c,v 1.9 2013/01/05 23:34:21 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uyurex.c,v 1.10 2015/03/07 20:20:55 mrg Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -150,6 +150,10 @@ uyurex_attach(device_t parent, device_t aprint_normal("\n"); aprint_naive("\n"); + /* + * XXX uhidev_open enables the interrupt, so we should do it as + * one of the final things here. + */ err = uhidev_open(&sc->sc_hdev); if (err) { aprint_error_dev(self, "uyurex_open: uhidev_open %d\n", err);