Skip to content

Commit

Permalink
HID: uhid: add ABI compatible UHID_GET_REPORT replacing UHID_FEATURE
Browse files Browse the repository at this point in the history
The old hdev->hid_get_raw_report() was broken by design. It was never
clear what kind of HW request it should trigger. Benjamin fixed that with
the core HID cleanup, though we never really adjusted uhid.

Unfortunately, our old UHID_FEATURE command was modelled around the broken
hid_get_raw_report(). We converted it silently to the new GET_REPORT and
nothing broke. Make this explicit by renaming UHID_FEATURE to
UHID_GET_REPORT and UHID_FEATURE_ANSWER to UHID_GET_REPORT_REPLY.

Note that this is 100% ABI compatible to UHID_FEATURE. This is just a
rename. But we have to keep the old definitions around to not break API.

>From now on, UHID_GET_REPORT must trigger a GET_REPORT request on the
user-space hardware layer. All the ambiguity due to the weird "feature"
name should be gone now.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
David Herrmann authored and Jiri Kosina committed Aug 25, 2014
1 parent 5942b84 commit fa71f32
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
28 changes: 14 additions & 14 deletions drivers/hid/uhid.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,16 @@ static int uhid_hid_parse(struct hid_device *hid)
return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
}

static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
__u8 *buf, size_t count, unsigned char rtype)
static int uhid_hid_get_report(struct hid_device *hid, unsigned char rnum,
__u8 *buf, size_t count, unsigned char rtype)
{
struct uhid_device *uhid = hid->driver_data;
__u8 report_type;
struct uhid_event *ev;
unsigned long flags;
int ret;
size_t uninitialized_var(len);
struct uhid_feature_answer_req *req;
struct uhid_get_report_reply_req *req;

if (!uhid->running)
return -EIO;
Expand Down Expand Up @@ -163,10 +163,10 @@ static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
}

spin_lock_irqsave(&uhid->qlock, flags);
ev->type = UHID_FEATURE;
ev->u.feature.id = ++uhid->report_id;
ev->u.feature.rnum = rnum;
ev->u.feature.rtype = report_type;
ev->type = UHID_GET_REPORT;
ev->u.get_report.id = ++uhid->report_id;
ev->u.get_report.rnum = rnum;
ev->u.get_report.rtype = report_type;

uhid->report_running = true;
uhid_queue(uhid, ev);
Expand All @@ -182,7 +182,7 @@ static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
ret = -ERESTARTSYS;
} else {
spin_lock_irqsave(&uhid->qlock, flags);
req = &uhid->report_buf.u.feature_answer;
req = &uhid->report_buf.u.get_report_reply;

if (req->err) {
ret = -EIO;
Expand Down Expand Up @@ -253,7 +253,7 @@ static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
return uhid_hid_get_report(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
/* TODO: implement proper SET_REPORT functionality */
return -ENOSYS;
Expand Down Expand Up @@ -487,8 +487,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
return 0;
}

static int uhid_dev_feature_answer(struct uhid_device *uhid,
struct uhid_event *ev)
static int uhid_dev_get_report_reply(struct uhid_device *uhid,
struct uhid_event *ev)
{
unsigned long flags;

Expand All @@ -498,7 +498,7 @@ static int uhid_dev_feature_answer(struct uhid_device *uhid,
spin_lock_irqsave(&uhid->qlock, flags);

/* id for old report; drop it silently */
if (uhid->report_id != ev->u.feature_answer.id)
if (uhid->report_id != ev->u.get_report_reply.id)
goto unlock;
if (!uhid->report_running)
goto unlock;
Expand Down Expand Up @@ -634,8 +634,8 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
case UHID_INPUT2:
ret = uhid_dev_input2(uhid, &uhid->input_buf);
break;
case UHID_FEATURE_ANSWER:
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
case UHID_GET_REPORT_REPLY:
ret = uhid_dev_get_report_reply(uhid, &uhid->input_buf);
break;
default:
ret = -EOPNOTSUPP;
Expand Down
23 changes: 21 additions & 2 deletions include/uapi/linux/uhid.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ enum uhid_event_type {
UHID_OUTPUT,
UHID_OUTPUT_EV, /* obsolete! */
UHID_INPUT,
UHID_FEATURE,
UHID_FEATURE_ANSWER,
UHID_FEATURE, /* obsolete! use UHID_GET_REPORT */
UHID_GET_REPORT = UHID_FEATURE,
UHID_FEATURE_ANSWER, /* obsolete! use UHID_GET_REPORT_REPLY */
UHID_GET_REPORT_REPLY = UHID_FEATURE_ANSWER,
UHID_CREATE2,
UHID_INPUT2,
};
Expand Down Expand Up @@ -98,19 +100,34 @@ struct uhid_output_ev_req {
__s32 value;
} __attribute__((__packed__));

/* Obsolete! Kernel uses ABI compatible UHID_GET_REPORT. */
struct uhid_feature_req {
__u32 id;
__u8 rnum;
__u8 rtype;
} __attribute__((__packed__));

struct uhid_get_report_req {
__u32 id;
__u8 rnum;
__u8 rtype;
} __attribute__((__packed__));

/* Obsolete! Use ABI compatible UHID_GET_REPORT_REPLY. */
struct uhid_feature_answer_req {
__u32 id;
__u16 err;
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));

struct uhid_get_report_reply_req {
__u32 id;
__u16 err;
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));

struct uhid_event {
__u32 type;

Expand All @@ -120,7 +137,9 @@ struct uhid_event {
struct uhid_output_req output;
struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature;
struct uhid_get_report_req get_report;
struct uhid_feature_answer_req feature_answer;
struct uhid_get_report_reply_req get_report_reply;
struct uhid_create2_req create2;
struct uhid_input2_req input2;
} u;
Expand Down

0 comments on commit fa71f32

Please sign in to comment.