diff options
author | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-04-17 13:22:58 +0000 |
---|---|---|
committer | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-04-17 13:22:58 +0000 |
commit | 4f32f865517ba5c6a65550d39504a44065b9d013 (patch) | |
tree | d0ae29b1e147695fa5ecbdc7d1534c0413927dd8 /input/manager.c | |
parent | c0b506f5fe4aef93a61a8b57b6a31ccc78de5a3a (diff) |
input: Connect/disconnect to the control and interrupt psm at the ending of CreateDevice
Diffstat (limited to 'input/manager.c')
-rw-r--r-- | input/manager.c | 174 |
1 files changed, 151 insertions, 23 deletions
diff --git a/input/manager.c b/input/manager.c index f74349df..d339c007 100644 --- a/input/manager.c +++ b/input/manager.c @@ -27,7 +27,9 @@ #include <ctype.h> #include <dirent.h> +#include <errno.h> #include <stdlib.h> +#include <unistd.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> @@ -62,6 +64,7 @@ struct pending_req { DBusMessage *msg; sdp_record_t *pnp_rec; sdp_record_t *hid_rec; + int ctrl_sock; }; static GSList *device_paths = NULL; /* Input registered paths */ @@ -245,15 +248,151 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } +static gboolean interrupt_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_req *pr) +{ + struct hidp_connadd_req hidp; + DBusMessage *reply; + const char *path; + int isk, ret, err; + socklen_t len; + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + isk = -1; + goto failed; + } + + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + isk = -1; + error("Hangup or error on HIDP interrupt socket"); + goto failed; + + } + + isk = g_io_channel_unix_get_fd(chan); + + len = sizeof(ret); + if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + + memset(&hidp, 0, sizeof(struct hidp_connadd_req)); + extract_hid_record(pr->hid_rec, &hidp); + if (pr->pnp_rec) + extract_pnp_record(pr->pnp_rec, &hidp); + + store_device_info(&pr->src, &pr->dst, &hidp); + + if (input_device_register(pr->conn, &pr->src, + &pr->dst, &hidp, &path) < 0) { + err_failed(pr->conn, pr->msg, "path registration failed"); + goto cleanup; + } + + device_paths = g_slist_append(device_paths, g_strdup(path)); + + /* Replying to the requestor */ + reply = dbus_message_new_method_return(pr->msg); + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + send_message_and_unref(pr->conn, reply); + + goto cleanup; +failed: + err_connection_failed(pr->conn, pr->msg, strerror(err)); + +cleanup: + if (isk > 0) + close(isk); + + close(pr->ctrl_sock); + pending_req_free(pr); + g_io_channel_unref(chan); + + return FALSE; +} + +static gboolean control_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_req *pr) +{ + int ret, csk, err; + socklen_t len; + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + csk = -1; + goto failed; + } + + if (cond & (G_IO_HUP | G_IO_ERR)) { + err = EINTR; + csk = -1; + error("Hangup or error on HIDP control socket"); + goto failed; + + } + + csk = g_io_channel_unix_get_fd(chan); + /* Set HID control channel */ + pr->ctrl_sock = csk; + + len = sizeof(ret); + if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + err = errno; + error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); + goto failed; + } + + if (ret != 0) { + err = ret; + error("connect(): %s (%d)", strerror(ret), ret); + goto failed; + } + + /* Connect to the HID interrupt channel */ + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb, pr) < 0) { + + err = errno; + error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + goto failed; + } + + g_io_channel_unref(chan); + return FALSE; + +failed: + if (csk > 0) + close(csk); + + err_connection_failed(pr->conn, pr->msg, strerror(err)); + pending_req_free(pr); + + g_io_channel_unref(chan); + + return FALSE; +} + static void hid_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusMessage *pr_reply; struct pending_req *pr = data; - struct hidp_connadd_req hidp; DBusError derr; uint8_t *rec_bin; - const char *path; int len, scanned; dbus_error_init(&derr); @@ -289,29 +428,18 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - memset(&hidp, 0, sizeof(struct hidp_connadd_req)); - extract_hid_record(pr->hid_rec, &hidp); - if (pr->pnp_rec) - extract_pnp_record(pr->pnp_rec, &hidp); - - store_device_info(&pr->src, &pr->dst, &hidp); - - if (input_device_register(pr->conn, &pr->src, - &pr->dst, &hidp, &path) < 0) { - err_failed(pr->conn, pr->msg, "D-Bus path registration failed"); + if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, pr) < 0) { + int err = errno; + error("L2CAP connect failed:%s (%d)", strerror(err), err); + err_connection_failed(pr->conn, pr->msg, strerror(err)); goto fail; - } - - device_paths = g_slist_append(device_paths, g_strdup(path)); - pr_reply = dbus_message_new_method_return(pr->msg); - - dbus_message_append_args(pr_reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(pr->conn, pr_reply); + } + dbus_message_unref(reply); + dbus_pending_call_unref(call); + return; fail: dbus_error_free(&derr); pending_req_free(pr); |