|
23 | 23 | #define WAC_CMD_ICON_XFER 0x23
|
24 | 24 | #define WAC_CMD_ICON_BT_XFER 0x26
|
25 | 25 | #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 |
26 | 29 |
|
27 | 30 | #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
|
28 | 31 | #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
|
| 32 | +#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) |
29 | 33 |
|
30 | 34 | static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf,
|
31 | 35 | size_t size, unsigned int retries)
|
@@ -1119,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev,
|
1119 | 1123 | static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
|
1120 | 1124 | wacom_show_speed, wacom_store_speed);
|
1121 | 1125 |
|
| 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 | + |
1122 | 1309 | static struct input_dev *wacom_allocate_input(struct wacom *wacom)
|
1123 | 1310 | {
|
1124 | 1311 | struct input_dev *input_dev;
|
@@ -1164,6 +1351,8 @@ static void wacom_clean_inputs(struct wacom *wacom)
|
1164 | 1351 | else
|
1165 | 1352 | input_free_device(wacom->wacom_wac.pad_input);
|
1166 | 1353 | }
|
| 1354 | + if (wacom->remote_dir) |
| 1355 | + kobject_put(wacom->remote_dir); |
1167 | 1356 | wacom->wacom_wac.pen_input = NULL;
|
1168 | 1357 | wacom->wacom_wac.touch_input = NULL;
|
1169 | 1358 | wacom->wacom_wac.pad_input = NULL;
|
@@ -1243,10 +1432,16 @@ static int wacom_register_inputs(struct wacom *wacom)
|
1243 | 1432 | error = wacom_initialize_leds(wacom);
|
1244 | 1433 | if (error)
|
1245 | 1434 | goto fail_leds;
|
| 1435 | + |
| 1436 | + error = wacom_initialize_remote(wacom); |
| 1437 | + if (error) |
| 1438 | + goto fail_remote; |
1246 | 1439 | }
|
1247 | 1440 |
|
1248 | 1441 | return 0;
|
1249 | 1442 |
|
| 1443 | +fail_remote: |
| 1444 | + wacom_destroy_leds(wacom); |
1250 | 1445 | fail_leds:
|
1251 | 1446 | input_unregister_device(pad_input_dev);
|
1252 | 1447 | pad_input_dev = NULL;
|
|
0 commit comments