Index: device.c =================================================================== RCS file: /cvsroot/bluez/utils/input/device.c,v retrieving revision 1.71 diff -a -u -r1.71 device.c --- device.c 14 Mar 2008 18:44:00 -0000 1.71 +++ device.c 1 Apr 2008 15:42:26 -0000 @@ -78,8 +78,10 @@ char *path; int ctrl_sk; int intr_sk; + int hidp_sk; guint ctrl_watch; guint intr_watch; + guint hidp_watch; }; GSList *devices = NULL; @@ -524,8 +526,10 @@ DBUS_TYPE_INVALID); g_source_remove(idev->ctrl_watch); + g_source_remove(idev->hidp_watch); idev->ctrl_watch = 0; idev->intr_watch = 0; + idev->hidp_watch = 0; /* Close control channel */ if (idev->ctrl_sk > 0) { @@ -533,6 +537,12 @@ idev->ctrl_sk = -1; } + /* Close hidp channel */ + if (idev->hidp_sk > 0) { + close(idev->hidp_sk); + idev->hidp_sk = -1; + } + return FALSE; } @@ -551,8 +561,10 @@ DBUS_TYPE_INVALID); g_source_remove(idev->intr_watch); + g_source_remove(idev->hidp_watch); idev->intr_watch = 0; idev->ctrl_watch = 0; + idev->hidp_watch = 0; /* Close interrupt channel */ if (idev->intr_sk > 0) { @@ -560,6 +572,47 @@ idev->intr_sk = -1; } + /* Close hidp channel */ + if (idev->hidp_sk > 0) { + close(idev->hidp_sk); + idev->hidp_sk = -1; + } + + return FALSE; +} + +static gboolean hidp_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct device *idev = data; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + g_io_channel_close(chan); + } + + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + g_source_remove(idev->intr_watch); + g_source_remove(idev->ctrl_watch); + idev->intr_watch = 0; + idev->ctrl_watch = 0; + idev->hidp_watch = 0; + + /* Close interrupt channel */ + if (idev->intr_sk > 0) { + close(idev->intr_sk); + idev->intr_sk = -1; + } + + /* Close control channel */ + if (idev->ctrl_sk > 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; + } + return FALSE; } @@ -620,12 +673,10 @@ err = ioctl(ctl, HIDPCONNADD, &req); cleanup: - close(ctl); - if (req.rd_data) free(req.rd_data); - return err; + return ctl; } static gboolean interrupt_connect_cb(GIOChannel *chan, @@ -663,13 +714,14 @@ } idev->intr_sk = isk; - err = hidp_connadd(&idev->src, &idev->dst, + idev->hidp_sk = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); - if (err < 0) + if (idev->hidp_sk < 0) goto failed; idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); + idev->hidp_watch = create_watch(idev->hidp_sk, hidp_watch_cb, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, @@ -802,10 +854,15 @@ idev->intr_sk = -1; } - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - error("Can't open HIDP control socket"); - return -errno; + if (idev->hidp_sk >= 0) { + ctl = idev->hidp_sk; + idev->hidp_sk = -1; + } else { + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP control socket"); + return -errno; + } } memset(&ci, 0, sizeof(ci)); @@ -1181,6 +1238,9 @@ * to access the D-Bus data assigned to this path * because the object path data was destroyed. */ + if (idev->hidp_watch) + g_source_remove(idev->hidp_watch); + if (idev->ctrl_watch) g_source_remove(idev->ctrl_watch); @@ -1364,8 +1424,15 @@ fake->disconnect = fake_hid_disconnect; fake->priv = fake_hid; err = fake_hid_connadd(fake, idev->intr_sk, fake_hid); - } else - err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + } else { + idev->hidp_sk = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (idev->hidp_sk < 0) { + err = idev->hidp_sk; + } else { + err = 0; + idev->hidp_watch = create_watch(idev->hidp_sk, hidp_watch_cb, idev); + } + } if (err < 0) goto error;