Allow bthidev_output() to not grab the bt lock, to prevent lock
authormiod <miod@openbsd.org>
Thu, 5 Aug 2010 13:13:17 +0000 (13:13 +0000)
committermiod <miod@openbsd.org>
Thu, 5 Aug 2010 13:13:17 +0000 (13:13 +0000)
recursion when trying to send commands from input callbacks. Makes the
caps/num/scroll lock keys on btkbd correctly lit the leds instead of
panic'ing.
Noticed and fix tested by mlarkin@, "do whatever you want in bt" deraadt@

sys/dev/bluetooth/bthidev.c
sys/dev/bluetooth/bthidev.h
sys/dev/bluetooth/btkbd.c

index 2df6341..5ae67ea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bthidev.c,v 1.7 2010/07/02 15:01:10 blambert Exp $    */
+/*     $OpenBSD: bthidev.c,v 1.8 2010/08/05 13:13:17 miod Exp $        */
 /*     $NetBSD: bthidev.c,v 1.16 2008/08/06 15:01:23 plunky Exp $      */
 
 /*-
@@ -95,7 +95,7 @@ struct bthidev_softc {
 void   bthidev_timeout(void *);
 int    bthidev_listen(struct bthidev_softc *);
 int    bthidev_connect(struct bthidev_softc *);
-int    bthidev_output(struct bthidev *, uint8_t *, int);
+int    bthidev_output(struct bthidev *, uint8_t *, int, int);
 void   bthidev_null(struct bthidev *, uint8_t *, int);
 
 /* autoconf(9) glue */
@@ -856,7 +856,7 @@ bthidev_null(struct bthidev *hidev, uint8_t *report, int len)
 }
 
 int
-bthidev_output(struct bthidev *hidev, uint8_t *report, int rlen)
+bthidev_output(struct bthidev *hidev, uint8_t *report, int rlen, int nolock)
 {
        struct bthidev_softc *sc = (struct bthidev_softc *)hidev->sc_parent;
        struct mbuf *m;
@@ -892,9 +892,11 @@ bthidev_output(struct bthidev *hidev, uint8_t *report, int rlen)
        memcpy(mtod(m, uint8_t *) + 2, report, rlen);
        m->m_pkthdr.len = m->m_len = rlen + 2;
 
-       mutex_enter(&bt_lock);
+       if (!nolock)
+               mutex_enter(&bt_lock);
        err = l2cap_send(sc->sc_int, m);
-       mutex_exit(&bt_lock);
+       if (!nolock)
+               mutex_exit(&bt_lock);
 
        return err;
 }
index cfc7341..2932d02 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bthidev.h,v 1.3 2008/02/24 21:46:19 uwe Exp $ */
+/*     $OpenBSD: bthidev.h,v 1.4 2010/08/05 13:13:17 miod Exp $ */
 /*     $NetBSD: bthidev.h,v 1.4 2007/11/03 17:41:03 plunky Exp $       */
 
 /*-
@@ -71,7 +71,7 @@ struct bthidev_attach_args {
        void            (*ba_feature)   /* feature method */
                        (struct bthidev *, uint8_t *, int);
        int             (*ba_output)    /* output method */
-                       (struct bthidev *, uint8_t *, int);
+                       (struct bthidev *, uint8_t *, int, int);
 };
 
 #endif /* _KERNEL */
index ff34824..5de8553 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: btkbd.c,v 1.6 2010/07/31 16:04:50 miod Exp $  */
+/*     $OpenBSD: btkbd.c,v 1.7 2010/08/05 13:13:17 miod Exp $  */
 /*     $NetBSD: btkbd.c,v 1.10 2008/09/09 03:54:56 cube Exp $  */
 
 /*
@@ -90,7 +90,8 @@ struct btkbd_softc {
        struct bthidev           sc_hidev;      /* device */
        struct hidkbd            sc_kbd;        /* keyboard state */
        int                     (*sc_output)    /* output method */
-                               (struct bthidev *, uint8_t *, int);
+                               (struct bthidev *, uint8_t *, int, int);
+       int                      sc_inintr;
 };
 
 /* autoconf(9) methods */
@@ -188,7 +189,7 @@ btkbd_set_leds(void *self, int leds)
        if (hidkbd_set_leds(kbd, leds, &report) != 0) {
                if (sc->sc_output != NULL)
                        (*sc->sc_output)(&sc->sc_hidev, &report,
-                           sizeof(report));
+                           sizeof(report), sc->sc_inintr);
        }
 }
 
@@ -216,6 +217,9 @@ btkbd_input(struct bthidev *self, uint8_t *data, int len)
        struct btkbd_softc *sc = (struct btkbd_softc *)self;
        struct hidkbd *kbd = &sc->sc_kbd;
 
-       if (kbd->sc_enabled != 0)
+       if (kbd->sc_enabled != 0) {
+               sc->sc_inintr = 1;
                hidkbd_input(kbd, data, len);
+               sc->sc_inintr = 0;
+       }
 }