?? device.c
字號:
"Connected", DBUS_TYPE_INVALID); /* Replying to the requestor */ send_message_and_unref(idev->conn, dbus_message_new_method_return(idev->pending_connect)); goto cleanup;failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, err); if (isk > 0) close(isk); close(idev->ctrl_sk); 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){ int ret, csk, err; socklen_t len; 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"); 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; } /* 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); goto failed; } return FALSE;failed: if (csk > 0) close(csk); idev->ctrl_sk = -1; error_connection_attempt_failed(idev->conn, idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; 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; struct hidp_conndel_req req; struct hidp_conninfo ci; int ctl, err; /* Fake input disconnect */ if (fake) { err = fake->disconnect(idev); if (err == 0) fake->flags &= ~FI_FLAG_CONNECTED; return err; } /* 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) { error("Can't open HIDP control socket"); return -errno; } memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || (ci.state != BT_CONNECTED)) { errno = ENOTCONN; goto fail; } memset(&req, 0, sizeof(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; return -err;}static int is_connected(struct device *idev){ struct fake_input *fake = idev->fake; struct hidp_conninfo ci; int ctl; /* Fake input */ if (fake) return fake->flags & FI_FLAG_CONNECTED; /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) return 0; memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->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 device *idev = data; struct fake_input *fake = idev->fake; if (idev->pending_connect) return error_in_progress(conn, msg, "Device connection already in progress"); if (is_connected(idev)) return error_already_connected(conn, msg); idev->pending_connect = dbus_message_ref(msg); /* Fake input device */ if (fake) { if (fake->connect(idev) < 0) { int err = errno; const char *str = strerror(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; } /* 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); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; return error_connection_attempt_failed(conn, msg, err); } return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *idev = data; if (disconnect(idev, 0) < 0) return error_failed_errno(conn, msg, errno); /* Replying to the requestor */ return send_message_and_unref(conn, dbus_message_new_method_return(msg));}static DBusHandlerResult 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_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); 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){ 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);}static DBusHandlerResult 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);}static DBusHandlerResult 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);}static DBusHandlerResult 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);}static void device_unregister(DBusConnection *conn, void *data){ struct device *idev = data; /* Disconnect if applied */ disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG)); 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 DBusSignalVTable device_signals[] = { { "Connected", "" }, { "Disconnected", "" }, { NULL, NULL }};/* * Input registration functions */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)) { error("Failed to register %s interface to %s", INPUT_DEVICE_INTERFACE, path); dbus_connection_destroy_object_path(conn, path); return -1; } devices = g_slist_append(devices, idev); info("Created input device: %s", path); return 0;}int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *hid, const char **ppath){ struct device *idev; const char *path; int err; 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; idev->conn = dbus_connection_ref(conn); err = register_path(conn, path, idev); if (!err && ppath) *ppath = path; return err;}int fake_input_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst, uint8_t ch, const char **ppath){ struct device *idev; const char *path; int err; 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); /* FIXME: Missing set product and vendor */ 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); if (!err && ppath) *ppath = path; return err;}int input_device_unregister(DBusConnection *conn, const char *path){ struct device *idev; if (!dbus_connection_get_object_user_data(conn, path, (void *) &idev) || !idev) return -EINVAL; if (idev->pending_connect) { /* Pending connection running */ return -EBUSY; } del_stored_device_info(&idev->src, &idev->dst); 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->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, "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;}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; 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;}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); 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; } 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, "Connected", DBUS_TYPE_INVALID); return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -