Skip to content

Commit 72b236d

Browse files
skomraJiri Kosina
authored andcommitted
HID: wacom: Add support for Express Key Remote.
This device is pad (buttons) only, there is no stylus or touch. Up to five remotes can pair with the device's associated USB dongle. Signed-off-by: Aaron Skomra <[email protected]> Reviewed-by: Jason Gerecke <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 70ee06c commit 72b236d

File tree

5 files changed

+370
-2
lines changed

5 files changed

+370
-2
lines changed

Documentation/ABI/testing/sysfs-driver-wacom

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,22 @@ Description:
7777
The format is also scrambled, like in the USB mode, and it can
7878
be summarized by converting 76543210 into GECA6420.
7979
HGFEDCBA HFDB7531
80+
81+
What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/unpair_remote
82+
Date: July 2015
83+
84+
Description:
85+
Writing the character sequence '*' followed by a newline to
86+
this file will delete all of the current pairings on the
87+
device. Other character sequences are reserved. This file is
88+
write only.
89+
90+
What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/<serial_number>/remote_mode
91+
Date: July 2015
92+
93+
Description:
94+
Reading from this file reports the mode status of the
95+
remote as indicated by the LED lights on the device. If no
96+
reports have been received from the paired device, reading
97+
from this file will report '-1'. The mode is read-only
98+
and cannot be set through the driver.

drivers/hid/wacom.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ struct wacom {
113113
struct mutex lock;
114114
struct work_struct work;
115115
struct wacom_led {
116-
u8 select[2]; /* status led selector (0..3) */
116+
u8 select[5]; /* status led selector (0..3) */
117117
u8 llv; /* status led brightness no button (1..127) */
118118
u8 hlv; /* status led brightness button pressed (1..127) */
119119
u8 img_lum; /* OLED matrix display brightness */
@@ -123,6 +123,8 @@ struct wacom {
123123
struct power_supply *ac;
124124
struct power_supply_desc battery_desc;
125125
struct power_supply_desc ac_desc;
126+
struct kobject *remote_dir;
127+
struct attribute_group remote_group[5];
126128
};
127129

128130
static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
@@ -147,4 +149,7 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
147149
struct hid_usage *usage, __s32 value);
148150
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
149151
void wacom_battery_work(struct work_struct *work);
152+
int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
153+
int index);
154+
void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);
150155
#endif

drivers/hid/wacom_sys.c

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323
#define WAC_CMD_ICON_XFER 0x23
2424
#define WAC_CMD_ICON_BT_XFER 0x26
2525
#define WAC_CMD_RETRIES 10
26+
#define WAC_CMD_DELETE_PAIRING 0x20
27+
#define WAC_CMD_UNPAIR_ALL 0xFF
28+
#define WAC_REMOTE_SERIAL_MAX_STRLEN 9
2629

2730
#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
2831
#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
32+
#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP)
2933

3034
static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf,
3135
size_t size, unsigned int retries)
@@ -1119,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev,
11191123
static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
11201124
wacom_show_speed, wacom_store_speed);
11211125

1126+
1127+
static ssize_t wacom_show_remote_mode(struct kobject *kobj,
1128+
struct kobj_attribute *kattr,
1129+
char *buf, int index)
1130+
{
1131+
struct device *dev = container_of(kobj->parent, struct device, kobj);
1132+
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
1133+
struct wacom *wacom = hid_get_drvdata(hdev);
1134+
u8 mode;
1135+
1136+
mode = wacom->led.select[index];
1137+
if (mode >= 0 && mode < 3)
1138+
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
1139+
else
1140+
return snprintf(buf, PAGE_SIZE, "%d\n", -1);
1141+
}
1142+
1143+
#define DEVICE_EKR_ATTR_GROUP(SET_ID) \
1144+
static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \
1145+
struct kobj_attribute *kattr, char *buf) \
1146+
{ \
1147+
return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \
1148+
} \
1149+
static struct kobj_attribute remote##SET_ID##_mode_attr = { \
1150+
.attr = {.name = "remote_mode", \
1151+
.mode = DEV_ATTR_RO_PERM}, \
1152+
.show = wacom_show_remote##SET_ID##_mode, \
1153+
}; \
1154+
static struct attribute *remote##SET_ID##_serial_attrs[] = { \
1155+
&remote##SET_ID##_mode_attr.attr, \
1156+
NULL \
1157+
}; \
1158+
static struct attribute_group remote##SET_ID##_serial_group = { \
1159+
.name = NULL, \
1160+
.attrs = remote##SET_ID##_serial_attrs, \
1161+
}
1162+
1163+
DEVICE_EKR_ATTR_GROUP(0);
1164+
DEVICE_EKR_ATTR_GROUP(1);
1165+
DEVICE_EKR_ATTR_GROUP(2);
1166+
DEVICE_EKR_ATTR_GROUP(3);
1167+
DEVICE_EKR_ATTR_GROUP(4);
1168+
1169+
int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
1170+
{
1171+
int error = 0;
1172+
char *buf;
1173+
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1174+
1175+
wacom_wac->serial[index] = serial;
1176+
1177+
buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
1178+
if (!buf)
1179+
return -ENOMEM;
1180+
snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
1181+
wacom->remote_group[index].name = buf;
1182+
1183+
error = sysfs_create_group(wacom->remote_dir,
1184+
&wacom->remote_group[index]);
1185+
if (error) {
1186+
hid_err(wacom->hdev,
1187+
"cannot create sysfs group err: %d\n", error);
1188+
kobject_put(wacom->remote_dir);
1189+
return error;
1190+
}
1191+
1192+
return 0;
1193+
}
1194+
1195+
void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
1196+
{
1197+
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1198+
int i;
1199+
1200+
if (!serial)
1201+
return;
1202+
1203+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1204+
if (wacom_wac->serial[i] == serial) {
1205+
wacom_wac->serial[i] = 0;
1206+
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
1207+
if (wacom->remote_group[i].name) {
1208+
sysfs_remove_group(wacom->remote_dir,
1209+
&wacom->remote_group[i]);
1210+
kfree(wacom->remote_group[i].name);
1211+
wacom->remote_group[i].name = NULL;
1212+
}
1213+
}
1214+
}
1215+
}
1216+
1217+
static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
1218+
{
1219+
const size_t buf_size = 2;
1220+
unsigned char *buf;
1221+
int retval;
1222+
1223+
buf = kzalloc(buf_size, GFP_KERNEL);
1224+
if (!buf)
1225+
return -ENOMEM;
1226+
1227+
buf[0] = WAC_CMD_DELETE_PAIRING;
1228+
buf[1] = selector;
1229+
1230+
retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf,
1231+
buf_size, WAC_CMD_RETRIES);
1232+
kfree(buf);
1233+
1234+
return retval;
1235+
}
1236+
1237+
static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
1238+
struct kobj_attribute *attr,
1239+
const char *buf, size_t count)
1240+
{
1241+
unsigned char selector = 0;
1242+
struct device *dev = container_of(kobj->parent, struct device, kobj);
1243+
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
1244+
struct wacom *wacom = hid_get_drvdata(hdev);
1245+
int err;
1246+
1247+
if (!strncmp(buf, "*\n", 2)) {
1248+
selector = WAC_CMD_UNPAIR_ALL;
1249+
} else {
1250+
hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n",
1251+
buf);
1252+
return -1;
1253+
}
1254+
1255+
mutex_lock(&wacom->lock);
1256+
1257+
err = wacom_cmd_unpair_remote(wacom, selector);
1258+
mutex_unlock(&wacom->lock);
1259+
1260+
return err < 0 ? err : count;
1261+
}
1262+
1263+
static struct kobj_attribute unpair_remote_attr = {
1264+
.attr = {.name = "unpair_remote", .mode = 0200},
1265+
.store = wacom_store_unpair_remote,
1266+
};
1267+
1268+
static const struct attribute *remote_unpair_attrs[] = {
1269+
&unpair_remote_attr.attr,
1270+
NULL
1271+
};
1272+
1273+
static int wacom_initialize_remote(struct wacom *wacom)
1274+
{
1275+
int error = 0;
1276+
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
1277+
int i;
1278+
1279+
if (wacom->wacom_wac.features.type != REMOTE)
1280+
return 0;
1281+
1282+
wacom->remote_group[0] = remote0_serial_group;
1283+
wacom->remote_group[1] = remote1_serial_group;
1284+
wacom->remote_group[2] = remote2_serial_group;
1285+
wacom->remote_group[3] = remote3_serial_group;
1286+
wacom->remote_group[4] = remote4_serial_group;
1287+
1288+
wacom->remote_dir = kobject_create_and_add("wacom_remote",
1289+
&wacom->hdev->dev.kobj);
1290+
if (!wacom->remote_dir)
1291+
return -ENOMEM;
1292+
1293+
error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
1294+
1295+
if (error) {
1296+
hid_err(wacom->hdev,
1297+
"cannot create sysfs group err: %d\n", error);
1298+
return error;
1299+
}
1300+
1301+
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
1302+
wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
1303+
wacom_wac->serial[i] = 0;
1304+
}
1305+
1306+
return 0;
1307+
}
1308+
11221309
static struct input_dev *wacom_allocate_input(struct wacom *wacom)
11231310
{
11241311
struct input_dev *input_dev;
@@ -1164,6 +1351,8 @@ static void wacom_clean_inputs(struct wacom *wacom)
11641351
else
11651352
input_free_device(wacom->wacom_wac.pad_input);
11661353
}
1354+
if (wacom->remote_dir)
1355+
kobject_put(wacom->remote_dir);
11671356
wacom->wacom_wac.pen_input = NULL;
11681357
wacom->wacom_wac.touch_input = NULL;
11691358
wacom->wacom_wac.pad_input = NULL;
@@ -1243,10 +1432,16 @@ static int wacom_register_inputs(struct wacom *wacom)
12431432
error = wacom_initialize_leds(wacom);
12441433
if (error)
12451434
goto fail_leds;
1435+
1436+
error = wacom_initialize_remote(wacom);
1437+
if (error)
1438+
goto fail_remote;
12461439
}
12471440

12481441
return 0;
12491442

1443+
fail_remote:
1444+
wacom_destroy_leds(wacom);
12501445
fail_leds:
12511446
input_unregister_device(pad_input_dev);
12521447
pad_input_dev = NULL;

0 commit comments

Comments
 (0)