Example #1
0
static gboolean intr_io_watch_cb(GIOChannel *chan, gpointer data)
{
	struct hid_device *dev = data;
	uint8_t buf[UHID_DATA_MAX];
	struct uhid_event ev;
	int fd, bread, err;

	/* Wait uHID if not ready */
	if (!dev->uhid)
		return TRUE;

	fd = g_io_channel_unix_get_fd(chan);
	bread = read(fd, buf, sizeof(buf));
	if (bread < 0) {
		error("hidhost: read from interrupt failed: %s(%d)",
						strerror(errno), -errno);
		return TRUE;
	}

	/* Discard non-data packets */
	if (bread == 0 || buf[0] != (HID_MSG_DATA | HID_DATA_TYPE_INPUT))
		return TRUE;

	/* send data to uHID device skipping HIDP header byte */
	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_INPUT;
	ev.u.input.size = bread - 1;
	memcpy(ev.u.input.data, &buf[1], ev.u.input.size);

	err = bt_uhid_send(dev->uhid, &ev);
	if (err < 0)
		DBG("bt_uhid_send: %s (%d)", strerror(-err), -err);

	return TRUE;
}
Example #2
0
static bool uhid_send_input_report(struct input_device *idev,
					const uint8_t *data, size_t size)
{
	struct uhid_event ev;
	int err;

	if (data == NULL)
		size = 0;

	if (size > sizeof(ev.u.input.data))
		size = sizeof(ev.u.input.data);

	if (!idev->uhid_created) {
		DBG("HID report (%zu bytes) dropped", size);
		return false;
	}

	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_INPUT;
	ev.u.input.size = size;

	if (size > 0)
		memcpy(ev.u.input.data, data, size);

	err = bt_uhid_send(idev->uhid, &ev);
	if (err < 0) {
		error("bt_uhid_send: %s (%d)", strerror(-err), -err);
		return false;
	}

	DBG("HID report (%zu bytes)", size);

	return true;
}
Example #3
0
static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
							gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	struct uhid_event rsp;
	int err;

	hogdev->getrep_att = 0;

	memset(&rsp, 0, sizeof(rsp));
	rsp.type = UHID_GET_REPORT_REPLY;
	rsp.u.get_report_reply.id = hogdev->getrep_id;

	if (status != 0) {
		error("Error reading Report value: %s", att_ecode2str(status));
		goto exit;
	}

	if (len == 0) {
		error("Error reading Report, length %d", len);
		status = EIO;
		goto exit;
	}

	if (pdu[0] != 0x0b) {
		error("Error reading Report, invalid response: %02x", pdu[0]);
		status = EPROTO;
		goto exit;
	}

	--len;
	++pdu;
	if (hogdev->has_report_id && len > 0) {
		--len;
		++pdu;
	}

	rsp.u.get_report_reply.size = len;
	memcpy(rsp.u.get_report_reply.data, pdu, len);

exit:
	rsp.u.get_report_reply.err = status;
	err = bt_uhid_send(hogdev->uhid, &rsp);
	if (err < 0)
		error("bt_uhid_send: %s", strerror(-err));
}
Example #4
0
static void set_report_cb(guint8 status, const guint8 *pdu,
					guint16 plen, gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	struct uhid_event rsp;
	int err;

	hogdev->setrep_att = 0;

	memset(&rsp, 0, sizeof(rsp));
	rsp.type = UHID_SET_REPORT_REPLY;
	rsp.u.set_report_reply.id = hogdev->setrep_id;
	rsp.u.set_report_reply.err = status;

	if (status != 0)
		error("Error setting Report value: %s", att_ecode2str(status));

	err = bt_uhid_send(hogdev->uhid, &rsp);
	if (err < 0)
		error("bt_uhid_send: %s", strerror(-err));
}
Example #5
0
static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
{
	struct report *report = user_data;
	struct hog_device *hogdev = report->hogdev;
	struct uhid_event ev;
	uint8_t *buf;
	int err;

	if (len < ATT_NOTIFICATION_HEADER_SIZE) {
		error("Malformed ATT notification");
		return;
	}

	pdu += ATT_NOTIFICATION_HEADER_SIZE;
	len -= ATT_NOTIFICATION_HEADER_SIZE;

	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_INPUT;
	buf = ev.u.input.data;

	if (hogdev->has_report_id) {
		buf[0] = report->id;
		len = MIN(len, sizeof(ev.u.input.data) - 1);
		memcpy(buf + 1, pdu, len);
		ev.u.input.size = ++len;
	} else {
		len = MIN(len, sizeof(ev.u.input.data));
		memcpy(buf, pdu, len);
		ev.u.input.size = len;
	}

	err = bt_uhid_send(hogdev->uhid, &ev);
	if (err < 0) {
		error("bt_uhid_send: %s (%d)", strerror(-err), -err);
		return;
	}

	DBG("HoG report (%u bytes)", ev.u.input.size);
}
Example #6
0
static bool uhid_send_feature_answer(struct input_device *idev,
					const uint8_t *data, size_t size,
					uint32_t id, uint16_t err)
{
	struct uhid_event ev;
	int ret;

	if (data == NULL)
		size = 0;

	if (size > sizeof(ev.u.feature_answer.data))
		size = sizeof(ev.u.feature_answer.data);

	if (!idev->uhid_created) {
		DBG("HID report (%zu bytes) dropped", size);
		return false;
	}

	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_FEATURE_ANSWER;
	ev.u.feature_answer.id = id;
	ev.u.feature_answer.err = err;
	ev.u.feature_answer.size = size;

	if (size > 0)
		memcpy(ev.u.feature_answer.data, data, size);

	ret = bt_uhid_send(idev->uhid, &ev);
	if (ret < 0) {
		error("bt_uhid_send: %s (%d)", strerror(-ret), -ret);
		return false;
	}

	DBG("HID report (%zu bytes)", size);

	return true;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
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);
}
Example #10
0
File: hog.c Project: aguedes/bluez
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);
}