From 6a5605954320fe1d43fa6957e07ec4bcc9724454 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 28 Jan 2007 18:06:45 +0000 Subject: Rename input-service.[ch] into device.[ch] --- input/device.c | 1450 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1450 insertions(+) create mode 100644 input/device.c (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c new file mode 100644 index 00000000..421b6c20 --- /dev/null +++ b/input/device.c @@ -0,0 +1,1450 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "dbus.h" +#include "logging.h" +#include "textfile.h" + +#include "storage.h" +#include "device.h" + +#define INPUT_PATH "/org/bluez/input" +#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" +#define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" +#define INPUT_ERROR_INTERFACE "org.bluez.Error" + +#define L2CAP_PSM_HIDP_CTRL 0x11 +#define L2CAP_PSM_HIDP_INTR 0x13 + +static DBusConnection *connection = NULL; + +const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; +const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; + +struct input_device { + bdaddr_t dst; + struct hidp_connadd_req hidp; +}; + +struct input_manager { + bdaddr_t src; /* Local adapter BT address */ + GSList *paths; /* Input registered paths */ +}; + +struct pending_req { + char *adapter_path; /* Local adapter D-Bus path */ + bdaddr_t src; /* Local adapter BT address */ + bdaddr_t dst; /* Peer BT address */ + DBusConnection *conn; + DBusMessage *msg; + sdp_record_t *pnp_rec; + sdp_record_t *hid_rec; +}; + +struct pending_connect { + bdaddr_t src; + bdaddr_t dst; + DBusConnection *conn; + DBusMessage *msg; +}; + +static struct input_device *input_device_new(bdaddr_t *dst) +{ + struct input_device *idev; + + idev = malloc(sizeof(struct input_device)); + if (!idev) + return NULL; + + memset(idev, 0, sizeof(struct input_device)); + + bacpy(&idev->dst, dst); + + return idev; +} + +static void input_device_free(struct input_device *idev) +{ + if (!idev) + return; + if (idev->hidp.rd_data) + free(idev->hidp.rd_data); + free(idev); +} + +static struct pending_req *pending_req_new(DBusConnection *conn, + DBusMessage *msg, const char *adapter_path, + bdaddr_t *src, bdaddr_t *dst) +{ + struct pending_req *pr; + pr = malloc(sizeof(struct pending_req)); + if (!pr) + return NULL; + + memset(pr, 0, sizeof(struct pending_req)); + pr->adapter_path = strdup(adapter_path); + bacpy(&pr->src, src); + bacpy(&pr->dst, dst); + pr->conn = dbus_connection_ref(conn); + pr->msg = dbus_message_ref(msg); + + return pr; +} + +static void pending_req_free(struct pending_req *pr) +{ + if (!pr) + return; + if (pr->adapter_path) + free(pr->adapter_path); + if (pr->conn) + dbus_connection_unref(pr->conn); + if (pr->msg) + dbus_message_unref(pr->msg); + if (pr->pnp_rec) + sdp_record_free(pr->pnp_rec); + if (pr->hid_rec) + sdp_record_free(pr->hid_rec); + free(pr); +} + +static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, + DBusConnection *conn, DBusMessage *msg) +{ + struct pending_connect *pc; + pc = malloc(sizeof(struct pending_connect)); + if (!pc) + return NULL; + + memset(pc, 0, sizeof(struct pending_connect)); + bacpy(&pc->src, src); + bacpy(&pc->dst, dst); + pc->conn = dbus_connection_ref(conn); + pc->msg = dbus_message_ref(msg); + + return pc; +} + +static void pending_connect_free(struct pending_connect *pc) +{ + if (!pc) + return; + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); +} + +/* + * Common D-Bus BlueZ input error functions + */ +static DBusHandlerResult err_unknown_device(DBusConnection *conn, DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".UnknownDevice", + "Invalid device")); +} + +static DBusHandlerResult err_unknown_method(DBusConnection *conn, DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".UnknownMethod", + "Unknown input method")); +} + +static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, + const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".Failed", str)); +} + +static DBusHandlerResult err_connection_failed(DBusConnection *conn, + DBusMessage *msg, const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE".ConnectionAttemptFailed", + str)); +} + +static DBusHandlerResult err_already_exists(DBusConnection *conn, + DBusMessage *msg, const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".AlreadyExists", str)); +} + +static DBusHandlerResult err_does_not_exist(DBusConnection *conn, + DBusMessage *msg, const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".DoesNotExist", str)); +} + +static DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg, + const char *name, const char *str) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, name, str)); + +} + +static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) +{ + sdp_data_t *pdlist, *pdlist2; + uint8_t attr_val; + + pdlist = sdp_data_get(rec, 0x0101); + pdlist2 = sdp_data_get(rec, 0x0102); + if (pdlist) { + if (pdlist2) { + if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { + strncpy(req->name, pdlist2->val.str, 127); + strcat(req->name, " "); + } + strncat(req->name, pdlist->val.str, 127 - strlen(req->name)); + } else + strncpy(req->name, pdlist->val.str, 127); + } else { + pdlist2 = sdp_data_get(rec, 0x0100); + if (pdlist2) + strncpy(req->name, pdlist2->val.str, 127); + } + + pdlist = sdp_data_get(rec, 0x0201); + req->parser = pdlist ? pdlist->val.uint16 : 0x0100; + + pdlist = sdp_data_get(rec, 0x0202); + req->subclass = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0203); + req->country = pdlist ? pdlist->val.uint8 : 0; + + pdlist = sdp_data_get(rec, 0x0204); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); + + pdlist = sdp_data_get(rec, 0x020E); + attr_val = pdlist ? pdlist->val.uint8 : 0; + if (attr_val) + req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); + + pdlist = sdp_data_get(rec, 0x0206); + if (pdlist) { + pdlist = pdlist->val.dataseq; + pdlist = pdlist->val.dataseq; + pdlist = pdlist->next; + + req->rd_data = malloc(pdlist->unitSize); + if (req->rd_data) { + memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); + req->rd_size = pdlist->unitSize; + } + } +} + +static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) +{ + sdp_data_t *pdlist; + + pdlist = sdp_data_get(rec, 0x0201); + req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0202); + req->product = pdlist ? pdlist->val.uint16 : 0x0000; + + pdlist = sdp_data_get(rec, 0x0203); + req->version = pdlist ? pdlist->val.uint16 : 0x0000; +} + +static const char *create_input_path(uint8_t minor) +{ + static char path[48]; + char subpath[32]; + static int next_id = 0; + + switch (minor & 0xc0) { + case 0x40: + strcpy(subpath, "keyboard"); + break; + case 0x80: + strcpy(subpath, "pointing"); + break; + case 0xc0: + strcpy(subpath, "combo"); + break; + default: + subpath[0] = '\0'; + break; + } + + if ((minor & 0x3f) && (strlen(subpath) > 0)) + strcat(subpath, "/"); + + switch (minor & 0x3f) { + case 0x00: + break; + case 0x01: + strcat(subpath, "joystick"); + break; + case 0x02: + strcat(subpath, "gamepad"); + break; + case 0x03: + strcat(subpath, "remotecontrol"); + break; + case 0x04: + strcat(subpath, "sensing"); + break; + case 0x05: + strcat(subpath, "digitizertablet"); + break; + case 0x06: + strcat(subpath, "cardreader"); + break; + default: + strcat(subpath, "reserved"); + break; + } + + snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); + return path; +} + +static int l2cap_connect(struct pending_connect *pc, + 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, &pc->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, &pc->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, (GIOFunc) cb, pc); + } else { + cb(io, G_IO_OUT, pc); + } + + return 0; + +failed: + err = errno; + close(sk); + errno = err; + + return -1; +} + +static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + struct input_device *idev; + int ctl, isk, ret, err; + socklen_t len; + const char *path; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + isk = -1; + goto failed; + } + + isk = g_io_channel_unix_get_fd(chan); + idev->hidp.intr_sock = isk; + idev->hidp.idle_to = 30 * 60; /* 30 minutes */ + + 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; + } + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + err = errno; + error("Can't open HIDP control socket"); + goto failed; + } + + if (idev->hidp.subclass & 0x40) { + err = encrypt_link(&pc->src, &pc->dst); + if (err < 0) { + close(ctl); + goto failed; + } + } + + if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { + err = errno; + close(ctl); + goto failed; + } + + + send_message_and_unref(pc->conn, + dbus_message_new_method_return(pc->msg)); + + close (ctl); + goto cleanup; +failed: + err_connection_failed(pc->conn, pc->msg, strerror(err)); + +cleanup: + if (isk > 0) + close(isk); + + close(idev->hidp.ctrl_sock); + + idev->hidp.intr_sock = -1; + idev->hidp.ctrl_sock = -1; + + pending_connect_free(pc); + g_io_channel_unref(chan); + + return FALSE; +} + +static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, + struct pending_connect *pc) +{ + struct input_device *idev; + int ret, csk, err; + socklen_t len; + const char *path; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + + if (cond & G_IO_NVAL) { + err = EHOSTDOWN; + csk = -1; + goto failed; + } + + csk = g_io_channel_unix_get_fd(chan); + /* Set HID control channel */ + idev->hidp.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(pc, L2CAP_PSM_HIDP_INTR, + (GIOFunc) interrupt_connect_cb) < 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); + + idev->hidp.ctrl_sock = -1; + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + g_io_channel_unref(chan); + + return FALSE; +} + +static int disconnect(struct input_device *idev, uint32_t flags) +{ + struct hidp_conndel_req req; + struct hidp_conninfo ci; + int ctl, err; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP control socket"); + return -errno; + } + + memset(&ci, 0, sizeof(struct hidp_conninfo)); + bacpy(&ci.bdaddr, &idev->dst); + if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || + (ci.state != BT_CONNECTED)) { + errno = ENOTCONN; + goto fail; + } + + memset(&req, 0, sizeof(struct hidp_conndel_req)); + bacpy(&req.bdaddr, &idev->dst); + req.flags = flags; + if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { + error("Can't delete the HID device: %s(%d)", + strerror(errno), errno); + goto fail; + } + + close(ctl); + + return 0; +fail: + err = errno; + close(ctl); + errno = err; + + idev->hidp.intr_sock = -1; + idev->hidp.ctrl_sock = -1; + + return -errno; +} + +static int is_connected(bdaddr_t *dst) +{ + struct hidp_conninfo ci; + int ctl; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) + return 0; + + memset(&ci, 0, sizeof(struct hidp_conninfo)); + bacpy(&ci.bdaddr, dst); + if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { + close(ctl); + return 0; + } + + close(ctl); + + if (ci.state != BT_CONNECTED) + return 0; + else + return 1; +} + +/* + * Input Device methods + */ +static DBusHandlerResult device_connect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + struct input_manager *mgr; + struct pending_connect *pc; + + if (is_connected(&idev->dst)) + return err_connection_failed(conn, msg, "Already connected"); + + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); + pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); + if (!pc) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + (GIOFunc) control_connect_cb) < 0) { + error("L2CAP connect failed: %s(%d)", strerror(errno), errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, strerror(errno)); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult device_disconnect(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + + if (disconnect(idev, 0) < 0) + return err_failed(conn, msg, strerror(errno)); + + return send_message_and_unref(conn, + dbus_message_new_method_return(msg)); +} + +static DBusHandlerResult device_is_connected(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + dbus_bool_t connected; + + connected = is_connected(&idev->dst); + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_address(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + char addr[18]; + const char *paddr = addr; + + ba2str(&idev->dst, addr); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_name(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + const char *pname = idev->hidp.name; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &pname, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_product_id(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.product, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_device *idev = data; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &idev->hidp.vendor, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult device_set_timeout(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult device_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *iface, *member; + + iface = dbus_message_get_interface(msg); + member = dbus_message_get_member(msg); + + /* Accept messages from the input interface only */ + if (strcmp(INPUT_DEVICE_INTERFACE, iface)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (strcmp(member, "Connect") == 0) + return device_connect(conn, msg, data); + + if (strcmp(member, "Disconnect") == 0) + return device_disconnect(conn, msg, data); + + if (strcmp(member, "IsConnected") == 0) + return device_is_connected(conn, msg, data); + + if (strcmp(member, "GetAddress") == 0) + return device_get_address(conn, msg, data); + + if (strcmp(member, "GetName") == 0) + return device_get_name(conn, msg, data); + + if (strcmp(member, "GetProductId") == 0) + return device_get_product_id(conn, msg, data); + + if (strcmp(member, "GetVendorId") == 0) + return device_get_vendor_id(conn, msg, data); + + if (strcmp(member, "SetTimeout") == 0) + return device_set_timeout(conn, msg, data); + + return err_unknown_method(conn, msg); +} + +static void device_unregister(DBusConnection *conn, void *data) +{ + input_device_free(data); +} + +/* Virtual table to handle device object path hierarchy */ +static const DBusObjectPathVTable device_table = { + .message_function = device_message, + .unregister_function = device_unregister, +}; + +/* + * Input Manager methods + */ +static void input_manager_free(struct input_manager *mgr) +{ + if (!mgr) + return; + + if (mgr->paths) { + g_slist_foreach(mgr->paths, (GFunc) free, NULL); + g_slist_free(mgr->paths); + } + + free(mgr); +} + +static int register_input_device(DBusConnection *conn, + struct input_device *idev, const char *path) +{ + DBusMessage *msg; + struct input_manager *mgr; + + if (!dbus_connection_register_object_path(conn, + path, &device_table, idev)) { + error("Input device path registration failed"); + return -1; + } + + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); + mgr->paths = g_slist_append(mgr->paths, strdup(path)); + + msg = dbus_message_new_signal(INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceCreated"); + if (!msg) + return -1; + + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + send_message_and_unref(conn, msg); + + info("Created input device: %s", path); + + return 0; +} + +static int unregister_input_device(DBusConnection *conn, const char *path) +{ + DBusMessage *msg; + + if (!dbus_connection_unregister_object_path(conn, path)) { + error("Input device path unregister failed"); + return -1; + } + + msg = dbus_message_new_signal(INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved"); + if (!msg) + return -1; + + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + send_message_and_unref(conn, msg); + + return 0; +} + +static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) +{ + struct input_device *idev; + + if (!dbus_connection_get_object_path_data(connection, path, + (void *) &idev)) + return -1; + + if (!idev) + return -1; + + return bacmp(&idev->dst, bdaddr); +} + +static int get_record(struct pending_req *pr, uint32_t handle, + DBusPendingCallNotifyFunction cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + char addr[18]; + const char *paddr = addr; + + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + "org.bluez.Adapter", "GetRemoteServiceRecord"); + if (!msg) + return -1; + + ba2str(&pr->dst, addr); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_UINT32, &handle, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { + error("Can't send D-Bus message."); + return -1; + } + + dbus_pending_call_set_notify(pending, cb, pr, NULL); + dbus_message_unref(msg); + + return 0; +} + +static int get_handles(struct pending_req *pr, const char *uuid, + DBusPendingCallNotifyFunction cb) +{ + DBusMessage *msg; + DBusPendingCall *pending; + char addr[18]; + const char *paddr = addr; + + msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, + "org.bluez.Adapter", "GetRemoteServiceHandles"); + if (!msg) + return -1; + + ba2str(&pr->dst, addr); + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { + error("Can't send D-Bus message."); + return -1; + } + + dbus_pending_call_set_notify(pending, cb, pr, NULL); + dbus_message_unref(msg); + + return 0; +} + +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 input_device *idev; + DBusError derr; + uint8_t *rec_bin; + const char *path; + int len, scanned; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len == 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + + pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); + if (!pr->hid_rec) { + err_failed(pr->conn, pr->msg, "HID not supported"); + goto fail; + } + + idev = input_device_new(&pr->dst); + + extract_hid_record(pr->hid_rec, &idev->hidp); + if (pr->pnp_rec) + extract_pnp_record(pr->pnp_rec, &idev->hidp); + + path = create_input_path(idev->hidp.subclass); + + if (register_input_device(pr->conn, idev, path) < 0) { + err_failed(pr->conn, pr->msg, "D-Bus path registration failed"); + input_device_free(idev); + goto fail; + } + + 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); + + store_device_info(&pr->src, &pr->dst, &idev->hidp); +fail: + pending_req_free(pr); + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static void hid_handle_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + uint32_t *phandle; + DBusError derr; + int len; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len != 0) { + if (get_record(pr, *phandle, hid_record_reply) < 0) + error("HID record search error"); + else + goto done; + } + err_failed(pr->conn, pr->msg, "SDP error"); +fail: + pending_req_free(pr); +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static void pnp_record_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + DBusError derr; + uint8_t *rec_bin; + int len; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len != 0) { + int scanned; + pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) + error("HID record search error"); + else + goto done; + } + + err_failed(pr->conn, pr->msg, "SDP error"); + +fail: + pending_req_free(pr); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static void pnp_handle_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + DBusError derr; + uint32_t *phandle; + int len; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { + + err_generic(pr->conn, pr->msg, derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + if (len == 0) { + /* PnP is optional: Ignore it and request the HID handle */ + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + } else { + /* Request PnP record */ + if (get_record(pr, *phandle, pnp_record_reply) < 0) { + err_failed(pr->conn, pr->msg, "SDP error"); + goto fail; + } + } + + goto done; + +fail: + pending_req_free(pr); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static DBusHandlerResult manager_create_device(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_manager *mgr = data; + struct input_device *idev; + DBusMessage *reply; + DBusError derr; + char adapter[18], adapter_path[32]; + const char *addr, *path; + GSList *l; + bdaddr_t dst; + int dev_id; + + dbus_error_init(&derr); + if (!dbus_message_get_args(msg, &derr, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID)) { + err_generic(conn, msg, derr.name, derr.message); + dbus_error_free(&derr); + return DBUS_HANDLER_RESULT_HANDLED; + } + + str2ba(addr, &dst); + l = g_slist_find_custom(mgr->paths, &dst, + (GCompareFunc) path_bdaddr_cmp); + if (l) + return err_already_exists(conn, msg, "Input Already exists"); + + ba2str(&mgr->src, adapter); + dev_id = hci_devid(adapter); + snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); + + idev = input_device_new(&dst); + if (!idev) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { + struct pending_req *pr; + + /* Data not found: create the input device later */ + input_device_free(idev); + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); + if (!pr) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { + pending_req_free(pr); + return err_failed(conn, msg, "SDP error"); + } + + return DBUS_HANDLER_RESULT_HANDLED; + } + + path = create_input_path(idev->hidp.subclass); + if (register_input_device(conn, idev, path) < 0) { + input_device_free(idev); + return err_failed(conn, msg, "D-Bus path registration failed"); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) { + input_device_free(idev); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult manager_remove_device(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_manager *mgr = data; + struct input_device *idev; + DBusMessage *reply; + DBusError derr; + GSList *l; + const char *path; + + dbus_error_init(&derr); + if (!dbus_message_get_args(msg, &derr, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_INVALID)) { + err_generic(conn, msg, derr.name, derr.message); + dbus_error_free(&derr); + return DBUS_HANDLER_RESULT_HANDLED; + } + + l = g_slist_find_custom(mgr->paths, path, (GCompareFunc) strcmp); + if (!l) + return err_does_not_exist(conn, msg, "Input doesn't exist"); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + /* Try disconnect */ + if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev) + disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); + + del_stored_device_info(&mgr->src, &idev->dst); + + if (unregister_input_device(conn, path) < 0) { + dbus_message_unref(reply); + return err_failed(conn, msg, "D-Bus path unregistration failed"); + } + + free(l->data); + mgr->paths = g_slist_remove(mgr->paths, l->data); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult manager_list_devices(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct input_manager *mgr = data; + DBusMessageIter iter, iter_array; + DBusMessage *reply; + GSList *paths; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &iter_array); + + for (paths = mgr->paths; paths != NULL; paths = paths->next) { + const char *ppath = paths->data; + dbus_message_iter_append_basic(&iter_array, + DBUS_TYPE_STRING, &ppath); + } + + dbus_message_iter_close_container(&iter, &iter_array); + + return send_message_and_unref(conn, reply); +} + +static DBusHandlerResult manager_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *path, *iface, *member; + + path = dbus_message_get_path(msg); + iface = dbus_message_get_interface(msg); + member = dbus_message_get_member(msg); + + /* Catching fallback paths */ + if (strcmp(INPUT_PATH, path) != 0) + return err_unknown_device(conn, msg); + + /* Accept messages from the input manager interface only */ + if (strcmp(INPUT_MANAGER_INTERFACE, iface)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (strcmp(member, "ListDevices") == 0) + return manager_list_devices(conn, msg, data); + + if (strcmp(member, "CreateDevice") == 0) + return manager_create_device(conn, msg, data); + + if (strcmp(member, "RemoveDevice") == 0) + return manager_remove_device(conn, msg, data); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void manager_unregister(DBusConnection *conn, void *data) +{ + struct input_manager *mgr = data; + + info("Unregistered manager path"); + + input_manager_free(mgr); +} + +/* Virtual table to handle manager object path hierarchy */ +static const DBusObjectPathVTable manager_table = { + .message_function = manager_message, + .unregister_function = manager_unregister, +}; + +static void stored_input(char *key, char *value, void *data) +{ + DBusConnection *conn = data; + struct input_device *idev; + const char *path; + bdaddr_t dst; + + str2ba(key, &dst); + idev = input_device_new(&dst); + if (parse_stored_device_info(value, &idev->hidp) < 0) { + input_device_free(idev); + return; + } + + path = create_input_path(idev->hidp.subclass); + if (register_input_device(conn, idev, path) < 0) + input_device_free(idev); +} + +static int register_stored_inputs(DBusConnection *conn, bdaddr_t *src) +{ + char filename[PATH_MAX + 1]; + char addr[18]; + + ba2str(src, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); + textfile_foreach(filename, stored_input, conn); + + return 0; +} + +int input_dbus_init(void) +{ + struct input_manager *mgr; + bdaddr_t src; + int dev_id; + + connection = init_dbus(NULL, NULL, NULL); + if (!connection) + return -1; + + dbus_connection_set_exit_on_disconnect(connection, TRUE); + + mgr = malloc(sizeof(struct input_manager)); + memset(mgr, 0, sizeof(struct input_manager)); + /* Fallback to catch invalid device path */ + if (!dbus_connection_register_fallback(connection, INPUT_PATH, + &manager_table, mgr)) { + error("D-Bus failed to register %s path", INPUT_PATH); + goto fail; + } + + info("Registered input manager path:%s", INPUT_PATH); + + /* Set the default adapter */ + bacpy(&src, BDADDR_ANY); + dev_id = hci_get_route(&src); + if (dev_id < 0) { + error("Bluetooth device not available"); + goto fail; + } + + if (hci_devba(dev_id, &src) < 0) { + error("Can't get local adapter device info"); + goto fail; + } + + bacpy(&mgr->src, &src); + /* Register well known HID devices */ + register_stored_inputs(connection, &src); + + return 0; + +fail: + input_manager_free(mgr); + + return -1; +} + +void input_dbus_exit(void) +{ + dbus_connection_unregister_object_path(connection, INPUT_PATH); + + dbus_connection_unref(connection); +} + +void internal_service(const char *identifier) +{ + DBusMessage *msg, *reply; + const char *name = "Input Service Debug", *desc = ""; + + info("Registering service"); + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Database", "RegisterService"); + if (!msg) { + error("Can't create service register method"); + return; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &identifier, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID); + + reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, NULL); + if (!reply) { + error("Can't register service"); + return; + } + + dbus_message_unref(msg); + dbus_message_unref(reply); + + dbus_connection_flush(connection); +} -- cgit From 928217b1aca4c7a16e77cf68d7c9e63fa0e6bdb2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 13 Feb 2007 17:51:09 +0000 Subject: Return NotSupported error if the remote device doesn't support the required services(compliant to audio daemon) --- input/device.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 421b6c20..54c5d3dc 100644 --- a/input/device.c +++ b/input/device.c @@ -206,6 +206,14 @@ static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, INPUT_ERROR_INTERFACE ".Failed", str)); } +static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg) +{ + return send_message_and_unref(conn, + dbus_message_new_error(msg, + INPUT_ERROR_INTERFACE ".NotSupported", + "The service is not supported by the remote device")); +} + static DBusHandlerResult err_connection_failed(DBusConnection *conn, DBusMessage *msg, const char *str) { @@ -967,7 +975,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -975,19 +984,20 @@ static void hid_record_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } if (len == 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); if (!pr->hid_rec) { - err_failed(pr->conn, pr->msg, "HID not supported"); + err_not_supported(pr->conn, pr->msg); goto fail; } @@ -1028,7 +1038,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1036,8 +1047,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1048,7 +1059,7 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) else goto done; } - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); fail: pending_req_free(pr); done: @@ -1066,7 +1077,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1074,7 +1086,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1088,8 +1101,7 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) goto done; } - err_failed(pr->conn, pr->msg, "SDP error"); - + err_not_supported(pr->conn, pr->msg); fail: pending_req_free(pr); @@ -1108,7 +1120,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1116,8 +1129,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - - err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1125,13 +1138,13 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) if (len == 0) { /* PnP is optional: Ignore it and request the HID handle */ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } } else { /* Request PnP record */ if (get_record(pr, *phandle, pnp_record_reply) < 0) { - err_failed(pr->conn, pr->msg, "SDP error"); + err_not_supported(pr->conn, pr->msg); goto fail; } } @@ -1193,7 +1206,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); - return err_failed(conn, msg, "SDP error"); + return err_not_supported(conn, msg); } return DBUS_HANDLER_RESULT_HANDLED; -- cgit From c90bdcc8c0c7659b2bb31bbbe5eb7e16fd7e9b5a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 18:45:59 +0000 Subject: Fake input: added initial code for headset support --- input/device.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 54c5d3dc..a1d4e1f5 100644 --- a/input/device.c +++ b/input/device.c @@ -63,6 +63,7 @@ static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; +const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct input_device { bdaddr_t dst; @@ -932,6 +933,28 @@ static int get_record(struct pending_req *pr, uint32_t handle, return 0; } +static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) +{ + char filename[PATH_MAX + 1], *str; + char addr[18]; + + ba2str(src, addr); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "classes"); + + ba2str(dst, addr); + str = textfile_get(filename, addr); + if (!str) + return -ENOENT; + + *cls = strtol(str, NULL, 16); + + free(str); + if ((*cls == LONG_MIN) || (*cls == LONG_MAX)) + return -ERANGE; + + return 0; +} + static int get_handles(struct pending_req *pr, const char *uuid, DBusPendingCallNotifyFunction cb) { @@ -1159,6 +1182,26 @@ done: dbus_pending_call_unref(call); } +static void headset_handle_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + struct pending_req *pr = data; + DBusError derr; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("%s: %s", derr.name, derr.message); + err_not_supported(pr->conn, pr->msg); + dbus_error_free(&derr); + } + + /*FIXME: Parse the content */ + + pending_req_free(pr); + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -1170,6 +1213,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, const char *addr, *path; GSList *l; bdaddr_t dst; + uint32_t cls = 0; int dev_id; dbus_error_init(&derr); @@ -1195,16 +1239,33 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; + if (get_class(&mgr->src, &dst, &cls) < 0) + return err_not_supported(conn, msg); + if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; - /* Data not found: create the input device later */ input_device_free(idev); + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); if (!pr) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { + switch (cls & 0x1f00) { + case 0x0500: /* Peripheral */ + if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { + pending_req_free(pr); + return err_not_supported(conn, msg); + } + break; + case 0x0400: /* Fake input */ + if (get_handles(pr, headset_uuid, + headset_handle_reply) < 0) { + pending_req_free(pr); + return err_not_supported(conn, msg); + } + break; + default: pending_req_free(pr); return err_not_supported(conn, msg); } @@ -1212,6 +1273,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } + /* FIXME: Stored data found, create a fake input or a standard HID */ path = create_input_path(idev->hidp.subclass); if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); -- cgit From 86fa3713b108d19fcf8add8ce109de337ede94c7 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 20:12:27 +0000 Subject: Fake input: added code to request the headset service record --- input/device.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index a1d4e1f5..fd448768 100644 --- a/input/device.c +++ b/input/device.c @@ -1182,22 +1182,77 @@ done: dbus_pending_call_unref(call); } +static void headset_record_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessage *pr_reply; + struct pending_req *pr = data; + DBusError derr; + const char *path = "/org/bluez/input/headset0"; + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); + error("%s: %s", derr.name, derr.message); + dbus_error_free(&derr); + goto fail; + } + + /* FIXME: extract the record */ + /* FIXME: Register the fake input 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); +fail: + pending_req_free(pr); + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + static void headset_handle_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; + uint32_t *phandle; + int len; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); + goto fail; + } + + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, + DBUS_TYPE_INVALID)) { err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("%s: %s", derr.name, derr.message); + goto fail; } - /*FIXME: Parse the content */ + if (len == 0) { + err_not_supported(pr->conn, pr->msg); + error("headset record handle not found"); + goto fail; + } + if (get_record(pr, *phandle, headset_record_reply) < 0) { + err_not_supported(pr->conn, pr->msg); + error("headset service attribute request failed"); + goto fail; + } + + /* Wait record reply */ + goto done; +fail: + dbus_error_free(&derr); pending_req_free(pr); +done: dbus_message_unref(reply); dbus_pending_call_unref(call); } -- cgit From 45bbf75895cf2f6902089e00bf23d7d96326416e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 21:03:27 +0000 Subject: Fake input: added headset record parsing --- input/device.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index fd448768..5f805ca2 100644 --- a/input/device.c +++ b/input/device.c @@ -1186,20 +1186,73 @@ static void headset_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusMessage *pr_reply; - struct pending_req *pr = data; DBusError derr; + struct pending_req *pr = data; + struct input_device *idev; + uint8_t *rec_bin; + sdp_record_t *rec; + sdp_list_t *protos; + int len, scanned; + uint8_t ch; const char *path = "/org/bluez/input/headset0"; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - dbus_error_free(&derr); goto fail; } - /* FIXME: extract the record */ - /* FIXME: Register the fake input path */ + if (!dbus_message_get_args(reply, &derr, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, + DBUS_TYPE_INVALID)) { + err_not_supported(pr->conn, pr->msg); + error("%s: %s", derr.name, derr.message); + goto fail; + } + + if (len == 0) { + err_not_supported(pr->conn, pr->msg); + error("Invalid headset service record length"); + goto fail; + } + + rec = sdp_extract_pdu(rec_bin, &scanned); + if (!rec) { + err_not_supported(pr->conn, pr->msg); + goto fail; + } + + if (sdp_get_access_protos(rec, &protos) < 0) { + err_not_supported(pr->conn, pr->msg); + goto fail; + } + + ch = sdp_get_proto_port(protos, RFCOMM_UUID); + sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL); + sdp_list_free(protos, NULL); + sdp_record_free(rec); + + if (ch <= 0) { + err_not_supported(pr->conn, pr->msg); + error("Invalid RFCOMM channel"); + goto fail; + } + + idev = input_device_new(&pr->dst); + if (!idev) { + error("Out of memory when allocating new input"); + goto fail; + } + + /* FIXME: Store the ch and create the fake input path */ + + if (register_input_device(pr->conn, idev, path) < 0) { + error("D-Bus path registration failed:%s", path); + err_failed(pr->conn, pr->msg, "Path registration failed"); + input_device_free(idev); + goto fail; + } pr_reply = dbus_message_new_method_return(pr->msg); dbus_message_append_args(pr_reply, @@ -1207,6 +1260,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) DBUS_TYPE_INVALID); send_message_and_unref(pr->conn, pr_reply); fail: + dbus_error_free(&derr); pending_req_free(pr); dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1237,13 +1291,13 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) if (len == 0) { err_not_supported(pr->conn, pr->msg); - error("headset record handle not found"); + error("Headset record handle not found"); goto fail; } if (get_record(pr, *phandle, headset_record_reply) < 0) { err_not_supported(pr->conn, pr->msg); - error("headset service attribute request failed"); + error("Headset service attribute request failed"); goto fail; } -- cgit From a83064cf50b360efc354f85d02cde8fda20399d2 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Feb 2007 21:13:54 +0000 Subject: Don't hide errors returned by hcid --- input/device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 5f805ca2..01b38b18 100644 --- a/input/device.c +++ b/input/device.c @@ -998,8 +998,8 @@ static void hid_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1061,8 +1061,8 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1100,8 +1100,8 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } @@ -1143,8 +1143,8 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { + err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - err_not_supported(pr->conn, pr->msg); dbus_error_free(&derr); goto fail; } -- cgit From 0f08988e53758147e3394bbc24c751f186392b06 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 13:44:11 +0000 Subject: Code cleanup: removing deep indentation and added error messages --- input/device.c | 71 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 30 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 01b38b18..2c44750e 100644 --- a/input/device.c +++ b/input/device.c @@ -1000,21 +1000,20 @@ static void hid_record_reply(DBusPendingCall *call, void *data) if (dbus_set_error_from_message(&derr, reply)) { err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { - error("%s: %s", derr.name, derr.message); err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("%s: %s", derr.name, derr.message); goto fail; } if (len == 0) { err_not_supported(pr->conn, pr->msg); + error("Invalid HID service record length"); goto fail; } @@ -1046,6 +1045,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) store_device_info(&pr->src, &pr->dst, &idev->hidp); fail: + dbus_error_free(&derr); pending_req_free(pr); dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1063,27 +1063,33 @@ static void hid_handle_reply(DBusPendingCall *call, void *data) if (dbus_set_error_from_message(&derr, reply)) { err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { + err_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); + goto fail; + } + + if (len == 0) { err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("HID record handle not found"); goto fail; } - if (len != 0) { - if (get_record(pr, *phandle, hid_record_reply) < 0) - error("HID record search error"); - else - goto done; + if (get_record(pr, *phandle, hid_record_reply) < 0) { + err_not_supported(pr->conn, pr->msg); + error("HID service attribute request failed"); + goto fail; + } else { + /* Wait record reply */ + goto done; } - err_not_supported(pr->conn, pr->msg); fail: + dbus_error_free(&derr); pending_req_free(pr); done: dbus_message_unref(reply); @@ -1096,38 +1102,42 @@ static void pnp_record_reply(DBusPendingCall *call, void *data) struct pending_req *pr = data; DBusError derr; uint8_t *rec_bin; - int len; + int len, scanned; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, DBUS_TYPE_INVALID)) { + err_not_supported(pr->conn, pr->msg); error("%s: %s", derr.name, derr.message); + goto fail; + } + + if (len == 0) { err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("Invalid PnP service record length"); goto fail; } - if (len != 0) { - int scanned; - pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) - error("HID record search error"); - else - goto done; + pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); + if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { + err_not_supported(pr->conn, pr->msg); + error("HID service search request failed"); + goto fail; + } else { + /* Wait handle reply */ + goto done; } - err_not_supported(pr->conn, pr->msg); fail: + dbus_error_free(&derr); pending_req_free(pr); - done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1145,16 +1155,14 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) if (dbus_set_error_from_message(&derr, reply)) { err_generic(pr->conn, pr->msg, derr.name, derr.message); error("%s: %s", derr.name, derr.message); - dbus_error_free(&derr); goto fail; } if (!dbus_message_get_args(reply, &derr, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, DBUS_TYPE_INVALID)) { - error("%s: %s", derr.name, derr.message); err_not_supported(pr->conn, pr->msg); - dbus_error_free(&derr); + error("%s: %s", derr.name, derr.message); goto fail; } @@ -1162,21 +1170,24 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data) /* PnP is optional: Ignore it and request the HID handle */ if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { err_not_supported(pr->conn, pr->msg); + error("HID service search request failed"); goto fail; } } else { /* Request PnP record */ if (get_record(pr, *phandle, pnp_record_reply) < 0) { err_not_supported(pr->conn, pr->msg); + error("PnP service attribute request failed"); goto fail; } } + /* Wait HID handle reply or PnP record reply */ goto done; fail: + dbus_error_free(&derr); pending_req_free(pr); - done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -1299,10 +1310,10 @@ static void headset_handle_reply(DBusPendingCall *call, void *data) err_not_supported(pr->conn, pr->msg); error("Headset service attribute request failed"); goto fail; + } else { + /* Wait record reply */ + goto done; } - - /* Wait record reply */ - goto done; fail: dbus_error_free(&derr); pending_req_free(pr); -- cgit From 2957490728208811926b2d548ef77432564fc916 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:22:03 +0000 Subject: Fake input: added function to create the D-Bus fake input path --- input/device.c | 177 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 58 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 2c44750e..495886bd 100644 --- a/input/device.c +++ b/input/device.c @@ -65,9 +65,17 @@ const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; +struct fake_input { + uint8_t ch; +}; + struct input_device { bdaddr_t dst; - struct hidp_connadd_req hidp; + uint8_t major; + uint8_t minor; + struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + struct fake_input *fake; + }; struct input_manager { @@ -92,7 +100,7 @@ struct pending_connect { DBusMessage *msg; }; -static struct input_device *input_device_new(bdaddr_t *dst) +static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) { struct input_device *idev; @@ -104,6 +112,9 @@ static struct input_device *input_device_new(bdaddr_t *dst) bacpy(&idev->dst, dst); + idev->major = (cls >> 8) & 0x1f; + idev->minor = (cls >> 2) & 0x3f; + return idev; } @@ -317,54 +328,76 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -static const char *create_input_path(uint8_t minor) +static const char *create_input_path(uint8_t major, uint8_t minor) { static char path[48]; char subpath[32]; static int next_id = 0; - switch (minor & 0xc0) { - case 0x40: - strcpy(subpath, "keyboard"); - break; - case 0x80: - strcpy(subpath, "pointing"); - break; - case 0xc0: - strcpy(subpath, "combo"); - break; - default: - subpath[0] = '\0'; + switch (major) { + case 0x04: /* Audio */ + switch (minor) { + /* FIXME: Testing required */ + case 0x01: /* Wearable Headset Device */ + strcpy(subpath, "wearable"); + break; + case 0x02: /* Hands-free */ + strcpy(subpath, "handsfree"); + break; + case 0x06: /* Headphone */ + strcpy(subpath, "headphone"); + break; + default: + return NULL; + } break; - } + case 0x05: /* Peripheral */ + switch (minor & 0x30) { + case 0x10: + strcpy(subpath, "keyboard"); + break; + case 0x20: + strcpy(subpath, "pointing"); + break; + case 0x30: + strcpy(subpath, "combo"); + break; + default: + subpath[0] = '\0'; + break; + } - if ((minor & 0x3f) && (strlen(subpath) > 0)) - strcat(subpath, "/"); + if ((minor & 0x0f) && (strlen(subpath) > 0)) + strcat(subpath, "/"); - switch (minor & 0x3f) { - case 0x00: - break; - case 0x01: - strcat(subpath, "joystick"); - break; - case 0x02: - strcat(subpath, "gamepad"); - break; - case 0x03: - strcat(subpath, "remotecontrol"); - break; - case 0x04: - strcat(subpath, "sensing"); - break; - case 0x05: - strcat(subpath, "digitizertablet"); - break; - case 0x06: - strcat(subpath, "cardreader"); + switch (minor & 0x0f) { + case 0x00: + break; + case 0x01: + strcat(subpath, "joystick"); + break; + case 0x02: + strcat(subpath, "gamepad"); + break; + case 0x03: + strcat(subpath, "remotecontrol"); + break; + case 0x04: + strcat(subpath, "sensing"); + break; + case 0x05: + strcat(subpath, "digitizertablet"); + break; + case 0x06: + strcat(subpath, "cardreader"); + break; + default: + strcat(subpath, "reserved"); + break; + } break; default: - strcat(subpath, "reserved"); - break; + return NULL; } snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++); @@ -995,6 +1028,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) uint8_t *rec_bin; const char *path; int len, scanned; + uint32_t cls; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -1023,13 +1057,19 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst); + if (get_class(&pr->src, &pr->dst, &cls) < 0) { + err_not_supported(pr->conn, pr->msg); + error("Device class not available"); + goto fail; + } + + idev = input_device_new(&pr->dst, cls); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) extract_pnp_record(pr->pnp_rec, &idev->hidp); - path = create_input_path(idev->hidp.subclass); + path = create_input_path(idev->major, idev->minor); if (register_input_device(pr->conn, idev, path) < 0) { err_failed(pr->conn, pr->msg, "D-Bus path registration failed"); @@ -1203,9 +1243,10 @@ static void headset_record_reply(DBusPendingCall *call, void *data) uint8_t *rec_bin; sdp_record_t *rec; sdp_list_t *protos; + const char *path; int len, scanned; + uint32_t cls; uint8_t ch; - const char *path = "/org/bluez/input/headset0"; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -1250,14 +1291,28 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst); + if (get_class(&pr->src, &pr->dst, &cls) < 0) { + err_not_supported(pr->conn, pr->msg); + error("Device class not available"); + goto fail; + } + + idev = input_device_new(&pr->dst, cls); if (!idev) { error("Out of memory when allocating new input"); goto fail; } - /* FIXME: Store the ch and create the fake input path */ + idev->fake = malloc(sizeof(struct fake_input)); + if (!idev->fake) { + error("Out of memory when allocating new fake input"); + input_device_free(idev); + goto fail; + } + memset(idev->fake, 0, sizeof(struct fake_input)); + idev->fake->ch = ch; + path = create_input_path(idev->major, idev->minor); if (register_input_device(pr->conn, idev, path) < 0) { error("D-Bus path registration failed:%s", path); err_failed(pr->conn, pr->msg, "Path registration failed"); @@ -1355,13 +1410,15 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, dev_id = hci_devid(adapter); snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); - idev = input_device_new(&dst); + if (get_class(&mgr->src, &dst, &cls) < 0) { + error("Device class not available"); + return err_not_supported(conn, msg); + } + + idev = input_device_new(&dst, cls); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (get_class(&mgr->src, &dst, &cls) < 0) - return err_not_supported(conn, msg); - if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; /* Data not found: create the input device later */ @@ -1393,8 +1450,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } - /* FIXME: Stored data found, create a fake input or a standard HID */ - path = create_input_path(idev->hidp.subclass); + path = create_input_path(idev->major, idev->minor); if (register_input_device(conn, idev, path) < 0) { input_device_free(idev); return err_failed(conn, msg, "D-Bus path registration failed"); @@ -1530,31 +1586,36 @@ static const DBusObjectPathVTable manager_table = { static void stored_input(char *key, char *value, void *data) { - DBusConnection *conn = data; + bdaddr_t *src = data; struct input_device *idev; const char *path; bdaddr_t dst; + uint32_t cls; str2ba(key, &dst); - idev = input_device_new(&dst); + + if (get_class(src, &dst, &cls) < 0) + return; + + idev = input_device_new(&dst, cls); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; } - path = create_input_path(idev->hidp.subclass); - if (register_input_device(conn, idev, path) < 0) + path = create_input_path(idev->major, idev->minor); + if (register_input_device(connection, idev, path) < 0) input_device_free(idev); } -static int register_stored_inputs(DBusConnection *conn, bdaddr_t *src) +static int register_stored_inputs(bdaddr_t *src) { char filename[PATH_MAX + 1]; char addr[18]; ba2str(src, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); - textfile_foreach(filename, stored_input, conn); + textfile_foreach(filename, stored_input, src); return 0; } @@ -1597,7 +1658,7 @@ int input_dbus_init(void) bacpy(&mgr->src, &src); /* Register well known HID devices */ - register_stored_inputs(connection, &src); + register_stored_inputs(&src); return 0; -- cgit From e977c52ef242556e3af44bec99c64bac91cc0b11 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:26:47 +0000 Subject: Fake input: missing input device fake struct free --- input/device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 495886bd..20c2a1d0 100644 --- a/input/device.c +++ b/input/device.c @@ -124,6 +124,8 @@ static void input_device_free(struct input_device *idev) return; if (idev->hidp.rd_data) free(idev->hidp.rd_data); + if (idev->fake) + free(idev->fake); free(idev); } @@ -1312,6 +1314,8 @@ static void headset_record_reply(DBusPendingCall *call, void *data) memset(idev->fake, 0, sizeof(struct fake_input)); idev->fake->ch = ch; + /* FIXME: Store the fake input data */ + path = create_input_path(idev->major, idev->minor); if (register_input_device(pr->conn, idev, path) < 0) { error("D-Bus path registration failed:%s", path); -- cgit From c436cfee30f6272b256f7cdbf66b2e35c70ac603 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 18:45:54 +0000 Subject: Fake input: added initial skeleton for Connect method --- input/device.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 20c2a1d0..c487b4ee 100644 --- a/input/device.c +++ b/input/device.c @@ -406,6 +406,18 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) +{ + char addr[18]; + /* FIXME: not implemented */ + + ba2str(&pc->dst, addr); + debug("RFCOMM connecting to %s on channel:%d", addr, ch); + errno = EIO; + + return -EIO; +} + static int l2cap_connect(struct pending_connect *pc, unsigned short psm, GIOFunc cb) { @@ -673,17 +685,33 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; + struct fake_input *fake = idev->fake; struct input_manager *mgr; struct pending_connect *pc; + /* FIXME: check if the fake input is connected */ if (is_connected(&idev->dst)) return err_connection_failed(conn, msg, "Already connected"); + /* FIXME: Check if there is a pending connection */ + dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); if (!pc) return DBUS_HANDLER_RESULT_NEED_MEMORY; + /* Fake input device */ + if (fake) { + if (rfcomm_connect(pc, fake->ch) < 0) { + const char *str = strerror(errno); + error("RFCOMM connect failed: %s(%d)", str, errno); + pending_connect_free(pc); + return err_connection_failed(conn, msg, str); + } + return DBUS_HANDLER_RESULT_HANDLED; + } + + /* HID devices */ if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb) < 0) { error("L2CAP connect failed: %s(%d)", strerror(errno), errno); -- cgit From 57e21703e213e61fdfd6571a421e2f9da118444b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 19:04:43 +0000 Subject: Fake input: added rfcomm_connect --- input/device.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index c487b4ee..3b11f491 100644 --- a/input/device.c +++ b/input/device.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -406,16 +407,88 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static gboolean rfcomm_connect_cb(GIOChannel *chan, + GIOCondition cond, struct pending_connect *pc) +{ + int err = EIO; + + err_connection_failed(pc->conn, pc->msg, strerror(err)); + pending_connect_free(pc); + g_io_channel_unref(chan); + return FALSE; +} + static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) { - char addr[18]; - /* FIXME: not implemented */ + struct sockaddr_rc addr; + GIOChannel *io; + int sk, err; + + sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (sk < 0) { + err = errno; + error("socket: %s (%d)", strerror(err), err); + return -err; + } + + io = g_io_channel_unix_new(sk); + if (!io) { + err = -EIO; + error("channel_unix_new failed in rfcomm connect"); + goto failed; + } + + g_io_channel_set_close_on_unref(io, FALSE); + + memset(&addr, 0, sizeof(addr)); + addr.rc_family = AF_BLUETOOTH; + bacpy(&addr.rc_bdaddr, &pc->src); + addr.rc_channel = 0; - ba2str(&pc->dst, addr); - debug("RFCOMM connecting to %s on channel:%d", addr, ch); - errno = EIO; + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + err = errno; + error("bind: %s (%d)", strerror(err), err); + goto failed; + } + + if (set_nonblocking(sk) < 0) { + err = errno; + error("Set non blocking: %s (%d)", strerror(err), err); + goto failed; + } + + memset(&addr, 0, sizeof(addr)); + addr.rc_family = AF_BLUETOOTH; + bacpy(&addr.rc_bdaddr, &pc->dst); + addr.rc_channel = ch; + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + char peer[18]; /* FIXME: debug purpose */ + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + err = errno; + error("connect() failed: %s (%d)", + strerror(err), err); + goto failed; + } + + ba2str(&pc->dst, peer); + debug("RFCOMM connection in progress: %s channel:%d", peer, ch); + g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + (GIOFunc) rfcomm_connect_cb, pc); + } else { + debug("Connect succeeded with first try"); + rfcomm_connect_cb(io, G_IO_OUT, pc); + } + + return 0; + +failed: + if (io) + g_io_channel_unref(io); + + close(sk); + errno = err; - return -EIO; + return -err; } static int l2cap_connect(struct pending_connect *pc, -- cgit From 6130f3819aa5e51d90202b0bd974c0d79f65f5ad Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 20:11:08 +0000 Subject: Fake input: added rfcomm connect callback function --- input/device.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 3b11f491..f92eb3b9 100644 --- a/input/device.c +++ b/input/device.c @@ -67,6 +67,7 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct fake_input { + int rfcomm; uint8_t ch; }; @@ -410,8 +411,63 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { - int err = EIO; + struct input_device *idev; + struct fake_input *fake; + DBusMessage *reply; + const char *path; + socklen_t len; + int ret, err; + + path = dbus_message_get_path(pc->msg); + dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); + fake = idev->fake; + + if (cond & G_IO_NVAL) { + g_io_channel_unref(chan); + return FALSE; + } + + if (cond & (G_IO_ERR | G_IO_HUP)) { + err = EIO; + goto failed; + } + + fake->rfcomm = g_io_channel_unix_get_fd(chan); + + len = sizeof(ret); + if (getsockopt(fake->rfcomm, 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(err), err); + goto failed; + } + + /* + * FIXME: Some headsets required a sco connection + * first to report volume gain key events + */ + + /* FIXME: Create the uinput */ + /* FIXME: Add the watch to listen on rfcomm channel */ + + reply = dbus_message_new_method_return(pc->msg); + if (reply) { + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + pending_connect_free(pc); + g_io_channel_unref(chan); + return FALSE; + +failed: + /* FIXME: close the rfcomm socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); -- cgit From 14f36096be225e8c30e439abf19e731bdc3feb02 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 23 Feb 2007 20:58:43 +0000 Subject: Fake input: added uinput create function --- input/device.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index f92eb3b9..26443177 100644 --- a/input/device.c +++ b/input/device.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include "dbus.h" #include "logging.h" #include "textfile.h" +#include "uinput.h" #include "storage.h" #include "device.h" @@ -67,8 +69,9 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct fake_input { - int rfcomm; - uint8_t ch; + int rfcomm; /* RFCOMM socket */ + int uinput; /* uinput socket */ + uint8_t ch; /* RFCOMM channel number */ }; struct input_device { @@ -332,6 +335,64 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } +static int uinput_create(char *name) +{ + struct uinput_dev dev; + int fd, err; + + fd = open("/dev/uinput", O_RDWR); + if (fd < 0) { + fd = open("/dev/input/uinput", O_RDWR); + if (fd < 0) { + fd = open("/dev/misc/uinput", O_RDWR); + if (fd < 0) { + err = errno; + error("Can't open input device: %s (%d)", + strerror(err), err); + return -err; + } + } + } + + memset(&dev, 0, sizeof(dev)); + if (name) + strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE); + + dev.id.bustype = BUS_BLUETOOTH; + dev.id.vendor = 0x0000; + dev.id.product = 0x0000; + dev.id.version = 0x0000; + + if (write(fd, &dev, sizeof(dev)) < 0) { + err = errno; + error("Can't write device information: %s (%d)", + strerror(err), err); + close(fd); + errno = err; + return -err; + } + + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_EVBIT, EV_REP); + + ioctl(fd, UI_SET_KEYBIT, KEY_UP); + ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP); + ioctl(fd, UI_SET_KEYBIT, KEY_DOWN); + ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN); + + if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { + err = errno; + error("Can't create uinput device: %s (%d)", + strerror(err), err); + close(fd); + errno = err; + return -err; + } + + return fd; +} + static const char *create_input_path(uint8_t major, uint8_t minor) { static char path[48]; @@ -453,6 +514,11 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, */ /* FIXME: Create the uinput */ + fake->uinput = uinput_create("Fake input"); + if (fake->uinput < 0) { + err = errno; + goto failed; + } /* FIXME: Add the watch to listen on rfcomm channel */ @@ -467,7 +533,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - /* FIXME: close the rfcomm socket */ + /* FIXME: close the rfcomm and uinput socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); -- cgit From 22021d175f4946a5e9f5a663542016bceec3106e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:05:03 +0000 Subject: Fake input: added watch for RFCOMM IO channel --- input/device.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 26443177..25235ece 100644 --- a/input/device.c +++ b/input/device.c @@ -62,6 +62,8 @@ #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 +#define BUF_SIZE 16 + static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; @@ -69,6 +71,7 @@ const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; struct fake_input { + GIOChannel *io; int rfcomm; /* RFCOMM socket */ int uinput; /* uinput socket */ uint8_t ch; /* RFCOMM channel number */ @@ -469,6 +472,50 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct fake_input *fake = data; + const char *ok = "\r\nOK\r\n"; + GError *gerr = NULL; + char buf[BUF_SIZE]; + gsize bread = 0, bwritten; + + if (cond & G_IO_NVAL) + return FALSE; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + error("Hangup or error on rfcomm server socket"); + goto failed; + } + + memset(buf, 0, BUF_SIZE); + if (g_io_channel_read_chars(chan, (gchar *)buf, sizeof(buf) - 1, + &bread, &gerr) != G_IO_STATUS_NORMAL) { + error("IO Channel read error: %s", gerr->message); + g_error_free(gerr); + goto failed; + } + + if (g_io_channel_write_chars(chan, ok, 6, &bwritten, + &gerr) != G_IO_STATUS_NORMAL) { + error("IO Channel write error: %s", gerr->message); + g_error_free(gerr); + goto failed; + } + + debug("FIXME: decode %s", buf); + + return TRUE; + +failed: + g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_unref(chan); + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + return FALSE; +} + static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *pc) { @@ -513,14 +560,16 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, * first to report volume gain key events */ - /* FIXME: Create the uinput */ fake->uinput = uinput_create("Fake input"); if (fake->uinput < 0) { err = errno; goto failed; } - /* FIXME: Add the watch to listen on rfcomm channel */ + fake->io = g_io_channel_unix_new(fake->rfcomm); + g_io_channel_set_close_on_unref(fake->io, TRUE); + g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) rfcomm_io_cb, fake); reply = dbus_message_new_method_return(pc->msg); if (reply) { -- cgit From 15b471676729c330796ebabe9481a028a76b1112 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:38:33 +0000 Subject: Fake input: Added function to decode keys --- input/device.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 25235ece..674a1c53 100644 --- a/input/device.c +++ b/input/device.c @@ -64,6 +64,8 @@ #define BUF_SIZE 16 +#define UPDOWN_ENABLED 1 + static DBusConnection *connection = NULL; const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; @@ -472,6 +474,37 @@ static const char *create_input_path(uint8_t major, uint8_t minor) return path; } +static int decode_key(const char *str) +{ + static int mode = UPDOWN_ENABLED, gain = 0; + + uint16_t key; + int new_gain; + + /* Switch from key up/down to page up/down */ + if (strncmp("AT+CKPD=200", str, 11) == 0) { + mode = ~mode; + return KEY_RESERVED; + } + + if (strncmp("AT+VG", str, 5)) + return KEY_RESERVED; + + /* Gain key pressed */ + if (strlen(str) != 10) + return KEY_RESERVED; + + new_gain = strtol(&str[7], NULL, 10); + if (new_gain <= gain) + key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); + else + key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP); + + gain = new_gain; + + return key; +} + static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; @@ -479,6 +512,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) GError *gerr = NULL; char buf[BUF_SIZE]; gsize bread = 0, bwritten; + uint16_t key; if (cond & G_IO_NVAL) return FALSE; @@ -503,7 +537,11 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) goto failed; } - debug("FIXME: decode %s", buf); + key = decode_key(buf); + if (key != KEY_RESERVED) { + /* FIXME: send the key to uinput */ + debug("Key code: %d", key); + } return TRUE; -- cgit From e67c250c80d1da4e8210c62cf473deeb2ba4e152 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 15:53:47 +0000 Subject: Fake input: fixed get_class --- input/device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 674a1c53..7cd595d0 100644 --- a/input/device.c +++ b/input/device.c @@ -1291,11 +1291,12 @@ static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) if (!str) return -ENOENT; - *cls = strtol(str, NULL, 16); + if (sscanf(str, "%x", cls) != 1) { + free(str); + return -ENOENT; + } free(str); - if ((*cls == LONG_MIN) || (*cls == LONG_MAX)) - return -ERANGE; return 0; } -- cgit From 1f4fd0b880866139504a0e233c7327c8b88dbbbd Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 26 Feb 2007 17:45:51 +0000 Subject: Fake input: added uinput send key/event --- input/device.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 7cd595d0..b28ae45b 100644 --- a/input/device.c +++ b/input/device.c @@ -496,15 +496,37 @@ static int decode_key(const char *str) new_gain = strtol(&str[7], NULL, 10); if (new_gain <= gain) - key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); - else key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP); + else + key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); gain = new_gain; return key; } +static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) +{ + struct uinput_event event; + + memset(&event, 0, sizeof(event)); + event.type = type; + event.code = code; + event.value = value; + + write(fd, &event, sizeof(event)); +} + +static void send_key(int fd, uint16_t key) +{ + /* Key press */ + send_event(fd, EV_KEY, key, 1); + send_event(fd, EV_SYN, SYN_REPORT, 0); + /* Key release */ + send_event(fd, EV_KEY, key, 0); + send_event(fd, EV_SYN, SYN_REPORT, 0); +} + static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; @@ -530,6 +552,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) goto failed; } + debug("Received: %s", buf); + if (g_io_channel_write_chars(chan, ok, 6, &bwritten, &gerr) != G_IO_STATUS_NORMAL) { error("IO Channel write error: %s", gerr->message); @@ -538,10 +562,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) } key = decode_key(buf); - if (key != KEY_RESERVED) { - /* FIXME: send the key to uinput */ - debug("Key code: %d", key); - } + if (key != KEY_RESERVED) + send_key(fake->uinput, key); return TRUE; -- cgit From af47f85ea4422e8ec35564c1e26f84469c94c1e4 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 12:20:59 +0000 Subject: Fake input: Changed disconnect function to support fake devices --- input/device.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index b28ae45b..bf20257e 100644 --- a/input/device.c +++ b/input/device.c @@ -915,12 +915,31 @@ failed: return FALSE; } -static int disconnect(struct input_device *idev, uint32_t flags) +static int disconnect(struct input_device *idev, uint32_t flags) { + struct fake_input *fake = idev->fake; struct hidp_conndel_req req; struct hidp_conninfo ci; int ctl, err; + /* Fake input disconnect */ + if (fake) { + if (fake->io) { + g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_unref(fake->io); + fake->io = NULL; + } + if (fake->uinput >= 0) { + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + } + + return 0; + } + + /* Standard HID disconnect */ + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { error("Can't open HIDP control socket"); -- cgit From bebbd2498d580e91d8184970732383449d856a3c Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 13:07:02 +0000 Subject: Fake input: fixed build error when glib is disabled --- input/device.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index bf20257e..0ae644a5 100644 --- a/input/device.c +++ b/input/device.c @@ -531,7 +531,6 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; const char *ok = "\r\nOK\r\n"; - GError *gerr = NULL; char buf[BUF_SIZE]; gsize bread = 0, bwritten; uint16_t key; @@ -545,19 +544,16 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) } memset(buf, 0, BUF_SIZE); - if (g_io_channel_read_chars(chan, (gchar *)buf, sizeof(buf) - 1, - &bread, &gerr) != G_IO_STATUS_NORMAL) { - error("IO Channel read error: %s", gerr->message); - g_error_free(gerr); + if (g_io_channel_read(chan, buf, sizeof(buf) - 1, + &bread) != G_IO_ERROR_NONE) { + error("IO Channel read error"); goto failed; } debug("Received: %s", buf); - if (g_io_channel_write_chars(chan, ok, 6, &bwritten, - &gerr) != G_IO_STATUS_NORMAL) { - error("IO Channel write error: %s", gerr->message); - g_error_free(gerr); + if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) { + error("IO Channel write error"); goto failed; } @@ -568,7 +564,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: - g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_close(chan); g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); @@ -925,7 +921,7 @@ static int disconnect(struct input_device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { if (fake->io) { - g_io_channel_shutdown(fake->io, FALSE, NULL); + g_io_channel_close(fake->io); g_io_channel_unref(fake->io); fake->io = NULL; } -- cgit From d242929462d90d619156709b9188f455d6f1fea3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 19:39:03 +0000 Subject: Fake input: changed is_connected function to support fake inputs --- input/device.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 0ae644a5..3c6c2f12 100644 --- a/input/device.c +++ b/input/device.c @@ -564,6 +564,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: + /* FIXME: Missing clean/free fake io channel */ g_io_channel_close(chan); g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); @@ -638,7 +639,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - /* FIXME: close the rfcomm and uinput socket */ err_connection_failed(pc->conn, pc->msg, strerror(err)); pending_connect_free(pc); g_io_channel_unref(chan); @@ -973,17 +973,27 @@ fail: return -errno; } -static int is_connected(bdaddr_t *dst) +static int is_connected(struct input_device *idev) { + struct fake_input *fake = idev->fake; struct hidp_conninfo ci; int ctl; + /* Fake input */ + if (fake) { + if (fake->io) + return 1; + else + return 0; + } + + /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) return 0; memset(&ci, 0, sizeof(struct hidp_conninfo)); - bacpy(&ci.bdaddr, dst); + bacpy(&ci.bdaddr, &idev->dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); return 0; @@ -1008,8 +1018,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct input_manager *mgr; struct pending_connect *pc; - /* FIXME: check if the fake input is connected */ - if (is_connected(&idev->dst)) + if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); /* FIXME: Check if there is a pending connection */ @@ -1060,7 +1069,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *reply; dbus_bool_t connected; - connected = is_connected(&idev->dst); + connected = is_connected(idev); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From 40d70645a6e6954eaeb6790d7e191ff8f8d958f3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 27 Feb 2007 21:40:12 +0000 Subject: Input: added verification for pending connection --- input/device.c | 182 ++++++++++++++++++++++++++------------------------------- 1 file changed, 83 insertions(+), 99 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 3c6c2f12..816342c0 100644 --- a/input/device.c +++ b/input/device.c @@ -79,13 +79,19 @@ struct fake_input { uint8_t ch; /* RFCOMM channel number */ }; +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + struct input_device { + bdaddr_t src; bdaddr_t dst; uint8_t major; uint8_t minor; struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ struct fake_input *fake; - + struct pending_connect *pending_connect; }; struct input_manager { @@ -103,14 +109,7 @@ struct pending_req { sdp_record_t *hid_rec; }; -struct pending_connect { - bdaddr_t src; - bdaddr_t dst; - DBusConnection *conn; - DBusMessage *msg; -}; - -static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) +static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint32_t cls) { struct input_device *idev; @@ -120,6 +119,7 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) memset(idev, 0, sizeof(struct input_device)); + bacpy(&idev->src, src); bacpy(&idev->dst, dst); idev->major = (cls >> 8) & 0x1f; @@ -128,6 +128,17 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) return idev; } +static void pending_connect_free(struct pending_connect *pc) +{ + if (!pc) + return; + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); +} + static void input_device_free(struct input_device *idev) { if (!idev) @@ -136,6 +147,9 @@ static void input_device_free(struct input_device *idev) free(idev->hidp.rd_data); if (idev->fake) free(idev->fake); + if (idev->pending_connect) + pending_connect_free(idev->pending_connect); + free(idev); } @@ -175,34 +189,6 @@ static void pending_req_free(struct pending_req *pr) free(pr); } -static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, - DBusConnection *conn, DBusMessage *msg) -{ - struct pending_connect *pc; - pc = malloc(sizeof(struct pending_connect)); - if (!pc) - return NULL; - - memset(pc, 0, sizeof(struct pending_connect)); - bacpy(&pc->src, src); - bacpy(&pc->dst, dst); - pc->conn = dbus_connection_ref(conn); - pc->msg = dbus_message_ref(msg); - - return pc; -} - -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - free(pc); -} - /* * Common D-Bus BlueZ input error functions */ @@ -573,18 +559,14 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_connect *pc) +static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, + struct input_device *idev) { - struct input_device *idev; struct fake_input *fake; DBusMessage *reply; - const char *path; socklen_t len; int ret, err; - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); fake = idev->fake; if (cond & G_IO_NVAL) { @@ -628,24 +610,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); - reply = dbus_message_new_method_return(pc->msg); + reply = dbus_message_new_method_return(idev->pending_connect->msg); if (reply) { dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } -static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) +static int rfcomm_connect(struct input_device *idev) { struct sockaddr_rc addr; GIOChannel *io; @@ -669,7 +654,7 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->src); + bacpy(&addr.rc_bdaddr, &idev->src); addr.rc_channel = 0; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { @@ -686,8 +671,8 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->dst); - addr.rc_channel = ch; + bacpy(&addr.rc_bdaddr, &idev->dst); + addr.rc_channel = idev->fake->ch; if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { char peer[18]; /* FIXME: debug purpose */ if (!(errno == EAGAIN || errno == EINPROGRESS)) { @@ -697,13 +682,13 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) goto failed; } - ba2str(&pc->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, ch); + ba2str(&idev->dst, peer); + debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, pc); + (GIOFunc) rfcomm_connect_cb, idev); } else { debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, pc); + rfcomm_connect_cb(io, G_IO_OUT, idev); } return 0; @@ -718,8 +703,8 @@ failed: return -err; } -static int l2cap_connect(struct pending_connect *pc, - unsigned short psm, GIOFunc cb) +static int l2cap_connect(struct input_device *idev, + unsigned short psm, GIOFunc cb) { GIOChannel *io; struct sockaddr_l2 addr; @@ -731,7 +716,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->src); + bacpy(&addr.l2_bdaddr, &idev->src); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; @@ -749,7 +734,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->dst); + bacpy(&addr.l2_bdaddr, &idev->dst); addr.l2_psm = htobs(psm); io = g_io_channel_unix_new(sk); @@ -759,9 +744,9 @@ static int l2cap_connect(struct pending_connect *pc, if (!(errno == EAGAIN || errno == EINPROGRESS)) goto failed; - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); + g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, idev); } else { - cb(io, G_IO_OUT, pc); + cb(io, G_IO_OUT, idev); } return 0; @@ -775,15 +760,10 @@ failed: } static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ctl, isk, ret, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -816,7 +796,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&pc->src, &pc->dst); + err = encrypt_link(&idev->src, &idev->dst); if (err < 0) { close(ctl); goto failed; @@ -830,13 +810,14 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } - send_message_and_unref(pc->conn, - dbus_message_new_method_return(pc->msg)); + send_message_and_unref(idev->pending_connect->conn, + dbus_message_new_method_return(idev->pending_connect->msg)); close (ctl); goto cleanup; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); cleanup: if (isk > 0) @@ -847,22 +828,18 @@ cleanup: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ret, csk, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -888,7 +865,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, } /* Connect to the HID interrupt channel */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_INTR, (GIOFunc) interrupt_connect_cb) < 0) { err = errno; @@ -904,8 +881,10 @@ failed: close(csk); idev->hidp.ctrl_sock = -1; - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; @@ -970,7 +949,7 @@ fail: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - return -errno; + return -err; } static int is_connected(struct input_device *idev) @@ -1014,36 +993,41 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; - struct fake_input *fake = idev->fake; - struct input_manager *mgr; - struct pending_connect *pc; + + if (idev->pending_connect) + return err_connection_failed(conn, msg, "Connection in progress"); if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); - /* FIXME: Check if there is a pending connection */ - - dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); - if (!pc) + idev->pending_connect = malloc(sizeof(struct pending_connect)); + if (!idev->pending_connect) { + error("Out of memory when allocating new struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + memset(idev->pending_connect, 0, sizeof(struct pending_connect)); + idev->pending_connect->conn = dbus_connection_ref(conn); + idev->pending_connect->msg = dbus_message_ref(msg); /* Fake input device */ - if (fake) { - if (rfcomm_connect(pc, fake->ch) < 0) { + if (idev->fake) { + if (rfcomm_connect(idev) < 0) { const char *str = strerror(errno); error("RFCOMM connect failed: %s(%d)", str, errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, str); } return DBUS_HANDLER_RESULT_HANDLED; } /* HID devices */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb) < 0) { error("L2CAP connect failed: %s(%d)", strerror(errno), errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, strerror(errno)); } @@ -1422,7 +1406,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) @@ -1656,7 +1640,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); if (!idev) { error("Out of memory when allocating new input"); goto fail; @@ -1776,7 +1760,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_not_supported(conn, msg); } - idev = input_device_new(&dst, cls); + idev = input_device_new(&mgr->src, &dst, cls); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1958,7 +1942,7 @@ static void stored_input(char *key, char *value, void *data) if (get_class(src, &dst, &cls) < 0) return; - idev = input_device_new(&dst, cls); + idev = input_device_new(src, &dst, cls); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; -- cgit From acfdab3a74249dc4e04078523a7fd10fd6fe4d5d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 28 Feb 2007 12:31:25 +0000 Subject: Input: Using glib memory alloc functions --- input/device.c | 57 ++++++++++++++++++++------------------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 816342c0..a3e4d7de 100644 --- a/input/device.c +++ b/input/device.c @@ -113,11 +113,7 @@ static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint3 { struct input_device *idev; - idev = malloc(sizeof(struct input_device)); - if (!idev) - return NULL; - - memset(idev, 0, sizeof(struct input_device)); + idev = g_new0(struct input_device, 1); bacpy(&idev->src, src); bacpy(&idev->dst, dst); @@ -136,7 +132,7 @@ static void pending_connect_free(struct pending_connect *pc) dbus_connection_unref(pc->conn); if (pc->msg) dbus_message_unref(pc->msg); - free(pc); + g_free(pc); } static void input_device_free(struct input_device *idev) @@ -144,13 +140,13 @@ static void input_device_free(struct input_device *idev) if (!idev) return; if (idev->hidp.rd_data) - free(idev->hidp.rd_data); + g_free(idev->hidp.rd_data); if (idev->fake) - free(idev->fake); + g_free(idev->fake); if (idev->pending_connect) pending_connect_free(idev->pending_connect); - free(idev); + g_free(idev); } static struct pending_req *pending_req_new(DBusConnection *conn, @@ -158,12 +154,11 @@ static struct pending_req *pending_req_new(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst) { struct pending_req *pr; - pr = malloc(sizeof(struct pending_req)); + pr = g_try_new0(struct pending_req, 1); if (!pr) return NULL; - memset(pr, 0, sizeof(struct pending_req)); - pr->adapter_path = strdup(adapter_path); + pr->adapter_path = g_strdup(adapter_path); bacpy(&pr->src, src); bacpy(&pr->dst, dst); pr->conn = dbus_connection_ref(conn); @@ -177,7 +172,7 @@ static void pending_req_free(struct pending_req *pr) if (!pr) return; if (pr->adapter_path) - free(pr->adapter_path); + g_free(pr->adapter_path); if (pr->conn) dbus_connection_unref(pr->conn); if (pr->msg) @@ -186,7 +181,7 @@ static void pending_req_free(struct pending_req *pr) sdp_record_free(pr->pnp_rec); if (pr->hid_rec) sdp_record_free(pr->hid_rec); - free(pr); + g_free(pr); } /* @@ -304,7 +299,7 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) pdlist = pdlist->val.dataseq; pdlist = pdlist->next; - req->rd_data = malloc(pdlist->unitSize); + req->rd_data = g_try_malloc0(pdlist->unitSize); if (req->rd_data) { memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); req->rd_size = pdlist->unitSize; @@ -1000,13 +995,12 @@ static DBusHandlerResult device_connect(DBusConnection *conn, if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); - idev->pending_connect = malloc(sizeof(struct pending_connect)); + idev->pending_connect = g_try_new0(struct pending_connect, 1); if (!idev->pending_connect) { error("Out of memory when allocating new struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; } - memset(idev->pending_connect, 0, sizeof(struct pending_connect)); idev->pending_connect->conn = dbus_connection_ref(conn); idev->pending_connect->msg = dbus_message_ref(msg); @@ -1207,7 +1201,7 @@ static void input_manager_free(struct input_manager *mgr) g_slist_free(mgr->paths); } - free(mgr); + g_free(mgr); } static int register_input_device(DBusConnection *conn, @@ -1223,7 +1217,7 @@ static int register_input_device(DBusConnection *conn, } dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - mgr->paths = g_slist_append(mgr->paths, strdup(path)); + mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); @@ -1322,11 +1316,11 @@ static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) return -ENOENT; if (sscanf(str, "%x", cls) != 1) { - free(str); + g_free(str); return -ENOENT; } - free(str); + g_free(str); return 0; } @@ -1641,18 +1635,8 @@ static void headset_record_reply(DBusPendingCall *call, void *data) } idev = input_device_new(&pr->src, &pr->dst, cls); - if (!idev) { - error("Out of memory when allocating new input"); - goto fail; - } - idev->fake = malloc(sizeof(struct fake_input)); - if (!idev->fake) { - error("Out of memory when allocating new fake input"); - input_device_free(idev); - goto fail; - } - memset(idev->fake, 0, sizeof(struct fake_input)); + idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; /* FIXME: Store the fake input data */ @@ -1761,8 +1745,6 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, } idev = input_device_new(&mgr->src, &dst, cls); - if (!idev) - return DBUS_HANDLER_RESULT_NEED_MEMORY; if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { struct pending_req *pr; @@ -1852,7 +1834,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn, return err_failed(conn, msg, "D-Bus path unregistration failed"); } - free(l->data); + g_free(l->data); mgr->paths = g_slist_remove(mgr->paths, l->data); return send_message_and_unref(conn, reply); @@ -1943,6 +1925,7 @@ static void stored_input(char *key, char *value, void *data) return; idev = input_device_new(src, &dst, cls); + if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; @@ -1977,8 +1960,8 @@ int input_dbus_init(void) dbus_connection_set_exit_on_disconnect(connection, TRUE); - mgr = malloc(sizeof(struct input_manager)); - memset(mgr, 0, sizeof(struct input_manager)); + mgr = g_new0(struct input_manager, 1); + /* Fallback to catch invalid device path */ if (!dbus_connection_register_fallback(connection, INPUT_PATH, &manager_table, mgr)) { -- cgit From bf2f0ef935869db6d1c6e4ea26ee8133b42b49b6 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 28 Feb 2007 16:39:34 +0000 Subject: Input: code cleanup --- input/device.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index a3e4d7de..94122554 100644 --- a/input/device.c +++ b/input/device.c @@ -274,26 +274,26 @@ static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) strncpy(req->name, pdlist2->val.str, 127); } - pdlist = sdp_data_get(rec, 0x0201); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - pdlist = sdp_data_get(rec, 0x0202); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); req->subclass = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, 0x0203); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); req->country = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, 0x0204); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE); attr_val = pdlist ? pdlist->val.uint8 : 0; if (attr_val) req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); - pdlist = sdp_data_get(rec, 0x020E); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE); attr_val = pdlist ? pdlist->val.uint8 : 0; if (attr_val) req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); - pdlist = sdp_data_get(rec, 0x0206); + pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); if (pdlist) { pdlist = pdlist->val.dataseq; pdlist = pdlist->val.dataseq; @@ -311,13 +311,13 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist; - pdlist = sdp_data_get(rec, 0x0201); + pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; - pdlist = sdp_data_get(rec, 0x0202); + pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); req->product = pdlist ? pdlist->val.uint16 : 0x0000; - pdlist = sdp_data_get(rec, 0x0203); + pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -- cgit From fd660e28020d6b26f8fe49c0a87545f04e981fa9 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 Mar 2007 11:40:20 +0000 Subject: Input: renamed input storage file to "input" --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 94122554..6e701862 100644 --- a/input/device.c +++ b/input/device.c @@ -1942,7 +1942,7 @@ static int register_stored_inputs(bdaddr_t *src) char addr[18]; ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); + create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); textfile_foreach(filename, stored_input, src); return 0; -- cgit From 3f27f7f7a01ad43532b65504e6204194e3e259df Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 1 Mar 2007 14:10:10 +0000 Subject: Input: Use stored device name instead of the service name attribute --- input/device.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 6e701862..2d05d264 100644 --- a/input/device.c +++ b/input/device.c @@ -85,8 +85,9 @@ struct pending_connect { }; struct input_device { - bdaddr_t src; - bdaddr_t dst; + bdaddr_t src; + bdaddr_t dst; + char *name; uint8_t major; uint8_t minor; struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ @@ -121,6 +122,11 @@ static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint3 idev->major = (cls >> 8) & 0x1f; idev->minor = (cls >> 2) & 0x3f; + read_device_name(src, dst, &idev->name); + + /* FIXME: hidp could be alloc dynamically */ + snprintf(idev->hidp.name, 128, "%s", idev->name); + return idev; } @@ -139,6 +145,8 @@ static void input_device_free(struct input_device *idev) { if (!idev) return; + if (idev->name) + g_free(idev->name); if (idev->hidp.rd_data) g_free(idev->hidp.rd_data); if (idev->fake) @@ -594,7 +602,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, * first to report volume gain key events */ - fake->uinput = uinput_create("Fake input"); + fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { err = errno; goto failed; -- cgit From d53935995279d96e4a2f973d11d3a3ba3d9c9bfc Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 5 Mar 2007 20:10:35 +0000 Subject: Input: added extra GIOConditon(HUP, ERR and NVAL) for watches --- input/device.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 2d05d264..0e182224 100644 --- a/input/device.c +++ b/input/device.c @@ -747,7 +747,8 @@ static int l2cap_connect(struct input_device *idev, if (!(errno == EAGAIN || errno == EINPROGRESS)) goto failed; - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, idev); + 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); } @@ -774,6 +775,14 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, 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); idev->hidp.intr_sock = isk; idev->hidp.idle_to = 30 * 60; /* 30 minutes */ @@ -850,6 +859,14 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, 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 */ idev->hidp.ctrl_sock = csk; -- cgit From 6752c3025ac9320ae2b60f5eba1f64205a7f6b78 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 6 Mar 2007 19:33:02 +0000 Subject: Input: useless code removed, stored devices are always created when the daemon initializes --- input/device.c | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 0e182224..72bab4c0 100644 --- a/input/device.c +++ b/input/device.c @@ -601,7 +601,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, * FIXME: Some headsets required a sco connection * first to report volume gain key events */ - fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { err = errno; @@ -1735,11 +1734,10 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_manager *mgr = data; - struct input_device *idev; - DBusMessage *reply; + struct pending_req *pr; DBusError derr; char adapter[18], adapter_path[32]; - const char *addr, *path; + const char *addr; GSList *l; bdaddr_t dst; uint32_t cls = 0; @@ -1769,18 +1767,11 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_not_supported(conn, msg); } - idev = input_device_new(&mgr->src, &dst, cls); - - if (get_stored_device_info(&mgr->src, &idev->dst, &idev->hidp) < 0) { - struct pending_req *pr; - /* Data not found: create the input device later */ - input_device_free(idev); - - pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); - if (!pr) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); + if (!pr) + return DBUS_HANDLER_RESULT_NEED_MEMORY; - switch (cls & 0x1f00) { + switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { pending_req_free(pr); @@ -1797,28 +1788,9 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, default: pending_req_free(pr); return err_not_supported(conn, msg); - } - - return DBUS_HANDLER_RESULT_HANDLED; - } - - path = create_input_path(idev->major, idev->minor); - if (register_input_device(conn, idev, path) < 0) { - input_device_free(idev); - return err_failed(conn, msg, "D-Bus path registration failed"); - } - - reply = dbus_message_new_method_return(msg); - if (!reply) { - input_device_free(idev); - return DBUS_HANDLER_RESULT_NEED_MEMORY; } - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult manager_remove_device(DBusConnection *conn, -- cgit From 6e3cd312032917facce3e8ef35812b713c16db2b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 9 Mar 2007 15:31:27 +0000 Subject: Fix not result checking warning --- input/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 72bab4c0..fb1e5e5d 100644 --- a/input/device.c +++ b/input/device.c @@ -497,13 +497,14 @@ static int decode_key(const char *str) static void send_event(int fd, uint16_t type, uint16_t code, int32_t value) { struct uinput_event event; + int err; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; - write(fd, &event, sizeof(event)); + err = write(fd, &event, sizeof(event)); } static void send_key(int fd, uint16_t key) -- cgit From f2c6a6f2debcccfb51d239834c3cf91a2c3a6c40 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 14:58:44 +0000 Subject: Moving input functions to the right files --- input/device.c | 1011 +++----------------------------------------------------- 1 file changed, 49 insertions(+), 962 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index fb1e5e5d..8488b406 100644 --- a/input/device.c +++ b/input/device.c @@ -34,12 +34,8 @@ #include #include -#include -#include #include #include -#include -#include #include #include @@ -52,12 +48,11 @@ #include "uinput.h" #include "storage.h" +#include "error.h" +#include "manager.h" #include "device.h" -#define INPUT_PATH "/org/bluez/input" -#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" -#define INPUT_ERROR_INTERFACE "org.bluez.Error" #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 @@ -66,12 +61,6 @@ #define UPDOWN_ENABLED 1 -static DBusConnection *connection = NULL; - -const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; -const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; -const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; - struct fake_input { GIOChannel *io; int rfcomm; /* RFCOMM socket */ @@ -95,35 +84,22 @@ struct input_device { struct pending_connect *pending_connect; }; -struct input_manager { - bdaddr_t src; /* Local adapter BT address */ - GSList *paths; /* Input registered paths */ -}; - -struct pending_req { - char *adapter_path; /* Local adapter D-Bus path */ - bdaddr_t src; /* Local adapter BT address */ - bdaddr_t dst; /* Peer BT address */ - DBusConnection *conn; - DBusMessage *msg; - sdp_record_t *pnp_rec; - sdp_record_t *hid_rec; -}; - -static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint32_t cls) +static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst) { struct input_device *idev; + uint32_t cls; idev = g_new0(struct input_device, 1); bacpy(&idev->src, src); bacpy(&idev->dst, dst); + read_device_name(src, dst, &idev->name); + read_device_class(src, dst, &cls); + idev->major = (cls >> 8) & 0x1f; idev->minor = (cls >> 2) & 0x3f; - read_device_name(src, dst, &idev->name); - /* FIXME: hidp could be alloc dynamically */ snprintf(idev->hidp.name, 128, "%s", idev->name); @@ -157,178 +133,6 @@ static void input_device_free(struct input_device *idev) g_free(idev); } -static struct pending_req *pending_req_new(DBusConnection *conn, - DBusMessage *msg, const char *adapter_path, - bdaddr_t *src, bdaddr_t *dst) -{ - struct pending_req *pr; - pr = g_try_new0(struct pending_req, 1); - if (!pr) - return NULL; - - pr->adapter_path = g_strdup(adapter_path); - bacpy(&pr->src, src); - bacpy(&pr->dst, dst); - pr->conn = dbus_connection_ref(conn); - pr->msg = dbus_message_ref(msg); - - return pr; -} - -static void pending_req_free(struct pending_req *pr) -{ - if (!pr) - return; - if (pr->adapter_path) - g_free(pr->adapter_path); - if (pr->conn) - dbus_connection_unref(pr->conn); - if (pr->msg) - dbus_message_unref(pr->msg); - if (pr->pnp_rec) - sdp_record_free(pr->pnp_rec); - if (pr->hid_rec) - sdp_record_free(pr->hid_rec); - g_free(pr); -} - -/* - * Common D-Bus BlueZ input error functions - */ -static DBusHandlerResult err_unknown_device(DBusConnection *conn, DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".UnknownDevice", - "Invalid device")); -} - -static DBusHandlerResult err_unknown_method(DBusConnection *conn, DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".UnknownMethod", - "Unknown input method")); -} - -static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg, - const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".Failed", str)); -} - -static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".NotSupported", - "The service is not supported by the remote device")); -} - -static DBusHandlerResult err_connection_failed(DBusConnection *conn, - DBusMessage *msg, const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE".ConnectionAttemptFailed", - str)); -} - -static DBusHandlerResult err_already_exists(DBusConnection *conn, - DBusMessage *msg, const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".AlreadyExists", str)); -} - -static DBusHandlerResult err_does_not_exist(DBusConnection *conn, - DBusMessage *msg, const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, - INPUT_ERROR_INTERFACE ".DoesNotExist", str)); -} - -static DBusHandlerResult err_generic(DBusConnection *conn, DBusMessage *msg, - const char *name, const char *str) -{ - return send_message_and_unref(conn, - dbus_message_new_error(msg, name, str)); - -} - -static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) -{ - sdp_data_t *pdlist, *pdlist2; - uint8_t attr_val; - - pdlist = sdp_data_get(rec, 0x0101); - pdlist2 = sdp_data_get(rec, 0x0102); - if (pdlist) { - if (pdlist2) { - if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { - strncpy(req->name, pdlist2->val.str, 127); - strcat(req->name, " "); - } - strncat(req->name, pdlist->val.str, 127 - strlen(req->name)); - } else - strncpy(req->name, pdlist->val.str, 127); - } else { - pdlist2 = sdp_data_get(rec, 0x0100); - if (pdlist2) - strncpy(req->name, pdlist2->val.str, 127); - } - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); - req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); - req->subclass = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); - req->country = pdlist ? pdlist->val.uint8 : 0; - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE); - attr_val = pdlist ? pdlist->val.uint8 : 0; - if (attr_val) - req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE); - attr_val = pdlist ? pdlist->val.uint8 : 0; - if (attr_val) - req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); - if (pdlist) { - pdlist = pdlist->val.dataseq; - pdlist = pdlist->val.dataseq; - pdlist = pdlist->next; - - req->rd_data = g_try_malloc0(pdlist->unitSize); - if (req->rd_data) { - memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); - req->rd_size = pdlist->unitSize; - } - } -} - -static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) -{ - sdp_data_t *pdlist; - - pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); - req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); - req->product = pdlist ? pdlist->val.uint16 : 0x0000; - - pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); - req->version = pdlist ? pdlist->val.uint16 : 0x0000; -} - static int uinput_create(char *name) { struct uinput_dev dev; @@ -615,7 +419,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, reply = dbus_message_new_method_return(idev->pending_connect->msg); if (reply) { - dbus_connection_send(connection, reply, NULL); + dbus_connection_send(idev->pending_connect->conn, reply, NULL); dbus_message_unref(reply); } @@ -1199,12 +1003,16 @@ static DBusHandlerResult device_message(DBusConnection *conn, if (strcmp(member, "SetTimeout") == 0) return device_set_timeout(conn, msg, data); - return err_unknown_method(conn, msg); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void device_unregister(DBusConnection *conn, void *data) { - input_device_free(data); + struct input_device *idev = data; + + /* Disconnect if applied */ + disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); + input_device_free(idev); } /* Virtual table to handle device object path hierarchy */ @@ -1214,819 +1022,98 @@ static const DBusObjectPathVTable device_table = { }; /* - * Input Manager methods + * Input registration functions */ -static void input_manager_free(struct input_manager *mgr) +int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, + struct hidp_connadd_req *hid, const char **path) { - if (!mgr) - return; + DBusMessage *msg; + struct input_device *idev; - if (mgr->paths) { - g_slist_foreach(mgr->paths, (GFunc) free, NULL); - g_slist_free(mgr->paths); - } + idev = input_device_new(src, dst); + *path = create_input_path(idev->major, idev->minor); - g_free(mgr); -} + memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); -static int register_input_device(DBusConnection *conn, - struct input_device *idev, const char *path) -{ - DBusMessage *msg; - struct input_manager *mgr; + /* FIXME: rd_data is a pointer - hacking */ if (!dbus_connection_register_object_path(conn, - path, &device_table, idev)) { + *path, &device_table, idev)) { error("Input device path registration failed"); return -1; } - dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - mgr->paths = g_slist_append(mgr->paths, g_strdup(path)); - msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) return -1; dbus_message_append_args(msg, - DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &*path, DBUS_TYPE_INVALID); send_message_and_unref(conn, msg); - info("Created input device: %s", path); + info("Created input device: %s", *path); return 0; } -static int unregister_input_device(DBusConnection *conn, const char *path) +int fake_input_register(DBusConnection *conn, bdaddr_t *src, + bdaddr_t *dst, uint8_t ch, const char **path) { DBusMessage *msg; + struct input_device *idev; - if (!dbus_connection_unregister_object_path(conn, path)) { - error("Input device path unregister failed"); + idev = input_device_new(src, dst); + *path = create_input_path(idev->major, idev->minor); + + idev->fake = g_new0(struct fake_input, 1); + idev->fake->ch = ch; + + if (!dbus_connection_register_object_path(conn, + *path, &device_table, idev)) { + error("Fake input device path registration failed"); return -1; } + /* FIXME: dupplicated code */ msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceRemoved"); + INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) return -1; dbus_message_append_args(msg, - DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &*path, DBUS_TYPE_INVALID); send_message_and_unref(conn, msg); - return 0; -} - -static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr) -{ - struct input_device *idev; + info("Created input device: %s", *path); - if (!dbus_connection_get_object_path_data(connection, path, - (void *) &idev)) - return -1; - - if (!idev) - return -1; + return 0; - return bacmp(&idev->dst, bdaddr); } -static int get_record(struct pending_req *pr, uint32_t handle, - DBusPendingCallNotifyFunction cb) +int input_device_unregister(DBusConnection *conn, const char *path) { DBusMessage *msg; - DBusPendingCall *pending; - char addr[18]; - const char *paddr = addr; - - msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, - "org.bluez.Adapter", "GetRemoteServiceRecord"); - if (!msg) - return -1; - ba2str(&pr->dst, addr); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { - error("Can't send D-Bus message."); + if (!dbus_connection_unregister_object_path(conn, path)) { + error("Input device path unregister failed"); return -1; } - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_message_unref(msg); - - return 0; -} - -static int get_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls) -{ - char filename[PATH_MAX + 1], *str; - char addr[18]; - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "classes"); - - ba2str(dst, addr); - str = textfile_get(filename, addr); - if (!str) - return -ENOENT; - - if (sscanf(str, "%x", cls) != 1) { - g_free(str); - return -ENOENT; - } - - g_free(str); - - return 0; -} - -static int get_handles(struct pending_req *pr, const char *uuid, - DBusPendingCallNotifyFunction cb) -{ - DBusMessage *msg; - DBusPendingCall *pending; - char addr[18]; - const char *paddr = addr; - - msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, - "org.bluez.Adapter", "GetRemoteServiceHandles"); + msg = dbus_message_new_signal(INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved"); if (!msg) return -1; - ba2str(&pr->dst, addr); dbus_message_append_args(msg, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { - error("Can't send D-Bus message."); - return -1; - } - - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_message_unref(msg); - - return 0; -} - -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 input_device *idev; - DBusError derr; - uint8_t *rec_bin; - const char *path; - int len, scanned; - uint32_t cls; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - err_not_supported(pr->conn, pr->msg); - error("Invalid HID service record length"); - goto fail; - } - - pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); - if (!pr->hid_rec) { - err_not_supported(pr->conn, pr->msg); - goto fail; - } - - if (get_class(&pr->src, &pr->dst, &cls) < 0) { - err_not_supported(pr->conn, pr->msg); - error("Device class not available"); - goto fail; - } - - idev = input_device_new(&pr->src, &pr->dst, cls); - - extract_hid_record(pr->hid_rec, &idev->hidp); - if (pr->pnp_rec) - extract_pnp_record(pr->pnp_rec, &idev->hidp); - - path = create_input_path(idev->major, idev->minor); - - if (register_input_device(pr->conn, idev, path) < 0) { - err_failed(pr->conn, pr->msg, "D-Bus path registration failed"); - input_device_free(idev); - goto fail; - } - - 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); - - store_device_info(&pr->src, &pr->dst, &idev->hidp); -fail: - dbus_error_free(&derr); - pending_req_free(pr); - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static void hid_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - uint32_t *phandle; - DBusError derr; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - err_not_supported(pr->conn, pr->msg); - error("HID record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, hid_record_reply) < 0) { - err_not_supported(pr->conn, pr->msg); - error("HID service attribute request failed"); - goto fail; - } else { - /* Wait record reply */ - goto done; - } -fail: - dbus_error_free(&derr); - pending_req_free(pr); -done: - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static void pnp_record_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint8_t *rec_bin; - int len, scanned; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - if (len == 0) { - err_not_supported(pr->conn, pr->msg); - error("Invalid PnP service record length"); - goto fail; - } - - pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { - err_not_supported(pr->conn, pr->msg); - error("HID service search request failed"); - goto fail; - } else { - /* Wait handle reply */ - goto done; - } - -fail: - dbus_error_free(&derr); - pending_req_free(pr); -done: - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static void pnp_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint32_t *phandle; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - /* PnP is optional: Ignore it and request the HID handle */ - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { - err_not_supported(pr->conn, pr->msg); - error("HID service search request failed"); - goto fail; - } - } else { - /* Request PnP record */ - if (get_record(pr, *phandle, pnp_record_reply) < 0) { - err_not_supported(pr->conn, pr->msg); - error("PnP service attribute request failed"); - goto fail; - } - } - - /* Wait HID handle reply or PnP record reply */ - goto done; - -fail: - dbus_error_free(&derr); - pending_req_free(pr); -done: - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static void headset_record_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusMessage *pr_reply; - DBusError derr; - struct pending_req *pr = data; - struct input_device *idev; - uint8_t *rec_bin; - sdp_record_t *rec; - sdp_list_t *protos; - const char *path; - int len, scanned; - uint32_t cls; - uint8_t ch; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - err_not_supported(pr->conn, pr->msg); - error("Invalid headset service record length"); - goto fail; - } - - rec = sdp_extract_pdu(rec_bin, &scanned); - if (!rec) { - err_not_supported(pr->conn, pr->msg); - goto fail; - } - - if (sdp_get_access_protos(rec, &protos) < 0) { - err_not_supported(pr->conn, pr->msg); - goto fail; - } - - ch = sdp_get_proto_port(protos, RFCOMM_UUID); - sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL); - sdp_list_free(protos, NULL); - sdp_record_free(rec); - - if (ch <= 0) { - err_not_supported(pr->conn, pr->msg); - error("Invalid RFCOMM channel"); - goto fail; - } - - if (get_class(&pr->src, &pr->dst, &cls) < 0) { - err_not_supported(pr->conn, pr->msg); - error("Device class not available"); - goto fail; - } - - idev = input_device_new(&pr->src, &pr->dst, cls); - - idev->fake = g_new0(struct fake_input, 1); - idev->fake->ch = ch; - - /* FIXME: Store the fake input data */ - - path = create_input_path(idev->major, idev->minor); - if (register_input_device(pr->conn, idev, path) < 0) { - error("D-Bus path registration failed:%s", path); - err_failed(pr->conn, pr->msg, "Path registration failed"); - input_device_free(idev); - goto fail; - } - - 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); -fail: - dbus_error_free(&derr); - pending_req_free(pr); - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static void headset_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint32_t *phandle; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - err_generic(pr->conn, pr->msg, derr.name, derr.message); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - err_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - err_not_supported(pr->conn, pr->msg); - error("Headset record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, headset_record_reply) < 0) { - err_not_supported(pr->conn, pr->msg); - error("Headset service attribute request failed"); - goto fail; - } else { - /* Wait record reply */ - goto done; - } -fail: - dbus_error_free(&derr); - pending_req_free(pr); -done: - dbus_message_unref(reply); - dbus_pending_call_unref(call); -} - -static DBusHandlerResult manager_create_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_manager *mgr = data; - struct pending_req *pr; - DBusError derr; - char adapter[18], adapter_path[32]; - const char *addr; - GSList *l; - bdaddr_t dst; - uint32_t cls = 0; - int dev_id; - - dbus_error_init(&derr); - if (!dbus_message_get_args(msg, &derr, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_INVALID)) { - err_generic(conn, msg, derr.name, derr.message); - dbus_error_free(&derr); - return DBUS_HANDLER_RESULT_HANDLED; - } - - str2ba(addr, &dst); - l = g_slist_find_custom(mgr->paths, &dst, - (GCompareFunc) path_bdaddr_cmp); - if (l) - return err_already_exists(conn, msg, "Input Already exists"); - - ba2str(&mgr->src, adapter); - dev_id = hci_devid(adapter); - snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id); - - if (get_class(&mgr->src, &dst, &cls) < 0) { - error("Device class not available"); - return err_not_supported(conn, msg); - } - - pr = pending_req_new(conn, msg, adapter_path, &mgr->src, &dst); - if (!pr) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - switch (cls & 0x1f00) { - case 0x0500: /* Peripheral */ - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { - pending_req_free(pr); - return err_not_supported(conn, msg); - } - break; - case 0x0400: /* Fake input */ - if (get_handles(pr, headset_uuid, - headset_handle_reply) < 0) { - pending_req_free(pr); - return err_not_supported(conn, msg); - } - break; - default: - pending_req_free(pr); - return err_not_supported(conn, msg); - } - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult manager_remove_device(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_manager *mgr = data; - struct input_device *idev; - DBusMessage *reply; - DBusError derr; - GSList *l; - const char *path; - - dbus_error_init(&derr); - if (!dbus_message_get_args(msg, &derr, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID)) { - err_generic(conn, msg, derr.name, derr.message); - dbus_error_free(&derr); - return DBUS_HANDLER_RESULT_HANDLED; - } - - l = g_slist_find_custom(mgr->paths, path, (GCompareFunc) strcmp); - if (!l) - return err_does_not_exist(conn, msg, "Input doesn't exist"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - /* Try disconnect */ - if (dbus_connection_get_object_path_data(conn, path, (void *) &idev) && idev) - disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - - del_stored_device_info(&mgr->src, &idev->dst); - - if (unregister_input_device(conn, path) < 0) { - dbus_message_unref(reply); - return err_failed(conn, msg, "D-Bus path unregistration failed"); - } - - g_free(l->data); - mgr->paths = g_slist_remove(mgr->paths, l->data); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult manager_list_devices(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct input_manager *mgr = data; - DBusMessageIter iter, iter_array; - DBusMessage *reply; - GSList *paths; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_iter_init_append(reply, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &iter_array); - - for (paths = mgr->paths; paths != NULL; paths = paths->next) { - const char *ppath = paths->data; - dbus_message_iter_append_basic(&iter_array, - DBUS_TYPE_STRING, &ppath); - } - - dbus_message_iter_close_container(&iter, &iter_array); - - return send_message_and_unref(conn, reply); -} - -static DBusHandlerResult manager_message(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *path, *iface, *member; - - path = dbus_message_get_path(msg); - iface = dbus_message_get_interface(msg); - member = dbus_message_get_member(msg); - - /* Catching fallback paths */ - if (strcmp(INPUT_PATH, path) != 0) - return err_unknown_device(conn, msg); - - /* Accept messages from the input manager interface only */ - if (strcmp(INPUT_MANAGER_INTERFACE, iface)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (strcmp(member, "ListDevices") == 0) - return manager_list_devices(conn, msg, data); - - if (strcmp(member, "CreateDevice") == 0) - return manager_create_device(conn, msg, data); - - if (strcmp(member, "RemoveDevice") == 0) - return manager_remove_device(conn, msg, data); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void manager_unregister(DBusConnection *conn, void *data) -{ - struct input_manager *mgr = data; - - info("Unregistered manager path"); - - input_manager_free(mgr); -} - -/* Virtual table to handle manager object path hierarchy */ -static const DBusObjectPathVTable manager_table = { - .message_function = manager_message, - .unregister_function = manager_unregister, -}; - -static void stored_input(char *key, char *value, void *data) -{ - bdaddr_t *src = data; - struct input_device *idev; - const char *path; - bdaddr_t dst; - uint32_t cls; - - str2ba(key, &dst); - - if (get_class(src, &dst, &cls) < 0) - return; - - idev = input_device_new(src, &dst, cls); - - if (parse_stored_device_info(value, &idev->hidp) < 0) { - input_device_free(idev); - return; - } - - path = create_input_path(idev->major, idev->minor); - if (register_input_device(connection, idev, path) < 0) - input_device_free(idev); -} - -static int register_stored_inputs(bdaddr_t *src) -{ - char filename[PATH_MAX + 1]; - char addr[18]; - - ba2str(src, addr); - create_name(filename, PATH_MAX, STORAGEDIR, addr, "input"); - textfile_foreach(filename, stored_input, src); - - return 0; -} - -int input_dbus_init(void) -{ - struct input_manager *mgr; - bdaddr_t src; - int dev_id; - - connection = init_dbus(NULL, NULL, NULL); - if (!connection) - return -1; - - dbus_connection_set_exit_on_disconnect(connection, TRUE); - - mgr = g_new0(struct input_manager, 1); - - /* Fallback to catch invalid device path */ - if (!dbus_connection_register_fallback(connection, INPUT_PATH, - &manager_table, mgr)) { - error("D-Bus failed to register %s path", INPUT_PATH); - goto fail; - } - - info("Registered input manager path:%s", INPUT_PATH); - - /* Set the default adapter */ - bacpy(&src, BDADDR_ANY); - dev_id = hci_get_route(&src); - if (dev_id < 0) { - error("Bluetooth device not available"); - goto fail; - } - - if (hci_devba(dev_id, &src) < 0) { - error("Can't get local adapter device info"); - goto fail; - } - - bacpy(&mgr->src, &src); - /* Register well known HID devices */ - register_stored_inputs(&src); + send_message_and_unref(conn, msg); return 0; - -fail: - input_manager_free(mgr); - - return -1; -} - -void input_dbus_exit(void) -{ - dbus_connection_unregister_object_path(connection, INPUT_PATH); - - dbus_connection_unref(connection); -} - -void internal_service(const char *identifier) -{ - DBusMessage *msg, *reply; - const char *name = "Input Service Debug", *desc = ""; - - info("Registering service"); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", "RegisterService"); - if (!msg) { - error("Can't create service register method"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &identifier, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID); - - reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, NULL); - if (!reply) { - error("Can't register service"); - return; - } - - dbus_message_unref(msg); - dbus_message_unref(reply); - - dbus_connection_flush(connection); } -- cgit From a798bf638f53dacb92d23265a0d228886e8bd5f0 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 15:07:03 +0000 Subject: input: handling encrypt_link function return value properly --- input/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 8488b406..8f255fd7 100644 --- a/input/device.c +++ b/input/device.c @@ -612,8 +612,10 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&idev->src, &idev->dst); - if (err < 0) { + int ret; + ret = encrypt_link(&idev->src, &idev->dst); + if (ret < 0) { + err = -ret; close(ctl); goto failed; } -- cgit From d307da66278af3505e2bb1a35de4ef2ccefb9a6d Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 19 Mar 2007 15:17:15 +0000 Subject: input: moving "struct input_device" to device.h --- input/device.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 8f255fd7..7e7325fb 100644 --- a/input/device.c +++ b/input/device.c @@ -61,29 +61,6 @@ #define UPDOWN_ENABLED 1 -struct fake_input { - GIOChannel *io; - int rfcomm; /* RFCOMM socket */ - int uinput; /* uinput socket */ - uint8_t ch; /* RFCOMM channel number */ -}; - -struct pending_connect { - DBusConnection *conn; - DBusMessage *msg; -}; - -struct input_device { - bdaddr_t src; - bdaddr_t dst; - char *name; - uint8_t major; - uint8_t minor; - struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ - struct fake_input *fake; - struct pending_connect *pending_connect; -}; - static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst) { struct input_device *idev; -- cgit From aa2c3ce4dcbbe498216407141479e20410d55b77 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 14:40:19 +0000 Subject: input: code cleanup --- input/device.c | 74 +++++++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 7e7325fb..5f70ede1 100644 --- a/input/device.c +++ b/input/device.c @@ -34,9 +34,9 @@ #include #include +#include #include #include -#include #include @@ -47,10 +47,10 @@ #include "textfile.h" #include "uinput.h" -#include "storage.h" +#include "device.h" #include "error.h" #include "manager.h" -#include "device.h" +#include "storage.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -1003,21 +1003,11 @@ static const DBusObjectPathVTable device_table = { /* * Input registration functions */ -int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, - struct hidp_connadd_req *hid, const char **path) +static int register_path(DBusConnection *conn, const char *path, struct input_device *idev) { DBusMessage *msg; - struct input_device *idev; - - idev = input_device_new(src, dst); - *path = create_input_path(idev->major, idev->minor); - - memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - - /* FIXME: rd_data is a pointer - hacking */ - - if (!dbus_connection_register_object_path(conn, - *path, &device_table, idev)) { + if (!dbus_connection_register_object_path(conn, path, + &device_table, idev)) { error("Input device path registration failed"); return -1; } @@ -1028,50 +1018,56 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, return -1; dbus_message_append_args(msg, - DBUS_TYPE_STRING, &*path, + DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); send_message_and_unref(conn, msg); - info("Created input device: %s", *path); + info("Created input device: %s", path); return 0; } -int fake_input_register(DBusConnection *conn, bdaddr_t *src, - bdaddr_t *dst, uint8_t ch, const char **path) +int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, + struct hidp_connadd_req *hid, const char **ppath) { - DBusMessage *msg; struct input_device *idev; + const char *path; idev = input_device_new(src, dst); - *path = create_input_path(idev->major, idev->minor); + path = create_input_path(idev->major, idev->minor); - idev->fake = g_new0(struct fake_input, 1); - idev->fake->ch = ch; + /* rd_data must not be deallocated since the memory address is copied */ + memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - if (!dbus_connection_register_object_path(conn, - *path, &device_table, idev)) { - error("Fake input device path registration failed"); + if (register_path(conn, path, idev) < 0) return -1; - } - /* FIXME: dupplicated code */ - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated"); - if (!msg) - return -1; + if (*ppath) + *ppath = path; - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &*path, - DBUS_TYPE_INVALID); + return 0; +} - send_message_and_unref(conn, msg); +int fake_input_register(DBusConnection *conn, bdaddr_t *src, + bdaddr_t *dst, uint8_t ch, const char **ppath) +{ + struct input_device *idev; + const char *path; - info("Created input device: %s", *path); + idev = input_device_new(src, dst); + path = create_input_path(idev->major, idev->minor); - return 0; + idev->fake = g_new0(struct fake_input, 1); + idev->fake->ch = ch; + + if (register_path(conn, path, idev) < 0) + return -1; + if (*ppath) + *ppath = path; + + return 0; } int input_device_unregister(DBusConnection *conn, const char *path) -- cgit From 2bdadb9a01d23b0118161dfc598cc688ef5719e5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 21 Mar 2007 18:02:00 +0000 Subject: input: added already connected error --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 5f70ede1..45c7fa4a 100644 --- a/input/device.c +++ b/input/device.c @@ -801,7 +801,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, return err_connection_failed(conn, msg, "Connection in progress"); if (is_connected(idev)) - return err_connection_failed(conn, msg, "Already connected"); + return err_already_connected(conn, msg); idev->pending_connect = g_try_new0(struct pending_connect, 1); if (!idev->pending_connect) { -- cgit From 07701210404d9bc7153af287cb58e7ea329fd8a8 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 13:34:37 +0000 Subject: input: minor code standard fixes --- input/device.c | 58 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 45c7fa4a..3283e657 100644 --- a/input/device.c +++ b/input/device.c @@ -61,12 +61,12 @@ #define UPDOWN_ENABLED 1 -static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { - struct input_device *idev; + struct device *idev; uint32_t cls; - idev = g_new0(struct input_device, 1); + idev = g_new0(struct device, 1); bacpy(&idev->src, src); bacpy(&idev->dst, dst); @@ -94,7 +94,7 @@ static void pending_connect_free(struct pending_connect *pc) g_free(pc); } -static void input_device_free(struct input_device *idev) +static void device_free(struct device *idev) { if (!idev) return; @@ -344,8 +344,8 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean rfcomm_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { struct fake_input *fake; DBusMessage *reply; @@ -414,7 +414,7 @@ failed: return FALSE; } -static int rfcomm_connect(struct input_device *idev) +static int rfcomm_connect(struct device *idev) { struct sockaddr_rc addr; GIOChannel *io; @@ -487,7 +487,7 @@ failed: return -err; } -static int l2cap_connect(struct input_device *idev, +static int l2cap_connect(struct device *idev, unsigned short psm, GIOFunc cb) { GIOChannel *io; @@ -544,8 +544,8 @@ failed: return -1; } -static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean interrupt_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; socklen_t len; @@ -630,8 +630,8 @@ cleanup: return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct input_device *idev) +static gboolean control_connect_cb(GIOChannel *chan, + GIOCondition cond, struct device *idev) { int ret, csk, err; socklen_t len; @@ -693,7 +693,7 @@ failed: return FALSE; } -static int disconnect(struct input_device *idev, uint32_t flags) +static int disconnect(struct device *idev, uint32_t flags) { struct fake_input *fake = idev->fake; struct hidp_conndel_req req; @@ -755,7 +755,7 @@ fail: return -err; } -static int is_connected(struct input_device *idev) +static int is_connected(struct device *idev) { struct fake_input *fake = idev->fake; struct hidp_conninfo ci; @@ -793,9 +793,9 @@ static int is_connected(struct input_device *idev) * Input Device methods */ static DBusHandlerResult device_connect(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; if (idev->pending_connect) return err_connection_failed(conn, msg, "Connection in progress"); @@ -839,7 +839,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); @@ -851,7 +851,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, static DBusHandlerResult device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; dbus_bool_t connected; @@ -870,7 +870,7 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; char addr[18]; const char *paddr = addr; @@ -891,7 +891,7 @@ static DBusHandlerResult device_get_address(DBusConnection *conn, static DBusHandlerResult device_get_name(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; const char *pname = idev->hidp.name; @@ -909,7 +909,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, static DBusHandlerResult device_get_product_id(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; reply = dbus_message_new_method_return(msg); @@ -926,7 +926,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, DBusMessage *msg, void *data) { - struct input_device *idev = data; + struct device *idev = data; DBusMessage *reply; reply = dbus_message_new_method_return(msg); @@ -987,11 +987,11 @@ static DBusHandlerResult device_message(DBusConnection *conn, static void device_unregister(DBusConnection *conn, void *data) { - struct input_device *idev = data; + struct device *idev = data; /* Disconnect if applied */ disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); - input_device_free(idev); + device_free(idev); } /* Virtual table to handle device object path hierarchy */ @@ -1003,7 +1003,7 @@ static const DBusObjectPathVTable device_table = { /* * Input registration functions */ -static int register_path(DBusConnection *conn, const char *path, struct input_device *idev) +static int register_path(DBusConnection *conn, const char *path, struct device *idev) { DBusMessage *msg; if (!dbus_connection_register_object_path(conn, path, @@ -1031,10 +1031,10 @@ static int register_path(DBusConnection *conn, const char *path, struct input_de int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hid, const char **ppath) { - struct input_device *idev; + struct device *idev; const char *path; - idev = input_device_new(src, dst); + idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); /* rd_data must not be deallocated since the memory address is copied */ @@ -1052,10 +1052,10 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath) { - struct input_device *idev; + struct device *idev; const char *path; - idev = input_device_new(src, dst); + idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); idev->fake = g_new0(struct fake_input, 1); -- cgit From 0156f06757a3d7e813ae4124b499eac6c28d2ab7 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 13:42:31 +0000 Subject: input: Removed SetTimeout(method not defined) --- input/device.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 3283e657..f765c6f1 100644 --- a/input/device.c +++ b/input/device.c @@ -604,7 +604,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); @@ -940,12 +939,6 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return send_message_and_unref(conn, reply); } -static DBusHandlerResult device_set_timeout(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - static DBusHandlerResult device_message(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -979,9 +972,6 @@ static DBusHandlerResult device_message(DBusConnection *conn, if (strcmp(member, "GetVendorId") == 0) return device_get_vendor_id(conn, msg, data); - if (strcmp(member, "SetTimeout") == 0) - return device_set_timeout(conn, msg, data); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -- cgit From 27fe6a301b25a0a3196e27267e8a40f32b303f86 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 14:46:25 +0000 Subject: input: added Connected signal --- input/device.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index f765c6f1..fe38e759 100644 --- a/input/device.c +++ b/input/device.c @@ -348,7 +348,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { struct fake_input *fake; - DBusMessage *reply; + DBusMessage *reply, *signal; + const char *path; socklen_t len; int ret, err; @@ -394,11 +395,15 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); + /* Replying to the requestor */ reply = dbus_message_new_method_return(idev->pending_connect->msg); - if (reply) { - dbus_connection_send(idev->pending_connect->conn, reply, NULL); - dbus_message_unref(reply); - } + send_message_and_unref(idev->pending_connect->conn, reply); + + /* Sending the Connected signal */ + path = dbus_message_get_path(idev->pending_connect->msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Connected"); + send_message_and_unref(idev->pending_connect->conn, signal); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -548,6 +553,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; + DBusMessage *signal; + const char *path; socklen_t len; if (cond & G_IO_NVAL) { @@ -604,9 +611,16 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } + /* Replying to the requestor */ send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); + /* Sending the Connected signal */ + path = dbus_message_get_path(idev->pending_connect->msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Connected"); + send_message_and_unref(idev->pending_connect->conn, signal); + close (ctl); goto cleanup; failed: -- cgit From 6caed0053e1c938737111e9f34c671803131bfbf Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 22 Mar 2007 14:53:22 +0000 Subject: input: Added the Disconnect signal --- input/device.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index fe38e759..5ebeb1ec 100644 --- a/input/device.c +++ b/input/device.c @@ -853,12 +853,21 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + DBusMessage *signal; + const char *path; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); - return send_message_and_unref(conn, + /* Replying to the requestor */ + send_message_and_unref(conn, dbus_message_new_method_return(msg)); + + /* Sending the Disconnect signal */ + path = dbus_message_get_path(msg); + signal = dbus_message_new_signal(path, + INPUT_DEVICE_INTERFACE, "Disconnected"); + return send_message_and_unref(conn, signal); } static DBusHandlerResult device_is_connected(DBusConnection *conn, -- cgit From e3aec1dd412fc0adb0587edf750979e4d18906b0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 12 Apr 2007 09:59:15 +0000 Subject: Keep the device structure local --- input/device.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 5ebeb1ec..a29cc095 100644 --- a/input/device.c +++ b/input/device.c @@ -61,6 +61,29 @@ #define UPDOWN_ENABLED 1 +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + +struct fake_input { + GIOChannel *io; + int rfcomm; /* RFCOMM socket */ + int uinput; /* uinput socket */ + uint8_t ch; /* RFCOMM channel number */ +}; + +struct device { + bdaddr_t src; + bdaddr_t dst; + char *name; + uint8_t major; + uint8_t minor; + struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + struct fake_input *fake; + struct pending_connect *pending_connect; +}; + static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; @@ -1086,6 +1109,13 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, int input_device_unregister(DBusConnection *conn, const char *path) { DBusMessage *msg; + struct device *idev; + + if (!dbus_connection_get_object_path_data(conn, + path, (void *) &idev)) + return -1; + + del_stored_device_info(&idev->src, &idev->dst); if (!dbus_connection_unregister_object_path(conn, path)) { error("Input device path unregister failed"); @@ -1105,3 +1135,21 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } + +int input_device_get_bdaddr(DBusConnection *conn, const char *path, + bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + + if (!dbus_connection_get_object_path_data(conn, path, + (void *) &idev)) + return -1; + + if (!idev) + return -1; + + bacpy(src, &idev->src); + bacpy(dst, &idev->dst); + + return 0; +} -- cgit From 4f32f865517ba5c6a65550d39504a44065b9d013 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 13:22:58 +0000 Subject: input: Connect/disconnect to the control and interrupt psm at the ending of CreateDevice --- input/device.c | 127 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 63 insertions(+), 64 deletions(-) (limited to 'input/device.c') 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; +} -- cgit From f9398eaf08b49c1e8af5bc87a4b19d862ab5a4de Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 19:36:28 +0000 Subject: input: fixed io channel unref and socket close --- input/device.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 76049ec4..24540ca1 100644 --- a/input/device.c +++ b/input/device.c @@ -520,6 +520,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, const char *path; socklen_t len; + isk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; isk = -1; @@ -527,14 +529,12 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - isk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP interrupt socket"); goto failed; } - isk = g_io_channel_unix_get_fd(chan); idev->hidp.intr_sock = isk; idev->hidp.idle_to = 30 * 60; /* 30 minutes */ @@ -601,7 +601,6 @@ cleanup: pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); return FALSE; } @@ -612,6 +611,8 @@ static gboolean control_connect_cb(GIOChannel *chan, int ret, csk, err; socklen_t len; + csk = g_io_channel_unix_get_fd(chan); + if (cond & G_IO_NVAL) { err = EHOSTDOWN; csk = -1; @@ -619,14 +620,11 @@ static gboolean control_connect_cb(GIOChannel *chan, } if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EINTR; - csk = -1; + err = EHOSTDOWN; error("Hangup or error on HIDP control socket"); goto failed; - } - csk = g_io_channel_unix_get_fd(chan); /* Set HID control channel */ idev->hidp.ctrl_sock = csk; @@ -652,7 +650,6 @@ static gboolean control_connect_cb(GIOChannel *chan, goto failed; } - g_io_channel_unref(chan); return FALSE; failed: @@ -664,7 +661,6 @@ failed: idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); return FALSE; } @@ -1143,6 +1139,8 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, cb(io, G_IO_OUT, data); } + g_io_channel_unref(io); + return 0; failed: -- cgit From 4136e617c4f8ab7dfc3488708c8ba129910dc597 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 17 Apr 2007 20:39:39 +0000 Subject: input: code cleanup/standard --- input/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 24540ca1..10950785 100644 --- a/input/device.c +++ b/input/device.c @@ -800,10 +800,12 @@ static DBusHandlerResult device_connect(DBusConnection *conn, 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); + int err = errno; + + error("L2CAP connect failed: %s(%d)", strerror(err), err); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, strerror(errno)); + return err_connection_failed(conn, msg, strerror(err)); } return DBUS_HANDLER_RESULT_HANDLED; -- cgit From 9cdd7162b4d1c999ad341f10ac5aba4215de4b22 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 18 Apr 2007 14:02:19 +0000 Subject: fake input: fixed GIOChannel unrefs --- input/device.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 10950785..ba827fb9 100644 --- a/input/device.c +++ b/input/device.c @@ -355,12 +355,11 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) return TRUE; failed: - /* FIXME: Missing clean/free fake io channel */ - g_io_channel_close(chan); - g_io_channel_unref(chan); ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); fake->uinput = -1; + g_io_channel_unref(fake->io); + return FALSE; } @@ -374,19 +373,16 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, int ret, err; fake = idev->fake; + fake->rfcomm = g_io_channel_unix_get_fd(chan); - if (cond & G_IO_NVAL) { - g_io_channel_unref(chan); + if (cond & G_IO_NVAL) return FALSE; - } if (cond & (G_IO_ERR | G_IO_HUP)) { err = EIO; goto failed; } - fake->rfcomm = g_io_channel_unix_get_fd(chan); - len = sizeof(ret); if (getsockopt(fake->rfcomm, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { err = errno; @@ -427,7 +423,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); + return FALSE; failed: @@ -435,7 +431,9 @@ failed: idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; - g_io_channel_unref(chan); + + g_io_channel_close(chan); + return FALSE; } @@ -452,15 +450,6 @@ static int rfcomm_connect(struct device *idev) return -err; } - io = g_io_channel_unix_new(sk); - if (!io) { - err = -EIO; - error("channel_unix_new failed in rfcomm connect"); - goto failed; - } - - g_io_channel_set_close_on_unref(io, FALSE); - memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &idev->src); @@ -482,12 +471,17 @@ static int rfcomm_connect(struct device *idev) addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &idev->dst); addr.rc_channel = idev->fake->ch; + + 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) { char peer[18]; /* FIXME: debug purpose */ if (!(errno == EAGAIN || errno == EINPROGRESS)) { err = errno; error("connect() failed: %s (%d)", strerror(err), err); + g_io_channel_unref(io); goto failed; } @@ -500,12 +494,11 @@ static int rfcomm_connect(struct device *idev) rfcomm_connect_cb(io, G_IO_OUT, idev); } + g_io_channel_unref(io); + return 0; failed: - if (io) - g_io_channel_unref(io); - close(sk); errno = err; -- cgit From c506053c991016d372948a912201fdc8b03d175f Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 18 Apr 2007 19:33:34 +0000 Subject: input: fixed seg fault when RemoveDevice is called and there is a pending connection request --- input/device.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index ba827fb9..cd8662db 100644 --- a/input/device.c +++ b/input/device.c @@ -667,11 +667,13 @@ static int disconnect(struct device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { - if (fake->io) { - g_io_channel_close(fake->io); - g_io_channel_unref(fake->io); - fake->io = NULL; - } + if (!fake->io) + return -ENOTCONN; + + g_io_channel_close(fake->io); + g_io_channel_unref(fake->io); + fake->io = NULL; + if (fake->uinput >= 0) { ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); @@ -974,16 +976,17 @@ static const DBusObjectPathVTable device_table = { static int register_path(DBusConnection *conn, const char *path, struct device *idev) { DBusMessage *msg; + if (!dbus_connection_register_object_path(conn, path, &device_table, idev)) { error("Input device path registration failed"); - return -1; + return -EINVAL; } msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) - return -1; + return -ENOMEM; dbus_message_append_args(msg, DBUS_TYPE_STRING, &path, @@ -1001,6 +1004,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, { struct device *idev; const char *path; + int err; idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); @@ -1008,13 +1012,12 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, /* rd_data must not be deallocated since the memory address is copied */ memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); - if (register_path(conn, path, idev) < 0) - return -1; + err = register_path(conn, path, idev); if (*ppath) *ppath = path; - return 0; + return err; } int fake_input_register(DBusConnection *conn, bdaddr_t *src, @@ -1044,20 +1047,22 @@ int input_device_unregister(DBusConnection *conn, const char *path) struct device *idev; if (!dbus_connection_get_object_path_data(conn, - path, (void *) &idev)) - return -1; + path, (void *) &idev) || !idev) + return -EINVAL; + + if (idev->pending_connect) { + /* Pending connection running */ + return -EBUSY; + } del_stored_device_info(&idev->src, &idev->dst); - if (!dbus_connection_unregister_object_path(conn, path)) { - error("Input device path unregister failed"); - return -1; - } + dbus_connection_unregister_object_path(conn, path); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved"); if (!msg) - return -1; + return -ENOMEM; dbus_message_append_args(msg, DBUS_TYPE_STRING, &path, -- cgit From 319cc14e14afcce95aa9299fd3b357d8d4e596cd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 May 2007 09:55:29 +0000 Subject: Input Service support for phones --- input/device.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index cd8662db..edf8c475 100644 --- a/input/device.c +++ b/input/device.c @@ -195,6 +195,9 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int next_id = 0; switch (major) { + case 0x02: /* Phone */ + strcpy(subpath, "phone"); + break; case 0x04: /* Audio */ switch (minor) { /* FIXME: Testing required */ -- cgit From 74416c5f12cc79cd0769220fa68b0f1bcaeb279e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 May 2007 14:53:34 +0000 Subject: Convert to using generic dbus message dispatching --- input/device.c | 76 ++++++++++++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index edf8c475..4a76b786 100644 --- a/input/device.c +++ b/input/device.c @@ -43,6 +43,7 @@ #include #include "dbus.h" +#include "dbus-helper.h" #include "logging.h" #include "textfile.h" #include "uinput.h" @@ -922,42 +923,6 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return send_message_and_unref(conn, reply); } -static DBusHandlerResult device_message(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - const char *iface, *member; - - iface = dbus_message_get_interface(msg); - member = dbus_message_get_member(msg); - - /* Accept messages from the input interface only */ - if (strcmp(INPUT_DEVICE_INTERFACE, iface)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (strcmp(member, "Connect") == 0) - return device_connect(conn, msg, data); - - if (strcmp(member, "Disconnect") == 0) - return device_disconnect(conn, msg, data); - - if (strcmp(member, "IsConnected") == 0) - return device_is_connected(conn, msg, data); - - if (strcmp(member, "GetAddress") == 0) - return device_get_address(conn, msg, data); - - if (strcmp(member, "GetName") == 0) - return device_get_name(conn, msg, data); - - if (strcmp(member, "GetProductId") == 0) - return device_get_product_id(conn, msg, data); - - if (strcmp(member, "GetVendorId") == 0) - return device_get_vendor_id(conn, msg, data); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - static void device_unregister(DBusConnection *conn, void *data) { struct device *idev = data; @@ -967,10 +932,21 @@ static void device_unregister(DBusConnection *conn, void *data) device_free(idev); } -/* Virtual table to handle device object path hierarchy */ -static const DBusObjectPathVTable device_table = { - .message_function = device_message, - .unregister_function = device_unregister, +static DBusMethodVTable device_methods[] = { + { "Connect", device_connect, "", "" }, + { "Disconnect", device_disconnect, "", "" }, + { "IsConnected", device_is_connected, "", "b" }, + { "GetAddress", device_get_address, "", "s" }, + { "GetName", device_get_name, "", "s" }, + { "GetProductId", device_get_product_id, "", "q" }, + { "GetVendorId", device_get_vendor_id, "", "q" }, + { NULL, NULL, NULL, NULL } +}; + +static DBusSignalVTable device_signals[] = { + { "Connected", "" }, + { "Disconnected", "" }, + { NULL, NULL } }; /* @@ -980,12 +956,22 @@ static int register_path(DBusConnection *conn, const char *path, struct device * { DBusMessage *msg; - if (!dbus_connection_register_object_path(conn, path, - &device_table, idev)) { + if (!dbus_connection_create_object_path(conn, path, + NULL, device_unregister)) { error("Input device path registration failed"); return -EINVAL; } + if (!dbus_connection_register_interface(conn, path, + INPUT_DEVICE_INTERFACE, + device_methods, + device_signals, NULL)) { + error("Failed to register %s interface to %s", + INPUT_DEVICE_INTERFACE, path); + dbus_connection_destroy_object_path(conn, path); + return -1; + } + msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated"); if (!msg) @@ -1049,7 +1035,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) DBusMessage *msg; struct device *idev; - if (!dbus_connection_get_object_path_data(conn, + if (!dbus_connection_get_object_user_data(conn, path, (void *) &idev) || !idev) return -EINVAL; @@ -1060,7 +1046,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) del_stored_device_info(&idev->src, &idev->dst); - dbus_connection_unregister_object_path(conn, path); + dbus_connection_destroy_object_path(conn, path); msg = dbus_message_new_signal(INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved"); @@ -1081,7 +1067,7 @@ int input_device_get_bdaddr(DBusConnection *conn, const char *path, { struct device *idev; - if (!dbus_connection_get_object_path_data(conn, path, + if (!dbus_connection_get_object_user_data(conn, path, (void *) &idev)) return -1; -- cgit From ea478e3120a4a2d777c5b828e96fde0e44fc897a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 May 2007 15:28:08 +0000 Subject: Fix device registration --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 4a76b786..7067133e 100644 --- a/input/device.c +++ b/input/device.c @@ -957,7 +957,7 @@ static int register_path(DBusConnection *conn, const char *path, struct device * DBusMessage *msg; if (!dbus_connection_create_object_path(conn, path, - NULL, device_unregister)) { + idev, device_unregister)) { error("Input device path registration failed"); return -EINVAL; } -- cgit From e8db465169591d3f77056294699c30113fe5206a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 9 May 2007 19:48:39 +0000 Subject: input: small code cleanup --- input/device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 7067133e..75c64621 100644 --- a/input/device.c +++ b/input/device.c @@ -1003,7 +1003,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, err = register_path(conn, path, idev); - if (*ppath) + if (!err && *ppath) *ppath = path; return err; @@ -1014,6 +1014,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, { struct device *idev; const char *path; + int err; idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); @@ -1021,13 +1022,12 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; - if (register_path(conn, path, idev) < 0) - return -1; + err = register_path(conn, path, idev); - if (*ppath) + if (!err && *ppath) *ppath = path; - return 0; + return err; } int input_device_unregister(DBusConnection *conn, const char *path) -- cgit From f0fe2c5ffb3741f4e6fdbe2d7aee01e66b2af4dd Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Wed, 9 May 2007 20:05:06 +0000 Subject: input: Use dbus_connection_emit_signal --- input/device.c | 51 ++++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 75c64621..d1c08190 100644 --- a/input/device.c +++ b/input/device.c @@ -371,7 +371,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { struct fake_input *fake; - DBusMessage *reply, *signal; + DBusMessage *reply; const char *path; socklen_t len; int ret, err; @@ -421,9 +421,9 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect->msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Connected"); - send_message_and_unref(idev->pending_connect->conn, signal); + dbus_connection_emit_signal(idev->pending_connect->conn, path, + INPUT_DEVICE_INTERFACE, "Connected", + DBUS_TYPE_INVALID); pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -513,7 +513,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { int ctl, isk, ret, err; - DBusMessage *signal; const char *path; socklen_t len; @@ -577,9 +576,9 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect->msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Connected"); - send_message_and_unref(idev->pending_connect->conn, signal); + dbus_connection_emit_signal(idev->pending_connect->conn, path, + INPUT_DEVICE_INTERFACE, "Connected" , + DBUS_TYPE_INVALID); close (ctl); goto cleanup; @@ -814,7 +813,6 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *signal; const char *path; if (disconnect(idev, 0) < 0) @@ -826,9 +824,11 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, /* Sending the Disconnect signal */ path = dbus_message_get_path(msg); - signal = dbus_message_new_signal(path, - INPUT_DEVICE_INTERFACE, "Disconnected"); - return send_message_and_unref(conn, signal); + dbus_connection_emit_signal(conn, path, + INPUT_DEVICE_INTERFACE, "Disconnected", + DBUS_TYPE_INVALID); + + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult device_is_connected(DBusConnection *conn, @@ -954,8 +954,6 @@ static DBusSignalVTable device_signals[] = { */ static int register_path(DBusConnection *conn, const char *path, struct device *idev) { - DBusMessage *msg; - if (!dbus_connection_create_object_path(conn, path, idev, device_unregister)) { error("Input device path registration failed"); @@ -972,16 +970,10 @@ static int register_path(DBusConnection *conn, const char *path, struct device * return -1; } - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated"); - if (!msg) - return -ENOMEM; - - dbus_message_append_args(msg, + dbus_connection_emit_signal(conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(conn, msg); + DBUS_TYPE_INVALID); info("Created input device: %s", path); @@ -1032,7 +1024,6 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, int input_device_unregister(DBusConnection *conn, const char *path) { - DBusMessage *msg; struct device *idev; if (!dbus_connection_get_object_user_data(conn, @@ -1048,16 +1039,10 @@ int input_device_unregister(DBusConnection *conn, const char *path) dbus_connection_destroy_object_path(conn, path); - msg = dbus_message_new_signal(INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceRemoved"); - if (!msg) - return -ENOMEM; - - dbus_message_append_args(msg, + dbus_connection_emit_signal(conn, INPUT_PATH, + INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - send_message_and_unref(conn, msg); + DBUS_TYPE_INVALID); return 0; } -- cgit From 60709fc61959f4ead3e305a0de2cd2419c41e8b4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 May 2007 08:43:37 +0000 Subject: Fix unitialized memory access --- input/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index d1c08190..b79bbc45 100644 --- a/input/device.c +++ b/input/device.c @@ -995,7 +995,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, err = register_path(conn, path, idev); - if (!err && *ppath) + if (!err && ppath) *ppath = path; return err; @@ -1016,7 +1016,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, err = register_path(conn, path, idev); - if (!err && *ppath) + if (!err && ppath) *ppath = path; return err; -- cgit From cc7ee42ddf28a602f3160fa024da36104eb925d1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 10 May 2007 13:57:15 +0000 Subject: input: skip auth/encrypt if the link is not available and allow connections --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index b79bbc45..d9f95c4e 100644 --- a/input/device.c +++ b/input/device.c @@ -557,7 +557,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (idev->hidp.subclass & 0x40) { int ret; ret = encrypt_link(&idev->src, &idev->dst); - if (ret < 0) { + if (ret < 0 && ret != -ENOKEY) { err = -ret; close(ctl); goto failed; -- cgit From 772f25e26e1d1c5982855eefd59b51c7e4aaab95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 May 2007 12:22:52 +0000 Subject: Add GetAdapter() method to retrieve the source address --- input/device.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index d9f95c4e..d85aae55 100644 --- a/input/device.c +++ b/input/device.c @@ -850,6 +850,27 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn, return send_message_and_unref(conn, reply); } +static DBusHandlerResult device_get_adapter(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct device *idev = data; + DBusMessage *reply; + char addr[18]; + const char *paddr = addr; + + ba2str(&idev->src, addr); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_append_args(reply, + DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); + + return send_message_and_unref(conn, reply); +} + static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -936,6 +957,7 @@ static DBusMethodVTable device_methods[] = { { "Connect", device_connect, "", "" }, { "Disconnect", device_disconnect, "", "" }, { "IsConnected", device_is_connected, "", "b" }, + { "GetAdapter", device_get_adapter, "", "s" }, { "GetAddress", device_get_address, "", "s" }, { "GetName", device_get_name, "", "s" }, { "GetProductId", device_get_product_id, "", "q" }, -- cgit From 6de268e32d69d08a9cf50c41f4a3ee67ade3ec99 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 29 May 2007 03:58:10 +0000 Subject: Don't set MTU value to 48 --- input/device.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index d85aae55..1310b7fb 100644 --- a/input/device.c +++ b/input/device.c @@ -797,7 +797,6 @@ static DBusHandlerResult device_connect(DBusConnection *conn, /* HID devices */ if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb, idev) < 0) { - int err = errno; error("L2CAP connect failed: %s(%d)", strerror(err), err); @@ -1087,14 +1086,16 @@ 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) +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) + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (sk < 0) return -1; memset(&addr, 0, sizeof(addr)); @@ -1108,12 +1109,14 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, goto failed; memset(&opts, 0, sizeof(opts)); +#if 0 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; +#endif memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; @@ -1131,9 +1134,8 @@ int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) cb, data); - } else { + } else cb(io, G_IO_OUT, data); - } g_io_channel_unref(io); -- cgit From 0bf3861da5ad7f4f2310029e2b42ae964a9e3aa5 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 21 Jun 2007 22:06:33 +0000 Subject: input: removed session_data structure and added watch for Disconnect signal --- input/device.c | 295 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 225 insertions(+), 70 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 1310b7fb..d3f07cf5 100644 --- a/input/device.c +++ b/input/device.c @@ -77,11 +77,18 @@ struct device { char *name; uint8_t major; uint8_t minor; - struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ + uint16_t product; + uint16_t vendor; struct fake_input *fake; - struct pending_connect *pending_connect; + struct pending_connect *pending_connect; /* FIXME: use only the msg */ + DBusConnection *conn; + char *path; + int ctrl_sk; + int intr_sk; }; +GSList *devices = NULL; + static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; @@ -95,11 +102,10 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) read_device_name(src, dst, &idev->name); read_device_class(src, dst, &cls); - idev->major = (cls >> 8) & 0x1f; - idev->minor = (cls >> 2) & 0x3f; - - /* FIXME: hidp could be alloc dynamically */ - snprintf(idev->hidp.name, 128, "%s", idev->name); + idev->major = (cls >> 8) & 0x1f; + idev->minor = (cls >> 2) & 0x3f; + idev->ctrl_sk = -1; + idev->intr_sk = -1; return idev; } @@ -121,12 +127,13 @@ static void device_free(struct device *idev) return; if (idev->name) g_free(idev->name); - if (idev->hidp.rd_data) - g_free(idev->hidp.rd_data); if (idev->fake) g_free(idev->fake); - if (idev->pending_connect) + if (idev->pending_connect) pending_connect_free(idev->pending_connect); + if (idev->path) + g_free(idev->path); + dbus_connection_unref(idev->conn); g_free(idev); } @@ -509,11 +516,95 @@ failed: return -err; } +static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct device *idev = data; + gboolean ret = TRUE; + + if (cond & G_IO_NVAL) + ret = FALSE; + + if (cond & (G_IO_HUP | G_IO_ERR)) { + g_io_channel_close(chan); + ret = FALSE; + } + + if (ret == FALSE) + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + return ret; +} + +static void create_watch(int sk, struct device *idev) +{ + GIOChannel *io; + + io = g_io_channel_unix_new(sk); + g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + connection_event, idev); + g_io_channel_unref(io); +} + +static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) +{ + struct hidp_connadd_req req; + char addr[18]; + int ctl, err, timeout = 30; + + ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); + if (ctl < 0) { + error("Can't open HIDP interface"); + return -errno; + } + + ba2str(dst, addr); + + memset(&req, 0, sizeof(req)); + req.ctrl_sock = ctrl_sk; + req.intr_sock = intr_sk; + req.flags = 0; + req.idle_to = timeout * 60; + + err = get_stored_device_info(src, dst, &req); + if (err < 0) { + error("Rejected connection from unknown device %s", addr); + goto cleanup; + } + + if (req.subclass & 0x40) { + err = encrypt_link(src, dst); + if (err < 0 && err != -ENOKEY) + goto cleanup; + } + + if (name) + strncpy(req.name, name, 128); + + info("New input device %s (%s)", addr, req.name); + + if (req.vendor == 0x054c && req.product == 0x0268) { + unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 }; + err = write(ctrl_sk, buf, sizeof(buf)); + } + + err = ioctl(ctl, HIDPCONNADD, &req); +cleanup: + close(ctl); + + if (req.rd_data) + free(req.rd_data); + + return err; +} + static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, struct device *idev) { - int ctl, isk, ret, err; - const char *path; + int isk, ret, err; socklen_t len; isk = g_io_channel_unix_get_fd(chan); @@ -531,9 +622,6 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } - idev->hidp.intr_sock = isk; - idev->hidp.idle_to = 30 * 60; /* 30 minutes */ - len = sizeof(ret); if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { err = errno; @@ -547,54 +635,33 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto failed; } - ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); - if (ctl < 0) { - err = errno; - error("Can't open HIDP control socket"); + idev->intr_sk = isk; + err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (err < 0) goto failed; - } - - if (idev->hidp.subclass & 0x40) { - int ret; - ret = encrypt_link(&idev->src, &idev->dst); - if (ret < 0 && ret != -ENOKEY) { - err = -ret; - close(ctl); - goto failed; - } - } - if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) { - err = errno; - close(ctl); - goto failed; - } + create_watch(idev->ctrl_sk, idev); + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Connected", + DBUS_TYPE_INVALID); /* Replying to the requestor */ send_message_and_unref(idev->pending_connect->conn, dbus_message_new_method_return(idev->pending_connect->msg)); - /* Sending the Connected signal */ - path = dbus_message_get_path(idev->pending_connect->msg); - dbus_connection_emit_signal(idev->pending_connect->conn, path, - INPUT_DEVICE_INTERFACE, "Connected" , - DBUS_TYPE_INVALID); - - close (ctl); goto cleanup; failed: err_connection_failed(idev->pending_connect->conn, idev->pending_connect->msg, strerror(err)); - -cleanup: if (isk > 0) close(isk); + close(idev->ctrl_sk); + idev->intr_sk = -1; + idev->ctrl_sk = -1; - close(idev->hidp.ctrl_sock); - - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; - +cleanup: pending_connect_free(idev->pending_connect); idev->pending_connect = NULL; @@ -622,7 +689,7 @@ static gboolean control_connect_cb(GIOChannel *chan, } /* Set HID control channel */ - idev->hidp.ctrl_sock = csk; + idev->ctrl_sk = csk; len = sizeof(ret); if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { @@ -652,7 +719,7 @@ failed: if (csk > 0) close(csk); - idev->hidp.ctrl_sock = -1; + idev->ctrl_sk = -1; err_connection_failed(idev->pending_connect->conn, idev->pending_connect->msg, strerror(err)); pending_connect_free(idev->pending_connect); @@ -687,6 +754,14 @@ static int disconnect(struct device *idev, uint32_t flags) } /* Standard HID disconnect */ + if (idev->ctrl_sk >= 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; + } + if (idev->intr_sk >= 0) { + close(idev->intr_sk); + idev->intr_sk = -1; + } ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -719,8 +794,8 @@ fail: close(ctl); errno = err; - idev->hidp.intr_sock = -1; - idev->hidp.ctrl_sock = -1; + idev->intr_sk = -1; + idev->ctrl_sk = -1; return -err; } @@ -812,22 +887,13 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - const char *path; if (disconnect(idev, 0) < 0) return err_failed(conn, msg, strerror(errno)); /* Replying to the requestor */ - send_message_and_unref(conn, + return send_message_and_unref(conn, dbus_message_new_method_return(msg)); - - /* Sending the Disconnect signal */ - path = dbus_message_get_path(msg); - dbus_connection_emit_signal(conn, path, - INPUT_DEVICE_INTERFACE, "Disconnected", - DBUS_TYPE_INVALID); - - return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult device_is_connected(DBusConnection *conn, @@ -896,7 +962,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, { struct device *idev = data; DBusMessage *reply; - const char *pname = idev->hidp.name; + const char *pname = idev->name; reply = dbus_message_new_method_return(msg); if (!reply) @@ -920,7 +986,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.product, + DBUS_TYPE_UINT16, &idev->product, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply); @@ -937,7 +1003,7 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->hidp.vendor, + DBUS_TYPE_UINT16, &idev->vendor, DBUS_TYPE_INVALID); return send_message_and_unref(conn, reply); @@ -994,7 +1060,9 @@ static int register_path(DBusConnection *conn, const char *path, struct device * dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceCreated", DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); + + devices = g_slist_append(devices, idev); info("Created input device: %s", path); @@ -1010,9 +1078,10 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); - - /* rd_data must not be deallocated since the memory address is copied */ - memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req)); + idev->path = g_strdup(path); + idev->product = hid->product; + idev->vendor = hid->vendor; + idev->conn = dbus_connection_ref(conn); err = register_path(conn, path, idev); @@ -1031,6 +1100,10 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev = device_new(src, dst); path = create_input_path(idev->major, idev->minor); + idev->path = g_strdup(path); + idev->conn = dbus_connection_ref(conn); + + /* FIXME: Missing set product and vendor */ idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; @@ -1058,6 +1131,8 @@ int input_device_unregister(DBusConnection *conn, const char *path) del_stored_device_info(&idev->src, &idev->dst); + devices = g_slist_remove(devices, idev); + dbus_connection_destroy_object_path(conn, path); dbus_connection_emit_signal(conn, INPUT_PATH, @@ -1148,3 +1223,83 @@ failed: return -1; } + +static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + idev = list->data; + + if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) + return idev; + } + + return NULL; +} + +int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + switch (psm) { + case L2CAP_PSM_HIDP_CTRL: + idev->ctrl_sk = nsk; + break; + case L2CAP_PSM_HIDP_INTR: + idev->intr_sk = nsk; + break; + } + + return 0; +} + +int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + if (idev->ctrl_sk >= 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; + } + + if (idev->intr_sk >= 0) { + close(idev->intr_sk); + idev->intr_sk = -1; + } + + return 0; +} + +int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev; + int err; + + idev = find_device(src, dst); + if (!idev) + return -ENOENT; + + err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); + if (err < 0) { + close(idev->ctrl_sk); + close(idev->intr_sk); + idev->ctrl_sk = -1; + idev->intr_sk = -1; + + return err; + } + + create_watch(idev->ctrl_sk, idev); + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Connected", + DBUS_TYPE_INVALID); + return 0; +} -- cgit From 51386028973220d84b6a7e59735fa1fce98621b3 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 14:25:16 +0000 Subject: input: pending_connect struct is not necessary anymore(replaced by DBusMessage pointer) --- input/device.c | 68 +++++++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index d3f07cf5..99c462c8 100644 --- a/input/device.c +++ b/input/device.c @@ -59,11 +59,6 @@ #define UPDOWN_ENABLED 1 -struct pending_connect { - DBusConnection *conn; - DBusMessage *msg; -}; - struct fake_input { GIOChannel *io; int rfcomm; /* RFCOMM socket */ @@ -80,7 +75,7 @@ struct device { uint16_t product; uint16_t vendor; struct fake_input *fake; - struct pending_connect *pending_connect; /* FIXME: use only the msg */ + DBusMessage *pending_connect; DBusConnection *conn; char *path; int ctrl_sk; @@ -110,17 +105,6 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) return idev; } -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - g_free(pc); -} - static void device_free(struct device *idev) { if (!idev) @@ -129,12 +113,11 @@ static void device_free(struct device *idev) g_free(idev->name); if (idev->fake) g_free(idev->fake); - if (idev->pending_connect) - pending_connect_free(idev->pending_connect); if (idev->path) g_free(idev->path); + if (idev->pending_connect) + dbus_message_unref(idev->pending_connect); dbus_connection_unref(idev->conn); - g_free(idev); } @@ -423,24 +406,24 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, (GIOFunc) rfcomm_io_cb, fake); /* Replying to the requestor */ - reply = dbus_message_new_method_return(idev->pending_connect->msg); - send_message_and_unref(idev->pending_connect->conn, reply); + reply = dbus_message_new_method_return(idev->pending_connect); + send_message_and_unref(idev->conn, reply); /* Sending the Connected signal */ - path = dbus_message_get_path(idev->pending_connect->msg); - dbus_connection_emit_signal(idev->pending_connect->conn, path, + path = dbus_message_get_path(idev->pending_connect); + dbus_connection_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_INVALID); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; failed: - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); - pending_connect_free(idev->pending_connect); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; g_io_channel_close(chan); @@ -648,13 +631,13 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, DBUS_TYPE_INVALID); /* Replying to the requestor */ - send_message_and_unref(idev->pending_connect->conn, - dbus_message_new_method_return(idev->pending_connect->msg)); + send_message_and_unref(idev->conn, + dbus_message_new_method_return(idev->pending_connect)); goto cleanup; failed: - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); if (isk > 0) close(isk); close(idev->ctrl_sk); @@ -662,7 +645,7 @@ failed: idev->ctrl_sk = -1; cleanup: - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; @@ -720,9 +703,9 @@ failed: close(csk); idev->ctrl_sk = -1; - err_connection_failed(idev->pending_connect->conn, - idev->pending_connect->msg, strerror(err)); - pending_connect_free(idev->pending_connect); + err_connection_failed(idev->conn, + idev->pending_connect, strerror(err)); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return FALSE; @@ -848,21 +831,14 @@ static DBusHandlerResult device_connect(DBusConnection *conn, if (is_connected(idev)) return err_already_connected(conn, msg); - idev->pending_connect = g_try_new0(struct pending_connect, 1); - if (!idev->pending_connect) { - error("Out of memory when allocating new struct pending_connect"); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - idev->pending_connect->conn = dbus_connection_ref(conn); - idev->pending_connect->msg = dbus_message_ref(msg); + idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ if (idev->fake) { if (rfcomm_connect(idev) < 0) { const char *str = strerror(errno); error("RFCOMM connect failed: %s(%d)", str, errno); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return err_connection_failed(conn, msg, str); } @@ -875,7 +851,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, int err = errno; error("L2CAP connect failed: %s(%d)", strerror(err), err); - pending_connect_free(idev->pending_connect); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return err_connection_failed(conn, msg, strerror(err)); } -- cgit From b4427e24489d4aaf6768041cbb3b90353a285cfe Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 18:39:50 +0000 Subject: input: missing Disconnected signal when RemoveDevice is called --- input/device.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 99c462c8..69b7a482 100644 --- a/input/device.c +++ b/input/device.c @@ -80,6 +80,7 @@ struct device { char *path; int ctrl_sk; int intr_sk; + guint watch; }; GSList *devices = NULL; @@ -512,24 +513,29 @@ static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer d ret = FALSE; } - if (ret == FALSE) + if (ret == FALSE) { dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); + idev->watch = 0; + } return ret; } -static void create_watch(int sk, struct device *idev) +static guint create_watch(int sk, struct device *idev) { + guint id; GIOChannel *io; io = g_io_channel_unix_new(sk); - g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - connection_event, idev); + id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + connection_event, idev); g_io_channel_unref(io); + + return id; } static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) @@ -623,7 +629,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (err < 0) goto failed; - create_watch(idev->ctrl_sk, idev); + idev->watch = create_watch(idev->ctrl_sk, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, @@ -1109,6 +1115,21 @@ int input_device_unregister(DBusConnection *conn, const char *path) devices = g_slist_remove(devices, idev); + /* + * Workaround: if connected, the watch will not be able + * to access the D-Bus data assigned to this path + * because the object path data was destroyed. + */ + if (idev->watch) { + g_source_remove(idev->watch); + idev->watch = 0; + dbus_connection_emit_signal(conn, + path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + } + dbus_connection_destroy_object_path(conn, path); dbus_connection_emit_signal(conn, INPUT_PATH, @@ -1271,7 +1292,7 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) return err; } - create_watch(idev->ctrl_sk, idev); + idev->watch = create_watch(idev->ctrl_sk, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, -- cgit From 7fb02908be38aaa273643ac6b78c5d72e40ae545 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 22 Jun 2007 19:14:38 +0000 Subject: input: fixed CreateDevice - verify the src and the dst address to discover if the device already exists --- input/device.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 69b7a482..d9dfbec4 100644 --- a/input/device.c +++ b/input/device.c @@ -1140,24 +1140,6 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } -int input_device_get_bdaddr(DBusConnection *conn, const char *path, - bdaddr_t *src, bdaddr_t *dst) -{ - struct device *idev; - - if (!dbus_connection_get_object_user_data(conn, path, - (void *) &idev)) - return -1; - - if (!idev) - return -1; - - bacpy(src, &idev->src); - bacpy(dst, &idev->dst); - - return 0; -} - int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data) { @@ -1236,6 +1218,15 @@ static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) return NULL; } +gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) +{ + struct device *idev = find_device(src, dst); + if (!idev) + return FALSE; + else + return TRUE; +} + int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) { struct device *idev = find_device(src, dst); -- cgit From 5c95755a67bc8653af44996bb2fe9263a3137131 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Sat, 23 Jun 2007 17:37:58 +0000 Subject: input: cleanup - removed useless code --- input/device.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index d9dfbec4..5c022ae6 100644 --- a/input/device.c +++ b/input/device.c @@ -783,9 +783,6 @@ fail: close(ctl); errno = err; - idev->intr_sk = -1; - idev->ctrl_sk = -1; - return -err; } -- cgit From ebd3c8b3a8fe0ec8050077e7739dba0b25aec2a1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 13:32:58 +0000 Subject: input: fixed invalid D-Bus path when the remote device class is unknown --- input/device.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 5c022ae6..4f983d99 100644 --- a/input/device.c +++ b/input/device.c @@ -85,10 +85,22 @@ struct device { GSList *devices = NULL; -static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) { struct device *idev; uint32_t cls; + uint8_t major, minor; + + if (!subclass) { + if (read_device_class(src, dst, &cls) < 0) + return NULL; + + major = (cls >> 8) & 0x1f; + minor = (cls >> 2) & 0x3f; + } else { + major = 0x05; /* Peripheral */ + minor = (subclass >> 2) & 0x3f; + } idev = g_new0(struct device, 1); @@ -96,10 +108,9 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst) bacpy(&idev->dst, dst); read_device_name(src, dst, &idev->name); - read_device_class(src, dst, &cls); - idev->major = (cls >> 8) & 0x1f; - idev->minor = (cls >> 2) & 0x3f; + idev->major = major; + idev->minor = minor; idev->ctrl_sk = -1; idev->intr_sk = -1; @@ -1055,8 +1066,16 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, const char *path; int err; - idev = device_new(src, dst); + idev = device_new(src, dst, hid->subclass); + if (!idev) + return -EINVAL; + path = create_input_path(idev->major, idev->minor); + if (!path) { + device_free(idev); + return -EINVAL; + } + idev->path = g_strdup(path); idev->product = hid->product; idev->vendor = hid->vendor; @@ -1077,8 +1096,16 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, const char *path; int err; - idev = device_new(src, dst); + idev = device_new(src, dst, 0); + if (!idev) + return -EINVAL; + path = create_input_path(idev->major, idev->minor); + if (!path) { + device_free(idev); + return -EINVAL; + } + idev->path = g_strdup(path); idev->conn = dbus_connection_ref(conn); -- cgit From 309dbb1060ee24785b06ceb49a75d42c69d02f8a Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 3 Aug 2007 14:18:54 +0000 Subject: input: GetName - fixed seg fault when the remote name is unknown --- input/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 4f983d99..6bf3da9a 100644 --- a/input/device.c +++ b/input/device.c @@ -952,8 +952,8 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, { struct device *idev = data; DBusMessage *reply; - const char *pname = idev->name; - + const char *pname = (idev->name ? idev->name : ""); + reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From 5aef8f33ebb1fb537e13ffeb336eb1d886a7adca Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 27 Aug 2007 13:50:32 +0000 Subject: input: don't send DeviceCreated signal when the daemon starts --- input/device.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 6bf3da9a..3e019a44 100644 --- a/input/device.c +++ b/input/device.c @@ -1047,11 +1047,6 @@ static int register_path(DBusConnection *conn, const char *path, struct device * return -1; } - dbus_connection_emit_signal(conn, INPUT_PATH, - INPUT_MANAGER_INTERFACE, "DeviceCreated", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - devices = g_slist_append(devices, idev); info("Created input device: %s", path); -- cgit From 2450e5e214398dc9d70fd28dcde9c2ac31bf8a29 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 30 Aug 2007 20:27:47 +0000 Subject: input: don't track POLLIN event --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 3e019a44..e137c28f 100644 --- a/input/device.c +++ b/input/device.c @@ -542,7 +542,7 @@ static guint create_watch(int sk, struct device *idev) GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + id = g_io_add_watch(G_IO_HUP | G_IO_ERR | G_IO_NVAL, connection_event, idev); g_io_channel_unref(io); -- cgit From 0ad9f50ac3cfb1885fec839d6ac0be5fdc5aabd1 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 30 Aug 2007 21:58:03 +0000 Subject: input: fixed last commit --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index e137c28f..3f78d15a 100644 --- a/input/device.c +++ b/input/device.c @@ -542,7 +542,7 @@ static guint create_watch(int sk, struct device *idev) GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(G_IO_HUP | G_IO_ERR | G_IO_NVAL, + id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, connection_event, idev); g_io_channel_unref(io); -- cgit From a6da15f222255a207a33a67b32e16eb6cf9f61af Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Fri, 31 Aug 2007 16:36:33 +0000 Subject: input: added interrupt and control channels watches --- input/device.c | 91 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 29 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 3f78d15a..4c485736 100644 --- a/input/device.c +++ b/input/device.c @@ -32,7 +32,7 @@ #include #include #include - + #include #include #include @@ -80,7 +80,8 @@ struct device { char *path; int ctrl_sk; int intr_sk; - guint watch; + guint ctrl_watch; + guint intr_watch; }; GSList *devices = NULL; @@ -402,7 +403,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, goto failed; } - /* + /* * FIXME: Some headsets required a sco connection * first to report volume gain key events */ @@ -425,7 +426,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, path = dbus_message_get_path(idev->pending_connect); dbus_connection_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -511,45 +512,73 @@ failed: return -err; } -static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data) +static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct device *idev = data; - gboolean ret = TRUE; - - if (cond & G_IO_NVAL) - ret = FALSE; - if (cond & (G_IO_HUP | G_IO_ERR)) { + if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - ret = FALSE; + + dbus_connection_emit_signal(idev->conn, + idev->path, + INPUT_DEVICE_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + + g_source_remove(idev->ctrl_watch); + idev->ctrl_watch = 0; + idev->intr_watch = 0; + + /* Close control channel */ + if (idev->ctrl_sk > 0) { + close(idev->ctrl_sk); + idev->ctrl_sk = -1; } - if (ret == FALSE) { - dbus_connection_emit_signal(idev->conn, - idev->path, - INPUT_DEVICE_INTERFACE, - "Disconnected", - DBUS_TYPE_INVALID); - idev->watch = 0; + return FALSE; + +} + +static gboolean ctrl_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); + idev->intr_watch = 0; + idev->ctrl_watch = 0; + + /* Close interrupt channel */ + if (idev->intr_sk > 0) { + close(idev->intr_sk); + idev->intr_sk = -1; } - return ret; + return FALSE; } -static guint create_watch(int sk, struct device *idev) +static guint create_watch(int sk, GIOFunc cb, struct device *idev) { guint id; GIOChannel *io; io = g_io_channel_unix_new(sk); - id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - connection_event, idev); + id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, cb, idev); g_io_channel_unref(io); return id; } -static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name) +static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, + int ctrl_sk, int intr_sk, const char *name) { struct hidp_connadd_req req; char addr[18]; @@ -640,7 +669,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, if (err < 0) goto failed; - idev->watch = create_watch(idev->ctrl_sk, idev); + idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); + idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, @@ -1139,9 +1169,11 @@ int input_device_unregister(DBusConnection *conn, const char *path) * to access the D-Bus data assigned to this path * because the object path data was destroyed. */ - if (idev->watch) { - g_source_remove(idev->watch); - idev->watch = 0; + if (idev->ctrl_watch) + g_source_remove(idev->ctrl_watch); + + if (idev->intr_watch) { + g_source_remove(idev->intr_watch); dbus_connection_emit_signal(conn, path, INPUT_DEVICE_INTERFACE, @@ -1154,7 +1186,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID); return 0; } @@ -1302,7 +1334,8 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) return err; } - idev->watch = create_watch(idev->ctrl_sk, idev); + idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); + idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); dbus_connection_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, -- cgit From 4e7fe8b13bd4cd3c82da00e812e812898a366b3b Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Tue, 2 Oct 2007 17:54:40 +0000 Subject: input: minor leak and code standard --- input/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 4c485736..59dbc5bb 100644 --- a/input/device.c +++ b/input/device.c @@ -665,7 +665,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, } idev->intr_sk = isk; - err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); + err = hidp_connadd(&idev->src, &idev->dst, + idev->ctrl_sk, idev->intr_sk, idev->name); if (err < 0) goto failed; -- cgit From 3571ae843629585caf996c73200bbbfd05c260a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 12 Oct 2007 11:00:32 +0000 Subject: Fix hidp_connad_req usage --- input/device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 59dbc5bb..33a00f7e 100644 --- a/input/device.c +++ b/input/device.c @@ -800,7 +800,7 @@ static int disconnect(struct device *idev, uint32_t flags) return -errno; } - memset(&ci, 0, sizeof(struct hidp_conninfo)); + memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || (ci.state != BT_CONNECTED)) { @@ -808,7 +808,7 @@ static int disconnect(struct device *idev, uint32_t flags) goto fail; } - memset(&req, 0, sizeof(struct hidp_conndel_req)); + memset(&req, 0, sizeof(req)); bacpy(&req.bdaddr, &idev->dst); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { @@ -847,7 +847,7 @@ static int is_connected(struct device *idev) if (ctl < 0) return 0; - memset(&ci, 0, sizeof(struct hidp_conninfo)); + memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); -- cgit From 7e88afe4f8307c092172ff3c3b76c2f95ab00293 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 Nov 2007 13:43:17 +0000 Subject: Update services to new error codes and helper functions --- input/device.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 33a00f7e..66712be2 100644 --- a/input/device.c +++ b/input/device.c @@ -434,8 +434,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, return FALSE; failed: - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -684,8 +684,8 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); if (isk > 0) close(isk); close(idev->ctrl_sk); @@ -751,8 +751,8 @@ failed: close(csk); idev->ctrl_sk = -1; - err_connection_failed(idev->conn, - idev->pending_connect, strerror(err)); + error_connection_attempt_failed(idev->conn, + idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; @@ -871,21 +871,24 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct device *idev = data; if (idev->pending_connect) - return err_connection_failed(conn, msg, "Connection in progress"); + return error_in_progress(conn, msg, + "Device connection already in progress"); if (is_connected(idev)) - return err_already_connected(conn, msg); + return error_already_connected(conn, msg); idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ if (idev->fake) { if (rfcomm_connect(idev) < 0) { - const char *str = strerror(errno); - error("RFCOMM connect failed: %s(%d)", str, errno); + int err = errno; + const char *str = strerror(err); + error("RFCOMM connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, str); + return error_connection_attempt_failed(conn, + msg, err); } return DBUS_HANDLER_RESULT_HANDLED; } @@ -898,7 +901,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("L2CAP connect failed: %s(%d)", strerror(err), err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return err_connection_failed(conn, msg, strerror(err)); + return error_connection_attempt_failed(conn, msg, err); } return DBUS_HANDLER_RESULT_HANDLED; @@ -910,7 +913,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn, struct device *idev = data; if (disconnect(idev, 0) < 0) - return err_failed(conn, msg, strerror(errno)); + return error_failed_errno(conn, msg, errno); /* Replying to the requestor */ return send_message_and_unref(conn, -- cgit From ba255beb79afb9c00ae5b71821f84f911aa8d1fe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Jan 2008 10:38:40 +0000 Subject: Whitespace cleanup --- input/device.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 66712be2..07ed7d9c 100644 --- a/input/device.c +++ b/input/device.c @@ -96,11 +96,11 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) if (read_device_class(src, dst, &cls) < 0) return NULL; - major = (cls >> 8) & 0x1f; - minor = (cls >> 2) & 0x3f; + major = (cls >> 8) & 0x1f; + minor = (cls >> 2) & 0x3f; } else { - major = 0x05; /* Peripheral */ - minor = (subclass >> 2) & 0x3f; + major = 0x05; /* Peripheral */ + minor = (subclass >> 2) & 0x3f; } idev = g_new0(struct device, 1); @@ -199,8 +199,8 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int next_id = 0; switch (major) { - case 0x02: /* Phone */ - strcpy(subpath, "phone"); + case 0x02: /* Phone */ + strcpy(subpath, "phone"); break; case 0x04: /* Audio */ switch (minor) { @@ -274,7 +274,7 @@ static const char *create_input_path(uint8_t major, uint8_t minor) static int decode_key(const char *str) { static int mode = UPDOWN_ENABLED, gain = 0; - + uint16_t key; int new_gain; @@ -335,7 +335,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) if (cond & G_IO_NVAL) return FALSE; - + if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on rfcomm server socket"); goto failed; @@ -871,7 +871,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, struct device *idev = data; if (idev->pending_connect) - return error_in_progress(conn, msg, + return error_in_progress(conn, msg, "Device connection already in progress"); if (is_connected(idev)) @@ -887,7 +887,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("RFCOMM connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, + return error_connection_attempt_failed(conn, msg, err); } return DBUS_HANDLER_RESULT_HANDLED; @@ -987,7 +987,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn, struct device *idev = data; DBusMessage *reply; const char *pname = (idev->name ? idev->name : ""); - + reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; -- cgit From e823c15e43a6f924779e466d434c51157002d9ee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 Feb 2008 03:37:05 +0000 Subject: Update copyright information --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 07ed7d9c..a8daa945 100644 --- a/input/device.c +++ b/input/device.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify -- cgit From fe4d95e06d3de9c917c689963d2894611e82d8ce Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 12 Feb 2008 04:44:53 +0000 Subject: Add support for connect/disconnect callbacks --- input/device.c | 61 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index a8daa945..290ad369 100644 --- a/input/device.c +++ b/input/device.c @@ -59,11 +59,16 @@ #define UPDOWN_ENABLED 1 +#define FI_FLAG_CONNECTED 1 + struct fake_input { + int flags; GIOChannel *io; int rfcomm; /* RFCOMM socket */ int uinput; /* uinput socket */ uint8_t ch; /* RFCOMM channel number */ + gboolean (*connect)(struct device *idev); + int (*disconnect)(struct device *idev); }; struct device { @@ -759,6 +764,26 @@ failed: return FALSE; } +static int fake_disconnect(struct device *idev) +{ + struct fake_input *fake = idev->fake; + + if (!fake->io) + return -ENOTCONN; + + g_io_channel_close(fake->io); + g_io_channel_unref(fake->io); + fake->io = NULL; + + if (fake->uinput >= 0) { + ioctl(fake->uinput, UI_DEV_DESTROY); + close(fake->uinput); + fake->uinput = -1; + } + + return 0; +} + static int disconnect(struct device *idev, uint32_t flags) { struct fake_input *fake = idev->fake; @@ -768,20 +793,10 @@ static int disconnect(struct device *idev, uint32_t flags) /* Fake input disconnect */ if (fake) { - if (!fake->io) - return -ENOTCONN; - - g_io_channel_close(fake->io); - g_io_channel_unref(fake->io); - fake->io = NULL; - - if (fake->uinput >= 0) { - ioctl(fake->uinput, UI_DEV_DESTROY); - close(fake->uinput); - fake->uinput = -1; - } - - return 0; + err = fake->disconnect(idev); + if (err == 0) + fake->flags &= ~FI_FLAG_CONNECTED; + return err; } /* Standard HID disconnect */ @@ -835,12 +850,8 @@ static int is_connected(struct device *idev) int ctl; /* Fake input */ - if (fake) { - if (fake->io) - return 1; - else - return 0; - } + if (fake) + return fake->flags & FI_FLAG_CONNECTED; /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); @@ -869,6 +880,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + struct fake_input *fake = idev->fake; if (idev->pending_connect) return error_in_progress(conn, msg, @@ -880,16 +892,17 @@ static DBusHandlerResult device_connect(DBusConnection *conn, idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ - if (idev->fake) { - if (rfcomm_connect(idev) < 0) { + if (fake) { + if (fake->connect(idev) < 0) { int err = errno; const char *str = strerror(err); - error("RFCOMM connect failed: %s(%d)", str, err); + error("Connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return error_connection_attempt_failed(conn, msg, err); } + fake->flags |= FI_FLAG_CONNECTED; return DBUS_HANDLER_RESULT_HANDLED; } @@ -1142,6 +1155,8 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, idev->fake = g_new0(struct fake_input, 1); idev->fake->ch = ch; + idev->fake->connect = rfcomm_connect; + idev->fake->disconnect = fake_disconnect; err = register_path(conn, path, idev); -- cgit From 465696fda58ed0902157cb537c067a5d1c82ff27 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 12 Feb 2008 04:47:02 +0000 Subject: Fix build problem --- input/device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 290ad369..9eee6e5a 100644 --- a/input/device.c +++ b/input/device.c @@ -61,6 +61,8 @@ #define FI_FLAG_CONNECTED 1 +struct device; + struct fake_input { int flags; GIOChannel *io; -- cgit From f53dce601c8b8ee28bc8b5d354aaa56b454b1a71 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 14 Mar 2008 18:44:00 +0000 Subject: Add basic fake HID infrastructure support --- input/device.c | 58 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 9eee6e5a..46214217 100644 --- a/input/device.c +++ b/input/device.c @@ -52,6 +52,7 @@ #include "error.h" #include "manager.h" #include "storage.h" +#include "fakehid.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -63,16 +64,6 @@ struct device; -struct fake_input { - int flags; - GIOChannel *io; - int rfcomm; /* RFCOMM socket */ - int uinput; /* uinput socket */ - uint8_t ch; /* RFCOMM channel number */ - gboolean (*connect)(struct device *idev); - int (*disconnect)(struct device *idev); -}; - struct device { bdaddr_t src; bdaddr_t dst; @@ -1336,24 +1327,47 @@ int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) return 0; } +static gboolean fake_hid_connect(struct device *dev) +{ + struct fake_hid *fhid = dev->fake->priv; + + return fhid->connect(dev->fake); +} + +static int fake_hid_disconnect(struct device *dev) +{ + struct fake_hid *fhid = dev->fake->priv; + + return fhid->disconnect(dev->fake); +} + int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; + struct fake_hid *fake_hid; + struct fake_input *fake = NULL; int err; idev = find_device(src, dst); if (!idev) return -ENOENT; - err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name); - if (err < 0) { - close(idev->ctrl_sk); - close(idev->intr_sk); - idev->ctrl_sk = -1; - idev->intr_sk = -1; + fake_hid = get_fake_hid(idev->vendor, idev->product); + if (fake_hid) { + fake = g_try_new0(struct fake_input, 1); + if (!fake) { + err = -ENOMEM; + goto error; + } - return err; - } + fake->connect = fake_hid_connect; + 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); + if (err < 0) + goto error; idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); @@ -1363,4 +1377,12 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) "Connected", DBUS_TYPE_INVALID); return 0; + +error: + close(idev->ctrl_sk); + close(idev->intr_sk); + idev->ctrl_sk = -1; + idev->intr_sk = -1; + g_free(fake); + return err; } -- cgit From 279e85d6da77c74f04e5fc605dd8074bfe56b5a5 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 25 Apr 2008 20:01:09 +0000 Subject: Make input service to use libbluetooth-glib convenient functions. --- input/device.c | 206 ++++++++++----------------------------------------------- 1 file changed, 35 insertions(+), 171 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 46214217..08a1c089 100644 --- a/input/device.c +++ b/input/device.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -53,6 +54,7 @@ #include "manager.h" #include "storage.h" #include "fakehid.h" +#include "glib-helper.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -368,38 +370,18 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) { + struct device *idev = user_data; struct fake_input *fake; DBusMessage *reply; const char *path; - socklen_t len; - int ret, err; fake = idev->fake; fake->rfcomm = g_io_channel_unix_get_fd(chan); - if (cond & G_IO_NVAL) - return FALSE; - - if (cond & (G_IO_ERR | G_IO_HUP)) { - err = EIO; - goto failed; - } - - len = sizeof(ret); - if (getsockopt(fake->rfcomm, 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(err), err); + if (err < 0) goto failed; - } /* * FIXME: Some headsets required a sco connection @@ -429,85 +411,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return FALSE; + return; failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - g_io_channel_close(chan); - - return FALSE; } static int rfcomm_connect(struct device *idev) { - struct sockaddr_rc addr; - GIOChannel *io; - int sk, err; - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - err = errno; - error("socket: %s (%d)", strerror(err), err); - return -err; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->src); - addr.rc_channel = 0; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - err = errno; - error("bind: %s (%d)", strerror(err), err); - goto failed; - } - - if (set_nonblocking(sk) < 0) { - err = errno; - error("Set non blocking: %s (%d)", strerror(err), err); - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->dst); - addr.rc_channel = idev->fake->ch; - - 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) { - char peer[18]; /* FIXME: debug purpose */ - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - err = errno; - error("connect() failed: %s (%d)", - strerror(err), err); - g_io_channel_unref(io); - goto failed; - } + int err; - ba2str(&idev->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); - g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, idev); - } else { - debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, idev); + err = bt_rfcomm_connect(&idev->src, &idev->dst, idev->fake->ch, + rfcomm_connect_cb, idev); + if (err < 0) { + error("connect() failed: %s (%d)", strerror(-err), -err); + return err; } - g_io_channel_unref(io); - return 0; - -failed: - close(sk); - errno = err; - - return -err; } static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) @@ -628,41 +552,16 @@ cleanup: return err; } -static gboolean interrupt_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int isk, ret, err; - socklen_t len; - - isk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP interrupt socket"); - goto failed; - - } - - 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; - } + struct device *idev = user_data; - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } - idev->intr_sk = isk; + idev->intr_sk = g_io_channel_unix_get_fd(chan); err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); if (err < 0) @@ -683,78 +582,43 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); - if (isk > 0) - close(isk); - close(idev->ctrl_sk); + idev->pending_connect, -err); idev->intr_sk = -1; idev->ctrl_sk = -1; cleanup: dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int ret, csk, err; - socklen_t len; + struct device *idev = user_data; - csk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP control socket"); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } /* Set HID control channel */ - idev->ctrl_sk = 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; - } + idev->ctrl_sk = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - 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); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + interrupt_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); goto failed; } - return FALSE; + return; failed: - if (csk > 0) - close(csk); - idev->ctrl_sk = -1; error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); + idev->pending_connect, -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } static int fake_disconnect(struct device *idev) @@ -874,6 +738,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, { struct device *idev = data; struct fake_input *fake = idev->fake; + int err; if (idev->pending_connect) return error_in_progress(conn, msg, @@ -900,14 +765,13 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, idev) < 0) { - int err = errno; - - error("L2CAP connect failed: %s(%d)", strerror(err), err); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed: %s(%d)", strerror(-err), -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, msg, err); + return error_connection_attempt_failed(conn, msg, -err); } return DBUS_HANDLER_RESULT_HANDLED; -- cgit From 2d5441331d402a0d78c4b84a028df076f6aab8cf Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 30 Apr 2008 19:37:46 +0000 Subject: Fix possible memory leak when closing control channel. --- input/device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 08a1c089..348622e6 100644 --- a/input/device.c +++ b/input/device.c @@ -580,6 +580,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) dbus_message_new_method_return(idev->pending_connect)); goto cleanup; + failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, -err); -- cgit From f85b9560ece47c94ec82466cba9c44da715591d9 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 7 May 2008 18:39:36 +0000 Subject: Make bt_l2cap_connect to take mtu as paramter. --- input/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 348622e6..b27800e4 100644 --- a/input/device.c +++ b/input/device.c @@ -605,7 +605,7 @@ static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) idev->ctrl_sk = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, 0, interrupt_connect_cb, idev); if (err < 0) { error("L2CAP connect failed:%s (%d)", strerror(-err), -err); @@ -766,7 +766,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, 0, control_connect_cb, idev); if (err < 0) { error("L2CAP connect failed: %s(%d)", strerror(-err), -err); -- cgit From 44a204a75880c342c3ac9066072f102f773a539a Mon Sep 17 00:00:00 2001 From: Cidorvan Leite Date: Thu, 8 May 2008 19:58:35 +0000 Subject: Removed function not used. --- input/device.c | 63 ---------------------------------------------------------- 1 file changed, 63 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index b27800e4..ab4e59c7 100644 --- a/input/device.c +++ b/input/device.c @@ -1068,69 +1068,6 @@ int input_device_unregister(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; - - sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (sk < 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)); -#if 0 - 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; -#endif - - 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); - - g_io_channel_unref(io); - - return 0; - -failed: - err = errno; - close(sk); - errno = err; - - return -1; -} - static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) { struct device *idev; -- cgit From e7d668ac9e813bc9922ee7d771848bd8822d5d1f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 20:23:45 +0000 Subject: Move D-Bus watch functions into libgdbus --- input/device.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index ab4e59c7..151ce08c 100644 --- a/input/device.c +++ b/input/device.c @@ -40,10 +40,8 @@ #include #include - #include -#include "dbus.h" #include "dbus-helper.h" #include "logging.h" #include "textfile.h" -- cgit From 15ea15b3a752f0487bc50d0ea04925f1b9d33dcb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 8 May 2008 22:19:14 +0000 Subject: Move D-Bus object and interface helpers into libgdbus --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 151ce08c..1975be16 100644 --- a/input/device.c +++ b/input/device.c @@ -41,8 +41,8 @@ #include #include +#include -#include "dbus-helper.h" #include "logging.h" #include "textfile.h" #include "uinput.h" -- cgit From 2ce4523624b67b48da037beceffe5710144850ec Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 14 May 2008 21:49:07 +0000 Subject: Add support for IdleTimeout config option --- input/device.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 1975be16..131e626d 100644 --- a/input/device.c +++ b/input/device.c @@ -67,6 +67,7 @@ struct device; struct device { bdaddr_t src; bdaddr_t dst; + int timeout; char *name; uint8_t major; uint8_t minor; @@ -84,7 +85,8 @@ struct device { GSList *devices = NULL; -static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) +static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, + uint8_t subclass, int timeout) { struct device *idev; uint32_t cls; @@ -105,6 +107,7 @@ static struct device *device_new(bdaddr_t *src, bdaddr_t *dst, uint8_t subclass) bacpy(&idev->src, src); bacpy(&idev->dst, dst); + idev->timeout = timeout; read_device_name(src, dst, &idev->name); @@ -498,11 +501,11 @@ static guint create_watch(int sk, GIOFunc cb, struct device *idev) } static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, - int ctrl_sk, int intr_sk, const char *name) + int ctrl_sk, int intr_sk, int timeout, const char *name) { struct hidp_connadd_req req; char addr[18]; - int ctl, err, timeout = 30; + int ctl, err; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { @@ -516,7 +519,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, req.ctrl_sock = ctrl_sk; req.intr_sock = intr_sk; req.flags = 0; - req.idle_to = timeout * 60; + req.idle_to = timeout; err = get_stored_device_info(src, dst, &req); if (err < 0) { @@ -561,7 +564,8 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) idev->intr_sk = g_io_channel_unix_get_fd(chan); err = hidp_connadd(&idev->src, &idev->dst, - idev->ctrl_sk, idev->intr_sk, idev->name); + idev->ctrl_sk, idev->intr_sk, + idev->timeout, idev->name); if (err < 0) goto failed; @@ -964,7 +968,7 @@ int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, const char *path; int err; - idev = device_new(src, dst, hid->subclass); + idev = device_new(src, dst, hid->subclass, hid->idle_to); if (!idev) return -EINVAL; @@ -994,7 +998,7 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, const char *path; int err; - idev = device_new(src, dst, 0); + idev = device_new(src, dst, 0, 0); if (!idev) return -EINVAL; @@ -1165,7 +1169,8 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) 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); + err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, + idev->timeout, idev->name); if (err < 0) goto error; -- cgit From 0094809955895c974fbe95f2d3ed13f420a6a6ed Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 14 May 2008 22:16:16 +0000 Subject: Make bt_io_callback_t to take both source and destination. --- input/device.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 131e626d..04cabb0f 100644 --- a/input/device.c +++ b/input/device.c @@ -371,7 +371,8 @@ failed: return FALSE; } -static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; struct fake_input *fake; @@ -553,7 +554,8 @@ cleanup: return err; } -static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; @@ -594,7 +596,8 @@ cleanup: idev->pending_connect = NULL; } -static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) +static void control_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, + const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; -- cgit From dcada8eed787ddcca19634f5a71a4dd0a2dc1856 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 15 May 2008 22:49:02 +0000 Subject: Fix wrong usage of non const bdaddr_t --- input/device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 04cabb0f..aa0689d0 100644 --- a/input/device.c +++ b/input/device.c @@ -1073,7 +1073,7 @@ int input_device_unregister(DBusConnection *conn, const char *path) return 0; } -static struct device *find_device(bdaddr_t *src, bdaddr_t *dst) +static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) { struct device *idev; GSList *list; @@ -1097,7 +1097,7 @@ gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) return TRUE; } -int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) +int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, int nsk) { struct device *idev = find_device(src, dst); if (!idev) @@ -1115,7 +1115,7 @@ int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk) return 0; } -int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst) +int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst) { struct device *idev = find_device(src, dst); if (!idev) -- cgit From 4de66ff306262950a6da54399cef89a9134247f0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 16 May 2008 09:30:18 +0000 Subject: Use EACCES instead of ENOKEY --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index aa0689d0..1794cf58 100644 --- a/input/device.c +++ b/input/device.c @@ -530,7 +530,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, if (req.subclass & 0x40) { err = encrypt_link(src, dst); - if (err < 0 && err != -ENOKEY) + if (err < 0 && err != -EACCES) goto cleanup; } -- cgit From e8961085b8d3dabc5550a4f1b309ae06065d14b4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 18:16:17 +0000 Subject: Convert the input device handling to gdbus API --- input/device.c | 187 +++++++++++++++++++++++---------------------------------- 1 file changed, 74 insertions(+), 113 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 1794cf58..1a8e0eee 100644 --- a/input/device.c +++ b/input/device.c @@ -402,7 +402,7 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, /* Replying to the requestor */ reply = dbus_message_new_method_return(idev->pending_connect); - send_message_and_unref(idev->conn, reply); + g_dbus_send_message(idev->conn, reply); /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect); @@ -545,6 +545,7 @@ static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, } err = ioctl(ctl, HIDPCONNADD, &req); + cleanup: close(ctl); @@ -580,8 +581,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, DBUS_TYPE_INVALID); /* Replying to the requestor */ - send_message_and_unref(idev->conn, - dbus_message_new_method_return(idev->pending_connect)); + g_dbus_send_reply(idev->conn, idev->pending_connect, DBUS_TYPE_INVALID); goto cleanup; @@ -698,6 +698,7 @@ static int disconnect(struct device *idev, uint32_t flags) close(ctl); return 0; + fail: err = errno; close(ctl); @@ -736,10 +737,28 @@ static int is_connected(struct device *idev) return 1; } +static inline DBusMessage *in_progress(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", + "Device connection already in progress"); +} + +static inline DBusMessage *already_connected(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", + "Already connected to a device"); +} + +static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", + err ? strerror(err) : "Connection attempt failed"); +} + /* * Input Device methods */ -static DBusHandlerResult device_connect(DBusConnection *conn, +static DBusMessage *device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; @@ -747,11 +766,10 @@ static DBusHandlerResult device_connect(DBusConnection *conn, int err; if (idev->pending_connect) - return error_in_progress(conn, msg, - "Device connection already in progress"); + return in_progress(msg); if (is_connected(idev)) - return error_already_connected(conn, msg); + return already_connected(msg); idev->pending_connect = dbus_message_ref(msg); @@ -763,153 +781,103 @@ static DBusHandlerResult device_connect(DBusConnection *conn, error("Connect failed: %s(%d)", str, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, - msg, err); + return connection_attempt_failed(msg, err); } fake->flags |= FI_FLAG_CONNECTED; - return DBUS_HANDLER_RESULT_HANDLED; + return NULL; } /* HID devices */ - err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, 0, - control_connect_cb, idev); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + 0, control_connect_cb, idev); if (err < 0) { error("L2CAP connect failed: %s(%d)", strerror(-err), -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, msg, -err); + return connection_attempt_failed(msg, -err); } - return DBUS_HANDLER_RESULT_HANDLED; + return NULL; } -static DBusHandlerResult device_disconnect(DBusConnection *conn, +static DBusMessage *device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; + int err; - if (disconnect(idev, 0) < 0) - return error_failed_errno(conn, msg, errno); + err = disconnect(idev, 0); + if (err < 0) + return create_errno_message(msg, -err); - /* Replying to the requestor */ - return send_message_and_unref(conn, - dbus_message_new_method_return(msg)); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusHandlerResult device_is_connected(DBusConnection *conn, +static DBusMessage *device_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - dbus_bool_t connected; - - connected = is_connected(idev); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + dbus_bool_t connected = is_connected(idev); - dbus_message_append_args(reply, - DBUS_TYPE_BOOLEAN, &connected, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &connected, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_adapter(DBusConnection *conn, +static DBusMessage *device_get_adapter(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&idev->src, addr); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_address(DBusConnection *conn, +static DBusMessage *device_get_address(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; char addr[18]; const char *paddr = addr; ba2str(&idev->dst, addr); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_name(DBusConnection *conn, +static DBusMessage *device_get_name(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; const char *pname = (idev->name ? idev->name : ""); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_STRING, &pname, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pname, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_product_id(DBusConnection *conn, +static DBusMessage *device_get_product_id(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->product, - DBUS_TYPE_INVALID); - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->product, + DBUS_TYPE_INVALID); } -static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, +static DBusMessage *device_get_vendor_id(DBusConnection *conn, DBusMessage *msg, void *data) { struct device *idev = data; - DBusMessage *reply; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &idev->vendor, - DBUS_TYPE_INVALID); - - return send_message_and_unref(conn, reply); + return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->vendor, + DBUS_TYPE_INVALID); } -static void device_unregister(DBusConnection *conn, void *data) +static void device_unregister(void *data) { struct device *idev = data; @@ -918,22 +886,23 @@ static void device_unregister(DBusConnection *conn, void *data) device_free(idev); } -static DBusMethodVTable device_methods[] = { - { "Connect", device_connect, "", "" }, - { "Disconnect", device_disconnect, "", "" }, - { "IsConnected", device_is_connected, "", "b" }, - { "GetAdapter", device_get_adapter, "", "s" }, - { "GetAddress", device_get_address, "", "s" }, - { "GetName", device_get_name, "", "s" }, - { "GetProductId", device_get_product_id, "", "q" }, - { "GetVendorId", device_get_vendor_id, "", "q" }, - { NULL, NULL, NULL, NULL } +static GDBusMethodTable device_methods[] = { + { "Connect", "", "", device_connect, + G_DBUS_METHOD_FLAG_ASYNC }, + { "Disconnect", "", "", device_disconnect }, + { "IsConnected", "", "b", device_is_connected }, + { "GetAdapter", "", "s", device_get_adapter }, + { "GetAddress", "", "s", device_get_address }, + { "GetName", "", "s", device_get_name }, + { "GetProductId", "", "q", device_get_product_id }, + { "GetVendorId", "", "q", device_get_vendor_id }, + { } }; -static DBusSignalVTable device_signals[] = { +static GDBusSignalTable device_signals[] = { { "Connected", "" }, { "Disconnected", "" }, - { NULL, NULL } + { } }; /* @@ -941,19 +910,11 @@ static DBusSignalVTable device_signals[] = { */ static int register_path(DBusConnection *conn, const char *path, struct device *idev) { - if (!dbus_connection_create_object_path(conn, path, - idev, device_unregister)) { - error("Input device path registration failed"); - return -EINVAL; - } - - if (!dbus_connection_register_interface(conn, path, - INPUT_DEVICE_INTERFACE, - device_methods, - device_signals, NULL)) { + if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE, + device_methods, device_signals, NULL, + NULL, device_unregister) == FALSE) { error("Failed to register %s interface to %s", - INPUT_DEVICE_INTERFACE, path); - dbus_connection_destroy_object_path(conn, path); + INPUT_DEVICE_INTERFACE, path); return -1; } -- cgit From c71805ac4bd1bd85d1d0dfc31a200a26d43a9a14 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 18:43:59 +0000 Subject: Don't forget user data on interface registration --- input/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 1a8e0eee..0f06d095 100644 --- a/input/device.c +++ b/input/device.c @@ -912,7 +912,7 @@ static int register_path(DBusConnection *conn, const char *path, struct device * { if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE, device_methods, device_signals, NULL, - NULL, device_unregister) == FALSE) { + idev, device_unregister) == FALSE) { error("Failed to register %s interface to %s", INPUT_DEVICE_INTERFACE, path); return -1; -- cgit From a7bc44bcbad838b8da5ab279a11075ae4f6f1418 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 19:35:53 +0000 Subject: Fix user data issue when removing device --- input/device.c | 57 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 0f06d095..b85f9cdb 100644 --- a/input/device.c +++ b/input/device.c @@ -990,12 +990,40 @@ int fake_input_register(DBusConnection *conn, bdaddr_t *src, return err; } +static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) +{ + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + struct device *idev = list->data; + + if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) + return idev; + } + + return NULL; +} + +static struct device *find_device_by_path(const char *path) +{ + GSList *list; + + for (list = devices; list != NULL; list = list->next) { + struct device *idev = list->data; + + if (strcmp(idev->path, path) == 0) + return idev; + } + + return NULL; +} + int input_device_unregister(DBusConnection *conn, const char *path) { struct device *idev; - if (!dbus_connection_get_object_user_data(conn, - path, (void *) &idev) || !idev) + idev = find_device_by_path(path); + if (idev == NULL) return -EINVAL; if (idev->pending_connect) { @@ -1018,35 +1046,18 @@ int input_device_unregister(DBusConnection *conn, const char *path) if (idev->intr_watch) { g_source_remove(idev->intr_watch); dbus_connection_emit_signal(conn, - path, - INPUT_DEVICE_INTERFACE, - "Disconnected", - DBUS_TYPE_INVALID); + path, INPUT_DEVICE_INTERFACE, + "Disconnected", DBUS_TYPE_INVALID); } - dbus_connection_destroy_object_path(conn, path); - dbus_connection_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); - return 0; -} - -static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst) -{ - struct device *idev; - GSList *list; - - for (list = devices; list != NULL; list = list->next) { - idev = list->data; - - if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) - return idev; - } + g_dbus_unregister_interface(conn, path, INPUT_DEVICE_INTERFACE); - return NULL; + return 0; } gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst) -- cgit From 27b076bdd6b65521f9e37fc6e088ea9396105d3b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 May 2008 22:03:43 +0000 Subject: Fix some handling of error cases --- input/device.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index b85f9cdb..261c1a58 100644 --- a/input/device.c +++ b/input/device.c @@ -371,6 +371,24 @@ failed: return FALSE; } +static inline DBusMessage *in_progress(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", + "Device connection already in progress"); +} + +static inline DBusMessage *already_connected(DBusMessage *msg) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", + "Already connected to a device"); +} + +static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) +{ + return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", + err ? strerror(err) : "Connection attempt failed"); +} + static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer user_data) { @@ -416,8 +434,9 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, return; failed: - error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); + reply = connection_attempt_failed(idev->pending_connect, err); + g_dbus_send_message(idev->conn, reply); + dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; } @@ -559,6 +578,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer user_data) { struct device *idev = user_data; + DBusMessage *reply; if (err < 0) { error("connect(): %s (%d)", strerror(-err), -err); @@ -586,8 +606,9 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, goto cleanup; failed: - error_connection_attempt_failed(idev->conn, - idev->pending_connect, -err); + reply = connection_attempt_failed(idev->pending_connect, -err); + g_dbus_send_message(idev->conn, reply); + idev->intr_sk = -1; idev->ctrl_sk = -1; @@ -737,24 +758,6 @@ static int is_connected(struct device *idev) return 1; } -static inline DBusMessage *in_progress(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", - "Device connection already in progress"); -} - -static inline DBusMessage *already_connected(DBusMessage *msg) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", - "Already connected to a device"); -} - -static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err) -{ - return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", - err ? strerror(err) : "Connection attempt failed"); -} - /* * Input Device methods */ -- cgit From f80a7215275b229a597cf8d2bbc7e4e208af522c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 7 Jun 2008 19:30:24 +0000 Subject: Use g_dbus_emit_signal for sending D-Bus signals --- input/device.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'input/device.c') diff --git a/input/device.c b/input/device.c index 261c1a58..75acaa82 100644 --- a/input/device.c +++ b/input/device.c @@ -424,7 +424,7 @@ static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, /* Sending the Connected signal */ path = dbus_message_get_path(idev->pending_connect); - dbus_connection_emit_signal(idev->conn, path, + g_dbus_emit_signal(idev->conn, path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_INVALID); @@ -462,7 +462,7 @@ static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", @@ -489,7 +489,7 @@ static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data if (cond & (G_IO_HUP | G_IO_ERR)) g_io_channel_close(chan); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Disconnected", @@ -594,7 +594,7 @@ static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src, idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", @@ -1048,12 +1048,12 @@ int input_device_unregister(DBusConnection *conn, const char *path) if (idev->intr_watch) { g_source_remove(idev->intr_watch); - dbus_connection_emit_signal(conn, + g_dbus_emit_signal(conn, path, INPUT_DEVICE_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); } - dbus_connection_emit_signal(conn, INPUT_PATH, + g_dbus_emit_signal(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE, "DeviceRemoved" , DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -1154,7 +1154,7 @@ int input_device_connadd(bdaddr_t *src, bdaddr_t *dst) idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev); idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev); - dbus_connection_emit_signal(idev->conn, + g_dbus_emit_signal(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", -- cgit