Skip to content

Commit

Permalink
HID: logitech: allow the DJ device to request the unifying name
Browse files Browse the repository at this point in the history
The names of the DJ devices are stored in the receiver. These names
can be retrieved through a HID++ command. However, the protocol says
that you have to ask the receiver for that, not the device iteself.

Introduce a special case in the DJ handling where a device can request
its unifying name, and when such a name is given, forward it also to
the corresponding device.

On the HID++ side, the receiver talks only HID++ 1.0, so we need to
implement this part of the protocol in the module.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: Andrew de los Reyes <adlr@chromium.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Benjamin Tissoires authored and Jiri Kosina committed Oct 29, 2014
1 parent 925f0f3 commit 3379782
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 7 deletions.
24 changes: 21 additions & 3 deletions drivers/hid/hid-logitech-dj.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,9 @@ static void logi_dj_ll_close(struct hid_device *hid)
dbg_hid("%s:%s\n", __func__, hid->phys);
}

static u8 unifying_name_query[] = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00};
static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5};

static int logi_dj_ll_raw_request(struct hid_device *hid,
unsigned char reportnum, __u8 *buf,
size_t count, unsigned char report_type,
Expand All @@ -682,7 +685,13 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
if (count < 2)
return -EINVAL;

buf[1] = djdev->device_index;
/* special case where we should not overwrite
* the device_index */
if (count == 7 && !memcmp(buf, unifying_name_query,
sizeof(unifying_name_query)))
buf[4] |= djdev->device_index - 1;
else
buf[1] = djdev->device_index;
return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
count, report_type, reqtype);
}
Expand Down Expand Up @@ -873,8 +882,17 @@ static int logi_dj_hidpp_event(struct hid_device *hdev,
unsigned long flags;
u8 device_index = dj_report->device_index;

if (device_index == HIDPP_RECEIVER_INDEX)
return false;
if (device_index == HIDPP_RECEIVER_INDEX) {
/* special case were the device wants to know its unifying
* name */
if (size == HIDPP_REPORT_LONG_LENGTH &&
!memcmp(data, unifying_name_answer,
sizeof(unifying_name_answer)) &&
((data[4] & 0xF0) == 0x40))
device_index = (data[4] & 0x0F) + 1;
else
return false;
}

/*
* Data is from the HID++ collection, in this case, we forward the
Expand Down
80 changes: 76 additions & 4 deletions drivers/hid/hid-logitech-hidpp.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,31 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
return ret;
}

static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count,
struct hidpp_report *response)
{
struct hidpp_report *message = kzalloc(sizeof(struct hidpp_report),
GFP_KERNEL);
int ret;

if ((report_id != REPORT_ID_HIDPP_SHORT) &&
(report_id != REPORT_ID_HIDPP_LONG))
return -EINVAL;

if (param_count > sizeof(message->rap.params))
return -EINVAL;

message->report_id = report_id;
message->rap.sub_id = sub_id;
message->rap.reg_address = reg_address;
memcpy(&message->rap.params, params, param_count);

ret = hidpp_send_message_sync(hidpp_dev, message, response);
kfree(message);
return ret;
}

static inline bool hidpp_match_answer(struct hidpp_report *question,
struct hidpp_report *answer)
{
Expand All @@ -220,6 +245,45 @@ static inline bool hidpp_match_error(struct hidpp_report *question,
(answer->fap.params[0] == question->fap.funcindex_clientid);
}

/* -------------------------------------------------------------------------- */
/* HIDP++ 1.0 commands */
/* -------------------------------------------------------------------------- */

#define HIDPP_SET_REGISTER 0x80
#define HIDPP_GET_REGISTER 0x81
#define HIDPP_SET_LONG_REGISTER 0x82
#define HIDPP_GET_LONG_REGISTER 0x83

#define HIDPP_REG_PAIRING_INFORMATION 0xB5
#define DEVICE_NAME 0x40

static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev)
{
struct hidpp_report response;
int ret;
/* hid-logitech-dj is in charge of setting the right device index */
u8 params[1] = { DEVICE_NAME };
char *name;
int len;

ret = hidpp_send_rap_command_sync(hidpp_dev,
REPORT_ID_HIDPP_SHORT,
HIDPP_GET_LONG_REGISTER,
HIDPP_REG_PAIRING_INFORMATION,
params, 1, &response);
if (ret)
return NULL;

len = response.rap.params[1];

name = kzalloc(len + 1, GFP_KERNEL);
if (!name)
return NULL;

memcpy(name, &response.rap.params[2], len);
return name;
}

/* -------------------------------------------------------------------------- */
/* 0x0000: Root */
/* -------------------------------------------------------------------------- */
Expand Down Expand Up @@ -726,13 +790,21 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
return 0;
}

static void hidpp_overwrite_name(struct hid_device *hdev)
static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
char *name;
u8 name_length;

name = hidpp_get_device_name(hidpp, &name_length);
if (use_unifying)
/*
* the device is connected through an Unifying receiver, and
* might not be already connected.
* Ask the receiver for its name.
*/
name = hidpp_get_unifying_name(hidpp);
else
name = hidpp_get_device_name(hidpp, &name_length);

if (!name)
hid_err(hdev, "unable to retrieve the name of the device");
Expand Down Expand Up @@ -783,12 +855,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto hid_parse_fail;
}

/* the device is connected, we can ask for its name */
hid_info(hdev, "HID++ %u.%u device connected.\n",
hidpp->protocol_major, hidpp->protocol_minor);
hidpp_overwrite_name(hdev);
}

hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE);

if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
ret = wtp_get_config(hidpp);
if (ret)
Expand Down

0 comments on commit 3379782

Please sign in to comment.