static int uhid_connadd(struct input_device *idev, struct hidp_connadd_req *req) { int err; struct uhid_event ev; if (idev->uhid_created) return 0; /* create uHID device */ memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; strncpy((char *) ev.u.create.name, req->name, sizeof(ev.u.create.name) - 1); ba2str(&idev->src, (char *) ev.u.create.phys); ba2str(&idev->dst, (char *) ev.u.create.uniq); ev.u.create.vendor = req->vendor; ev.u.create.product = req->product; ev.u.create.version = req->version; ev.u.create.country = req->country; ev.u.create.bus = BUS_BLUETOOTH; ev.u.create.rd_data = req->rd_data; ev.u.create.rd_size = req->rd_size; err = bt_uhid_send(idev->uhid, &ev); if (err < 0) { error("bt_uhid_send: %s", strerror(-err)); return err; } bt_uhid_register(idev->uhid, UHID_OUTPUT, hidp_send_set_report, idev); bt_uhid_register(idev->uhid, UHID_FEATURE, hidp_send_get_report, idev); idev->uhid_created = true; return err; }
static int uhid_create(struct hid_device *dev) { struct uhid_event ev; int err; dev->uhid = bt_uhid_new_default(); if (!dev->uhid) { err = -errno; error("hidhost: Failed to create bt_uhid instance"); return err; } memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; strcpy((char *) ev.u.create.name, "bluez-input-device"); ev.u.create.bus = BUS_BLUETOOTH; ev.u.create.vendor = dev->vendor; ev.u.create.product = dev->product; ev.u.create.version = dev->version; ev.u.create.country = dev->country; ev.u.create.rd_size = dev->rd_size; ev.u.create.rd_data = dev->rd_data; err = bt_uhid_send(dev->uhid, &ev); if (err < 0) { error("hidhost: Failed to create uHID device: %s", strerror(-err)); bt_uhid_unref(dev->uhid); dev->uhid = NULL; return err; } bt_uhid_register(dev->uhid, UHID_OUTPUT, handle_uhid_output, dev); bt_hid_set_info(dev); return 0; }
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct hog_device *hogdev = user_data; struct btd_adapter *adapter = device_get_adapter(hogdev->device); uint8_t value[HOG_REPORT_MAP_MAX_SIZE]; struct uhid_event ev; uint16_t vendor_src, vendor, product, version; ssize_t vlen; char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */ int i, err; if (status != 0) { error("Report Map read failed: %s", att_ecode2str(status)); return; } vlen = dec_read_resp(pdu, plen, value, sizeof(value)); if (vlen < 0) { error("ATT protocol error"); return; } DBG("Report MAP:"); for (i = 0; i < vlen;) { ssize_t ilen = 0; bool long_item = false; if (get_descriptor_item_info(&value[i], vlen - i, &ilen, &long_item)) { /* Report ID is short item with prefix 100001xx */ if (!long_item && (value[i] & 0xfc) == 0x84) hogdev->has_report_id = TRUE; DBG("\t%s", item2string(itemstr, &value[i], ilen)); i += ilen; } else { error("Report Map parsing failed at %d", i); /* Just print remaining items at once and break */ DBG("\t%s", item2string(itemstr, &value[i], vlen - i)); break; } } vendor_src = btd_device_get_vendor_src(hogdev->device); vendor = btd_device_get_vendor(hogdev->device); product = btd_device_get_product(hogdev->device); version = btd_device_get_version(hogdev->device); DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, " "version=0x%X", vendor_src, vendor, product, version); /* create uHID device */ memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; if (device_name_known(hogdev->device)) device_get_name(hogdev->device, (char *) ev.u.create.name, sizeof(ev.u.create.name)); else strcpy((char *) ev.u.create.name, "bluez-hog-device"); ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys); ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq); ev.u.create.vendor = vendor; ev.u.create.product = product; ev.u.create.version = version; ev.u.create.country = hogdev->bcountrycode; ev.u.create.bus = BUS_BLUETOOTH; ev.u.create.rd_data = value; ev.u.create.rd_size = vlen; err = bt_uhid_send(hogdev->uhid, &ev); if (err < 0) { error("bt_uhid_send: %s", strerror(-err)); return; } bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev); bt_uhid_register(hogdev->uhid, UHID_SET_REPORT, set_report, hogdev); bt_uhid_register(hogdev->uhid, UHID_GET_REPORT, get_report, hogdev); }
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct bt_hog *hog = user_data; uint8_t value[HOG_REPORT_MAP_MAX_SIZE]; struct uhid_event ev; ssize_t vlen; char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */ int i, err; GError *gerr = NULL; if (status != 0) { error("Report Map read failed: %s", att_ecode2str(status)); return; } vlen = dec_read_resp(pdu, plen, value, sizeof(value)); if (vlen < 0) { error("ATT protocol error"); return; } DBG("Report MAP:"); for (i = 0; i < vlen;) { ssize_t ilen = 0; bool long_item = false; if (get_descriptor_item_info(&value[i], vlen - i, &ilen, &long_item)) { /* Report ID is short item with prefix 100001xx */ if (!long_item && (value[i] & 0xfc) == 0x84) hog->has_report_id = TRUE; DBG("\t%s", item2string(itemstr, &value[i], ilen)); i += ilen; } else { error("Report Map parsing failed at %d", i); /* Just print remaining items at once and break */ DBG("\t%s", item2string(itemstr, &value[i], vlen - i)); break; } } /* create uHID device */ memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; bt_io_get(g_attrib_get_channel(hog->attrib), &gerr, BT_IO_OPT_SOURCE, ev.u.create.phys, BT_IO_OPT_DEST, ev.u.create.uniq, BT_IO_OPT_INVALID); if (gerr) { error("Failed to connection details: %s", gerr->message); g_error_free(gerr); return; } strcpy((char *) ev.u.create.name, hog->name); ev.u.create.vendor = hog->vendor; ev.u.create.product = hog->product; ev.u.create.version = hog->version; ev.u.create.country = hog->bcountrycode; ev.u.create.bus = BUS_BLUETOOTH; ev.u.create.rd_data = value; ev.u.create.rd_size = vlen; err = bt_uhid_send(hog->uhid, &ev); if (err < 0) { error("bt_uhid_send: %s", strerror(-err)); return; } bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog); bt_uhid_register(hog->uhid, UHID_FEATURE, forward_report, hog); }