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 | |
parent | c0b506f5fe4aef93a61a8b57b6a31ccc78de5a3a (diff) |
input: Connect/disconnect to the control and interrupt psm at the ending of CreateDevice
Diffstat (limited to 'input')
-rw-r--r-- | input/device.c | 127 | ||||
-rw-r--r-- | input/device.h | 4 | ||||
-rw-r--r-- | input/manager.c | 174 |
3 files changed, 218 insertions, 87 deletions
diff --git a/input/device.c b/input/device.c index a29cc095..76049ec4 100644 --- a/input/device.c +++ b/input/device.c @@ -54,9 +54,6 @@ #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" -#define L2CAP_PSM_HIDP_CTRL 0x11 -#define L2CAP_PSM_HIDP_INTR 0x13 - #define BUF_SIZE 16 #define UPDOWN_ENABLED 1 @@ -515,63 +512,6 @@ failed: return -err; } -static int l2cap_connect(struct device *idev, - unsigned short psm, GIOFunc cb) -{ - GIOChannel *io; - struct sockaddr_l2 addr; - struct l2cap_options opts; - int sk, err; - - if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &idev->src); - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) - goto failed; - - if (set_nonblocking(sk) < 0) - goto failed; - - memset(&opts, 0, sizeof(opts)); - opts.imtu = HIDP_DEFAULT_MTU; - opts.omtu = HIDP_DEFAULT_MTU; - opts.flush_to = 0xffff; - - if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) - goto failed; - - memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &idev->dst); - addr.l2_psm = htobs(psm); - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) - goto failed; - - g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) cb, idev); - } else { - cb(io, G_IO_OUT, idev); - } - - return 0; - -failed: - err = errno; - close(sk); - errno = err; - - return -1; -} - static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { @@ -704,8 +644,8 @@ static gboolean control_connect_cb(GIOChannel *chan, } /* Connect to the HID interrupt channel */ - if (l2cap_connect(idev, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb) < 0) { + if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb, idev) < 0) { err = errno; error("L2CAP connect failed:%s (%d)", strerror(errno), errno); @@ -861,8 +801,9 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - if (l2cap_connect(idev, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb) < 0) { + if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb, idev) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -1153,3 +1094,61 @@ int input_device_get_bdaddr(DBusConnection *conn, const char *path, return 0; } + +int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data) +{ + GIOChannel *io; + struct sockaddr_l2 addr; + struct l2cap_options opts; + int sk, err; + + if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, src); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) + goto failed; + + if (set_nonblocking(sk) < 0) + goto failed; + + memset(&opts, 0, sizeof(opts)); + opts.imtu = HIDP_DEFAULT_MTU; + opts.omtu = HIDP_DEFAULT_MTU; + opts.flush_to = 0xffff; + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) + goto failed; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, dst); + addr.l2_psm = htobs(psm); + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, FALSE); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + g_io_channel_unref(io); + goto failed; + } + + g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) cb, data); + } else { + cb(io, G_IO_OUT, data); + } + + return 0; + +failed: + err = errno; + close(sk); + errno = err; + + return -1; +} diff --git a/input/device.h b/input/device.h index b156b985..b3316841 100644 --- a/input/device.h +++ b/input/device.h @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ +#define L2CAP_PSM_HIDP_CTRL 0x11 +#define L2CAP_PSM_HIDP_INTR 0x13 int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hidp, const char **ppath); @@ -29,3 +31,5 @@ int input_device_unregister(DBusConnection *conn, const char *path); int input_device_get_bdaddr(DBusConnection *conn, const char *path, bdaddr_t *src, bdaddr_t *dst); +int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, + unsigned short psm, GIOFunc cb, void *data); 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); |