static void read_commands_complete(uint8_t status, uint16_t length,
					const void *param, void *user_data)
{
	const struct mgmt_rp_read_commands *rp = param;
	uint16_t num_commands, num_events;
	size_t expected_len;
	int i;

	if (status != MGMT_STATUS_SUCCESS) {
		error("Failed to read supported commands: %s (0x%02x)",
						mgmt_errstr(status), status);
		return;
	}

	if (length < sizeof(*rp)) {
		error("Wrong size of read commands response");
		return;
	}

	num_commands = btohs(rp->num_commands);
	num_events = btohs(rp->num_events);

	DBG("Number of commands: %d", num_commands);
	DBG("Number of events: %d", num_events);

	expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
						num_events * sizeof(uint16_t);

	if (length < expected_len) {
		error("Too small reply for supported commands: (%u != %zu)",
							length, expected_len);
		return;
	}

	for (i = 0; i < num_commands; i++) {
		uint16_t op = get_le16(rp->opcodes + i);

		switch (op) {
		case MGMT_OP_ADD_DEVICE:
			DBG("enabling kernel-side connection control");
			kernel_features |= KERNEL_CONN_CONTROL;
			break;
		case MGMT_OP_SET_BLOCKED_KEYS:
			DBG("kernel supports the set_blocked_keys op");
			kernel_features |= KERNEL_BLOCKED_KEYS_SUPPORTED;
			break;
		case MGMT_OP_SET_DEF_SYSTEM_CONFIG:
			DBG("kernel supports set system confic");
			kernel_features |= KERNEL_SET_SYSTEM_CONFIG;
			break;
		case MGMT_OP_READ_EXP_FEATURES_INFO:
			DBG("kernel supports exp features");
			kernel_features |= KERNEL_EXP_FEATURES;
			break;
		case MGMT_OP_ADD_EXT_ADV_PARAMS:
			DBG("kernel supports ext adv commands");
			kernel_features |= KERNEL_HAS_EXT_ADV_ADD_CMDS;
			break;
		case MGMT_OP_READ_CONTROLLER_CAP:
			DBG("kernel supports controller cap command");
			kernel_features |= KERNEL_HAS_CONTROLLER_CAP_CMD;
			break;
		default:
			break;
		}
	}

	for (i = 0; i < num_events; i++) {
		uint16_t ev = get_le16(rp->opcodes + num_commands + i);

		switch(ev) {
		case MGMT_EV_CONTROLLER_RESUME:
			DBG("kernel supports suspend/resume events");
			kernel_features |= KERNEL_HAS_RESUME_EVT;
			break;
		}
	}
}
static void read_commands_complete(uint8_t status, uint16_t length,
					const void *param, void *user_data)
{
	const struct mgmt_rp_read_commands *rp = param;
	uint16_t num_commands, num_events;
	size_t expected_len;
	int i;

	if (status != MGMT_STATUS_SUCCESS) {
		error("Failed to read supported commands: %s (0x%02x)",
						mgmt_errstr(status), status);
		return;
	}

	if (length < sizeof(*rp)) {
		error("Wrong size of read commands response");
		return;
	}

	num_commands = btohs(rp->num_commands);
	num_events = btohs(rp->num_events);

	DBG("Number of commands: %d", num_commands);
	DBG("Number of events: %d", num_events);

	expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
						num_events * sizeof(uint16_t);

	if (length < expected_len) {
		error("Too small reply for supported commands: (%u != %zu)",
							length, expected_len);
		return;
	}

	for (i = 0; i < num_commands; i++) {
		uint16_t op = get_le16(rp->opcodes + i);

		switch (op) {
		case MGMT_OP_ADD_DEVICE:
			DBG("enabling kernel-side connection control");
			kernel_features |= KERNEL_CONN_CONTROL;
			break;
		case MGMT_OP_SET_BLOCKED_KEYS:
			DBG("kernel supports the set_blocked_keys op");
			kernel_features |= KERNEL_BLOCKED_KEYS_SUPPORTED;
			break;
		case MGMT_OP_SET_DEF_SYSTEM_CONFIG:
			DBG("kernel supports set system confic");
			kernel_features |= KERNEL_SET_SYSTEM_CONFIG;
			break;
		case MGMT_OP_READ_EXP_FEATURES_INFO:
			DBG("kernel supports exp features");
			kernel_features |= KERNEL_EXP_FEATURES;
			break;
		case MGMT_OP_ADD_EXT_ADV_PARAMS:
			DBG("kernel supports ext adv commands");
			kernel_features |= KERNEL_HAS_EXT_ADV_ADD_CMDS;
			break;
		case MGMT_OP_READ_CONTROLLER_CAP:
			DBG("kernel supports controller cap command");
			kernel_features |= KERNEL_HAS_CONTROLLER_CAP_CMD;
			break;
		default:
			break;
		}
	}

	for (i = 0; i < num_events; i++) {
		uint16_t ev = get_le16(rp->opcodes + num_commands + i);

		switch(ev) {
		case MGMT_EV_CONTROLLER_RESUME:
			DBG("kernel supports suspend/resume events");
			kernel_features |= KERNEL_HAS_RESUME_EVT;
			break;
		}
	}
}