1471d1714SBenjamin Tissoires /* 2471d1714SBenjamin Tissoires * drivers/input/tablet/wacom_sys.c 3471d1714SBenjamin Tissoires * 4471d1714SBenjamin Tissoires * USB Wacom tablet support - system specific code 5471d1714SBenjamin Tissoires */ 6471d1714SBenjamin Tissoires 7471d1714SBenjamin Tissoires /* 8471d1714SBenjamin Tissoires * This program is free software; you can redistribute it and/or modify 9471d1714SBenjamin Tissoires * it under the terms of the GNU General Public License as published by 10471d1714SBenjamin Tissoires * the Free Software Foundation; either version 2 of the License, or 11471d1714SBenjamin Tissoires * (at your option) any later version. 12471d1714SBenjamin Tissoires */ 13471d1714SBenjamin Tissoires 14471d1714SBenjamin Tissoires #include "wacom_wac.h" 15471d1714SBenjamin Tissoires #include "wacom.h" 16b58ba1baSJason Gerecke #include <linux/input/mt.h> 17471d1714SBenjamin Tissoires 18471d1714SBenjamin Tissoires #define WAC_MSG_RETRIES 5 19471d1714SBenjamin Tissoires 20912ca216SPing Cheng #define WAC_CMD_WL_LED_CONTROL 0x03 21471d1714SBenjamin Tissoires #define WAC_CMD_LED_CONTROL 0x20 22471d1714SBenjamin Tissoires #define WAC_CMD_ICON_START 0x21 23471d1714SBenjamin Tissoires #define WAC_CMD_ICON_XFER 0x23 24849e2f06SBenjamin Tissoires #define WAC_CMD_ICON_BT_XFER 0x26 25471d1714SBenjamin Tissoires #define WAC_CMD_RETRIES 10 2672b236d6SAaron Skomra #define WAC_CMD_DELETE_PAIRING 0x20 2772b236d6SAaron Skomra #define WAC_CMD_UNPAIR_ALL 0xFF 2872b236d6SAaron Skomra #define WAC_REMOTE_SERIAL_MAX_STRLEN 9 29471d1714SBenjamin Tissoires 30e0984bc3SPing Cheng #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) 31e0984bc3SPing Cheng #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) 3272b236d6SAaron Skomra #define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) 33e0984bc3SPing Cheng 34c64d8834SPing Cheng static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, 35c64d8834SPing Cheng size_t size, unsigned int retries) 36471d1714SBenjamin Tissoires { 37471d1714SBenjamin Tissoires int retval; 38471d1714SBenjamin Tissoires 39471d1714SBenjamin Tissoires do { 40c64d8834SPing Cheng retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, 41471d1714SBenjamin Tissoires HID_REQ_GET_REPORT); 42aef3156dSJason Gerecke } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); 43aef3156dSJason Gerecke 44aef3156dSJason Gerecke if (retval < 0) 45aef3156dSJason Gerecke hid_err(hdev, "wacom_get_report: ran out of retries " 46aef3156dSJason Gerecke "(last error = %d)\n", retval); 47471d1714SBenjamin Tissoires 48471d1714SBenjamin Tissoires return retval; 49471d1714SBenjamin Tissoires } 50471d1714SBenjamin Tissoires 51296b7378SPrzemo Firszt static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf, 52296b7378SPrzemo Firszt size_t size, unsigned int retries) 53471d1714SBenjamin Tissoires { 54471d1714SBenjamin Tissoires int retval; 55471d1714SBenjamin Tissoires 56471d1714SBenjamin Tissoires do { 57296b7378SPrzemo Firszt retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, 58471d1714SBenjamin Tissoires HID_REQ_SET_REPORT); 59aef3156dSJason Gerecke } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); 60aef3156dSJason Gerecke 61aef3156dSJason Gerecke if (retval < 0) 62aef3156dSJason Gerecke hid_err(hdev, "wacom_set_report: ran out of retries " 63aef3156dSJason Gerecke "(last error = %d)\n", retval); 64471d1714SBenjamin Tissoires 65471d1714SBenjamin Tissoires return retval; 66471d1714SBenjamin Tissoires } 67471d1714SBenjamin Tissoires 68471d1714SBenjamin Tissoires static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, 69471d1714SBenjamin Tissoires u8 *raw_data, int size) 70471d1714SBenjamin Tissoires { 71471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 72471d1714SBenjamin Tissoires 73471d1714SBenjamin Tissoires if (size > WACOM_PKGLEN_MAX) 74471d1714SBenjamin Tissoires return 1; 75471d1714SBenjamin Tissoires 76471d1714SBenjamin Tissoires memcpy(wacom->wacom_wac.data, raw_data, size); 77471d1714SBenjamin Tissoires 78471d1714SBenjamin Tissoires wacom_wac_irq(&wacom->wacom_wac, size); 79471d1714SBenjamin Tissoires 80471d1714SBenjamin Tissoires return 0; 81471d1714SBenjamin Tissoires } 82471d1714SBenjamin Tissoires 83471d1714SBenjamin Tissoires static int wacom_open(struct input_dev *dev) 84471d1714SBenjamin Tissoires { 85471d1714SBenjamin Tissoires struct wacom *wacom = input_get_drvdata(dev); 86471d1714SBenjamin Tissoires 87dff67416SBenjamin Tissoires return hid_hw_open(wacom->hdev); 88471d1714SBenjamin Tissoires } 89471d1714SBenjamin Tissoires 90471d1714SBenjamin Tissoires static void wacom_close(struct input_dev *dev) 91471d1714SBenjamin Tissoires { 92471d1714SBenjamin Tissoires struct wacom *wacom = input_get_drvdata(dev); 93471d1714SBenjamin Tissoires 94471d1714SBenjamin Tissoires hid_hw_close(wacom->hdev); 95471d1714SBenjamin Tissoires } 96471d1714SBenjamin Tissoires 97471d1714SBenjamin Tissoires /* 98471d1714SBenjamin Tissoires * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res. 99471d1714SBenjamin Tissoires */ 100471d1714SBenjamin Tissoires static int wacom_calc_hid_res(int logical_extents, int physical_extents, 101471d1714SBenjamin Tissoires unsigned unit, int exponent) 102471d1714SBenjamin Tissoires { 103471d1714SBenjamin Tissoires struct hid_field field = { 104471d1714SBenjamin Tissoires .logical_maximum = logical_extents, 105471d1714SBenjamin Tissoires .physical_maximum = physical_extents, 106471d1714SBenjamin Tissoires .unit = unit, 107471d1714SBenjamin Tissoires .unit_exponent = exponent, 108471d1714SBenjamin Tissoires }; 109471d1714SBenjamin Tissoires 110471d1714SBenjamin Tissoires return hidinput_calc_abs_res(&field, ABS_X); 111471d1714SBenjamin Tissoires } 112471d1714SBenjamin Tissoires 113471d1714SBenjamin Tissoires static void wacom_feature_mapping(struct hid_device *hdev, 114471d1714SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 115471d1714SBenjamin Tissoires { 116471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 117471d1714SBenjamin Tissoires struct wacom_features *features = &wacom->wacom_wac.features; 1185ae6e89fSBenjamin Tissoires struct hid_data *hid_data = &wacom->wacom_wac.hid_data; 1198ffffd52SBenjamin Tissoires u8 *data; 1208ffffd52SBenjamin Tissoires int ret; 121471d1714SBenjamin Tissoires 122471d1714SBenjamin Tissoires switch (usage->hid) { 123471d1714SBenjamin Tissoires case HID_DG_CONTACTMAX: 124471d1714SBenjamin Tissoires /* leave touch_max as is if predefined */ 1258ffffd52SBenjamin Tissoires if (!features->touch_max) { 1268ffffd52SBenjamin Tissoires /* read manually */ 1278ffffd52SBenjamin Tissoires data = kzalloc(2, GFP_KERNEL); 1288ffffd52SBenjamin Tissoires if (!data) 1298ffffd52SBenjamin Tissoires break; 1308ffffd52SBenjamin Tissoires data[0] = field->report->id; 1318ffffd52SBenjamin Tissoires ret = wacom_get_report(hdev, HID_FEATURE_REPORT, 13205e8fd92SJason Gerecke data, 2, WAC_CMD_RETRIES); 13305e8fd92SJason Gerecke if (ret == 2) { 1348ffffd52SBenjamin Tissoires features->touch_max = data[1]; 13505e8fd92SJason Gerecke } else { 13605e8fd92SJason Gerecke features->touch_max = 16; 13705e8fd92SJason Gerecke hid_warn(hdev, "wacom_feature_mapping: " 13805e8fd92SJason Gerecke "could not get HID_DG_CONTACTMAX, " 13905e8fd92SJason Gerecke "defaulting to %d\n", 14005e8fd92SJason Gerecke features->touch_max); 14105e8fd92SJason Gerecke } 1428ffffd52SBenjamin Tissoires kfree(data); 1438ffffd52SBenjamin Tissoires } 144471d1714SBenjamin Tissoires break; 1455ae6e89fSBenjamin Tissoires case HID_DG_INPUTMODE: 1465ae6e89fSBenjamin Tissoires /* Ignore if value index is out of bounds. */ 1475ae6e89fSBenjamin Tissoires if (usage->usage_index >= field->report_count) { 1485ae6e89fSBenjamin Tissoires dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); 1495ae6e89fSBenjamin Tissoires break; 1505ae6e89fSBenjamin Tissoires } 1515ae6e89fSBenjamin Tissoires 1525ae6e89fSBenjamin Tissoires hid_data->inputmode = field->report->id; 1535ae6e89fSBenjamin Tissoires hid_data->inputmode_index = usage->usage_index; 1545ae6e89fSBenjamin Tissoires break; 155471d1714SBenjamin Tissoires } 156471d1714SBenjamin Tissoires } 157471d1714SBenjamin Tissoires 158471d1714SBenjamin Tissoires /* 159471d1714SBenjamin Tissoires * Interface Descriptor of wacom devices can be incomplete and 160471d1714SBenjamin Tissoires * inconsistent so wacom_features table is used to store stylus 161471d1714SBenjamin Tissoires * device's packet lengths, various maximum values, and tablet 162471d1714SBenjamin Tissoires * resolution based on product ID's. 163471d1714SBenjamin Tissoires * 164471d1714SBenjamin Tissoires * For devices that contain 2 interfaces, wacom_features table is 165471d1714SBenjamin Tissoires * inaccurate for the touch interface. Since the Interface Descriptor 166471d1714SBenjamin Tissoires * for touch interfaces has pretty complete data, this function exists 167471d1714SBenjamin Tissoires * to query tablet for this missing information instead of hard coding in 168471d1714SBenjamin Tissoires * an additional table. 169471d1714SBenjamin Tissoires * 170471d1714SBenjamin Tissoires * A typical Interface Descriptor for a stylus will contain a 171471d1714SBenjamin Tissoires * boot mouse application collection that is not of interest and this 172471d1714SBenjamin Tissoires * function will ignore it. 173471d1714SBenjamin Tissoires * 174471d1714SBenjamin Tissoires * It also contains a digitizer application collection that also is not 175471d1714SBenjamin Tissoires * of interest since any information it contains would be duplicate 176471d1714SBenjamin Tissoires * of what is in wacom_features. Usually it defines a report of an array 177471d1714SBenjamin Tissoires * of bytes that could be used as max length of the stylus packet returned. 178471d1714SBenjamin Tissoires * If it happens to define a Digitizer-Stylus Physical Collection then 179471d1714SBenjamin Tissoires * the X and Y logical values contain valid data but it is ignored. 180471d1714SBenjamin Tissoires * 181471d1714SBenjamin Tissoires * A typical Interface Descriptor for a touch interface will contain a 182471d1714SBenjamin Tissoires * Digitizer-Finger Physical Collection which will define both logical 183471d1714SBenjamin Tissoires * X/Y maximum as well as the physical size of tablet. Since touch 184471d1714SBenjamin Tissoires * interfaces haven't supported pressure or distance, this is enough 185471d1714SBenjamin Tissoires * information to override invalid values in the wacom_features table. 186471d1714SBenjamin Tissoires * 187471d1714SBenjamin Tissoires * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful 188471d1714SBenjamin Tissoires * data. We deal with them after returning from this function. 189471d1714SBenjamin Tissoires */ 190471d1714SBenjamin Tissoires static void wacom_usage_mapping(struct hid_device *hdev, 191471d1714SBenjamin Tissoires struct hid_field *field, struct hid_usage *usage) 192471d1714SBenjamin Tissoires { 193471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 194471d1714SBenjamin Tissoires struct wacom_features *features = &wacom->wacom_wac.features; 195d97a5522SBenjamin Tissoires bool finger = WACOM_FINGER_FIELD(field); 196d97a5522SBenjamin Tissoires bool pen = WACOM_PEN_FIELD(field); 197471d1714SBenjamin Tissoires 198471d1714SBenjamin Tissoires /* 199471d1714SBenjamin Tissoires * Requiring Stylus Usage will ignore boot mouse 200471d1714SBenjamin Tissoires * X/Y values and some cases of invalid Digitizer X/Y 201471d1714SBenjamin Tissoires * values commonly reported. 202471d1714SBenjamin Tissoires */ 203042628abSJason Gerecke if (pen) 204aa86b18cSJason Gerecke features->device_type |= WACOM_DEVICETYPE_PEN; 205042628abSJason Gerecke else if (finger) 206aa86b18cSJason Gerecke features->device_type |= WACOM_DEVICETYPE_TOUCH; 207042628abSJason Gerecke else 208471d1714SBenjamin Tissoires return; 209471d1714SBenjamin Tissoires 21030ebc1aeSPing Cheng /* 21130ebc1aeSPing Cheng * Bamboo models do not support HID_DG_CONTACTMAX. 21230ebc1aeSPing Cheng * And, Bamboo Pen only descriptor contains touch. 21330ebc1aeSPing Cheng */ 214*3b164a00SPing Cheng if (features->type > BAMBOO_PT) { 21530ebc1aeSPing Cheng /* ISDv4 touch devices at least supports one touch point */ 216471d1714SBenjamin Tissoires if (finger && !features->touch_max) 217471d1714SBenjamin Tissoires features->touch_max = 1; 21830ebc1aeSPing Cheng } 219471d1714SBenjamin Tissoires 220471d1714SBenjamin Tissoires switch (usage->hid) { 221471d1714SBenjamin Tissoires case HID_GD_X: 222471d1714SBenjamin Tissoires features->x_max = field->logical_maximum; 223471d1714SBenjamin Tissoires if (finger) { 224471d1714SBenjamin Tissoires features->x_phy = field->physical_maximum; 225*3b164a00SPing Cheng if ((features->type != BAMBOO_PT) && 226*3b164a00SPing Cheng (features->type != BAMBOO_TOUCH)) { 227471d1714SBenjamin Tissoires features->unit = field->unit; 228471d1714SBenjamin Tissoires features->unitExpo = field->unit_exponent; 229471d1714SBenjamin Tissoires } 230471d1714SBenjamin Tissoires } 231471d1714SBenjamin Tissoires break; 232471d1714SBenjamin Tissoires case HID_GD_Y: 233471d1714SBenjamin Tissoires features->y_max = field->logical_maximum; 234471d1714SBenjamin Tissoires if (finger) { 235471d1714SBenjamin Tissoires features->y_phy = field->physical_maximum; 236*3b164a00SPing Cheng if ((features->type != BAMBOO_PT) && 237*3b164a00SPing Cheng (features->type != BAMBOO_TOUCH)) { 238471d1714SBenjamin Tissoires features->unit = field->unit; 239471d1714SBenjamin Tissoires features->unitExpo = field->unit_exponent; 240471d1714SBenjamin Tissoires } 241471d1714SBenjamin Tissoires } 242471d1714SBenjamin Tissoires break; 243471d1714SBenjamin Tissoires case HID_DG_TIPPRESSURE: 244471d1714SBenjamin Tissoires if (pen) 245471d1714SBenjamin Tissoires features->pressure_max = field->logical_maximum; 246471d1714SBenjamin Tissoires break; 247471d1714SBenjamin Tissoires } 2487704ac93SBenjamin Tissoires 2497704ac93SBenjamin Tissoires if (features->type == HID_GENERIC) 2507704ac93SBenjamin Tissoires wacom_wac_usage_mapping(hdev, field, usage); 251471d1714SBenjamin Tissoires } 252471d1714SBenjamin Tissoires 253b58ba1baSJason Gerecke static void wacom_post_parse_hid(struct hid_device *hdev, 254b58ba1baSJason Gerecke struct wacom_features *features) 255b58ba1baSJason Gerecke { 256b58ba1baSJason Gerecke struct wacom *wacom = hid_get_drvdata(hdev); 257b58ba1baSJason Gerecke struct wacom_wac *wacom_wac = &wacom->wacom_wac; 258b58ba1baSJason Gerecke 259b58ba1baSJason Gerecke if (features->type == HID_GENERIC) { 260b58ba1baSJason Gerecke /* Any last-minute generic device setup */ 261b58ba1baSJason Gerecke if (features->touch_max > 1) { 2622a6cdbddSJason Gerecke input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max, 263b58ba1baSJason Gerecke INPUT_MT_DIRECT); 264b58ba1baSJason Gerecke } 265b58ba1baSJason Gerecke } 266b58ba1baSJason Gerecke } 267b58ba1baSJason Gerecke 268471d1714SBenjamin Tissoires static void wacom_parse_hid(struct hid_device *hdev, 269471d1714SBenjamin Tissoires struct wacom_features *features) 270471d1714SBenjamin Tissoires { 271471d1714SBenjamin Tissoires struct hid_report_enum *rep_enum; 272471d1714SBenjamin Tissoires struct hid_report *hreport; 273471d1714SBenjamin Tissoires int i, j; 274471d1714SBenjamin Tissoires 275471d1714SBenjamin Tissoires /* check features first */ 276471d1714SBenjamin Tissoires rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 277471d1714SBenjamin Tissoires list_for_each_entry(hreport, &rep_enum->report_list, list) { 278471d1714SBenjamin Tissoires for (i = 0; i < hreport->maxfield; i++) { 279471d1714SBenjamin Tissoires /* Ignore if report count is out of bounds. */ 280471d1714SBenjamin Tissoires if (hreport->field[i]->report_count < 1) 281471d1714SBenjamin Tissoires continue; 282471d1714SBenjamin Tissoires 283471d1714SBenjamin Tissoires for (j = 0; j < hreport->field[i]->maxusage; j++) { 284471d1714SBenjamin Tissoires wacom_feature_mapping(hdev, hreport->field[i], 285471d1714SBenjamin Tissoires hreport->field[i]->usage + j); 286471d1714SBenjamin Tissoires } 287471d1714SBenjamin Tissoires } 288471d1714SBenjamin Tissoires } 289471d1714SBenjamin Tissoires 290471d1714SBenjamin Tissoires /* now check the input usages */ 291471d1714SBenjamin Tissoires rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; 292471d1714SBenjamin Tissoires list_for_each_entry(hreport, &rep_enum->report_list, list) { 293471d1714SBenjamin Tissoires 294471d1714SBenjamin Tissoires if (!hreport->maxfield) 295471d1714SBenjamin Tissoires continue; 296471d1714SBenjamin Tissoires 297471d1714SBenjamin Tissoires for (i = 0; i < hreport->maxfield; i++) 298471d1714SBenjamin Tissoires for (j = 0; j < hreport->field[i]->maxusage; j++) 299471d1714SBenjamin Tissoires wacom_usage_mapping(hdev, hreport->field[i], 300471d1714SBenjamin Tissoires hreport->field[i]->usage + j); 301471d1714SBenjamin Tissoires } 302b58ba1baSJason Gerecke 303b58ba1baSJason Gerecke wacom_post_parse_hid(hdev, features); 304471d1714SBenjamin Tissoires } 305471d1714SBenjamin Tissoires 3065ae6e89fSBenjamin Tissoires static int wacom_hid_set_device_mode(struct hid_device *hdev) 3075ae6e89fSBenjamin Tissoires { 3085ae6e89fSBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 3095ae6e89fSBenjamin Tissoires struct hid_data *hid_data = &wacom->wacom_wac.hid_data; 3105ae6e89fSBenjamin Tissoires struct hid_report *r; 3115ae6e89fSBenjamin Tissoires struct hid_report_enum *re; 3125ae6e89fSBenjamin Tissoires 3135ae6e89fSBenjamin Tissoires if (hid_data->inputmode < 0) 3145ae6e89fSBenjamin Tissoires return 0; 3155ae6e89fSBenjamin Tissoires 3165ae6e89fSBenjamin Tissoires re = &(hdev->report_enum[HID_FEATURE_REPORT]); 3175ae6e89fSBenjamin Tissoires r = re->report_id_hash[hid_data->inputmode]; 3185ae6e89fSBenjamin Tissoires if (r) { 3195ae6e89fSBenjamin Tissoires r->field[0]->value[hid_data->inputmode_index] = 2; 3205ae6e89fSBenjamin Tissoires hid_hw_request(hdev, r, HID_REQ_SET_REPORT); 3215ae6e89fSBenjamin Tissoires } 3225ae6e89fSBenjamin Tissoires return 0; 3235ae6e89fSBenjamin Tissoires } 3245ae6e89fSBenjamin Tissoires 325471d1714SBenjamin Tissoires static int wacom_set_device_mode(struct hid_device *hdev, int report_id, 326471d1714SBenjamin Tissoires int length, int mode) 327471d1714SBenjamin Tissoires { 328471d1714SBenjamin Tissoires unsigned char *rep_data; 329471d1714SBenjamin Tissoires int error = -ENOMEM, limit = 0; 330471d1714SBenjamin Tissoires 331471d1714SBenjamin Tissoires rep_data = kzalloc(length, GFP_KERNEL); 332471d1714SBenjamin Tissoires if (!rep_data) 333471d1714SBenjamin Tissoires return error; 334471d1714SBenjamin Tissoires 335471d1714SBenjamin Tissoires do { 336471d1714SBenjamin Tissoires rep_data[0] = report_id; 337471d1714SBenjamin Tissoires rep_data[1] = mode; 338471d1714SBenjamin Tissoires 339296b7378SPrzemo Firszt error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 340296b7378SPrzemo Firszt length, 1); 341471d1714SBenjamin Tissoires if (error >= 0) 342471d1714SBenjamin Tissoires error = wacom_get_report(hdev, HID_FEATURE_REPORT, 343c64d8834SPing Cheng rep_data, length, 1); 344a1c173daSJason Gerecke } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); 345471d1714SBenjamin Tissoires 346471d1714SBenjamin Tissoires kfree(rep_data); 347471d1714SBenjamin Tissoires 348471d1714SBenjamin Tissoires return error < 0 ? error : 0; 349471d1714SBenjamin Tissoires } 350471d1714SBenjamin Tissoires 351f81a1295SBenjamin Tissoires static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed, 352f81a1295SBenjamin Tissoires struct wacom_features *features) 353f81a1295SBenjamin Tissoires { 354387142bbSBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 355387142bbSBenjamin Tissoires int ret; 356387142bbSBenjamin Tissoires u8 rep_data[2]; 357387142bbSBenjamin Tissoires 358387142bbSBenjamin Tissoires switch (features->type) { 359387142bbSBenjamin Tissoires case GRAPHIRE_BT: 360387142bbSBenjamin Tissoires rep_data[0] = 0x03; 361387142bbSBenjamin Tissoires rep_data[1] = 0x00; 362296b7378SPrzemo Firszt ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2, 363296b7378SPrzemo Firszt 3); 364387142bbSBenjamin Tissoires 365387142bbSBenjamin Tissoires if (ret >= 0) { 366387142bbSBenjamin Tissoires rep_data[0] = speed == 0 ? 0x05 : 0x06; 367387142bbSBenjamin Tissoires rep_data[1] = 0x00; 368387142bbSBenjamin Tissoires 369387142bbSBenjamin Tissoires ret = wacom_set_report(hdev, HID_FEATURE_REPORT, 370296b7378SPrzemo Firszt rep_data, 2, 3); 371387142bbSBenjamin Tissoires 372387142bbSBenjamin Tissoires if (ret >= 0) { 373387142bbSBenjamin Tissoires wacom->wacom_wac.bt_high_speed = speed; 374387142bbSBenjamin Tissoires return 0; 375387142bbSBenjamin Tissoires } 376387142bbSBenjamin Tissoires } 377387142bbSBenjamin Tissoires 378387142bbSBenjamin Tissoires /* 379387142bbSBenjamin Tissoires * Note that if the raw queries fail, it's not a hard failure 380387142bbSBenjamin Tissoires * and it is safe to continue 381387142bbSBenjamin Tissoires */ 382387142bbSBenjamin Tissoires hid_warn(hdev, "failed to poke device, command %d, err %d\n", 383387142bbSBenjamin Tissoires rep_data[0], ret); 384387142bbSBenjamin Tissoires break; 38581af7e61SBenjamin Tissoires case INTUOS4WL: 38681af7e61SBenjamin Tissoires if (speed == 1) 38781af7e61SBenjamin Tissoires wacom->wacom_wac.bt_features &= ~0x20; 38881af7e61SBenjamin Tissoires else 38981af7e61SBenjamin Tissoires wacom->wacom_wac.bt_features |= 0x20; 39081af7e61SBenjamin Tissoires 39181af7e61SBenjamin Tissoires rep_data[0] = 0x03; 39281af7e61SBenjamin Tissoires rep_data[1] = wacom->wacom_wac.bt_features; 39381af7e61SBenjamin Tissoires 394296b7378SPrzemo Firszt ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2, 395296b7378SPrzemo Firszt 1); 39681af7e61SBenjamin Tissoires if (ret >= 0) 39781af7e61SBenjamin Tissoires wacom->wacom_wac.bt_high_speed = speed; 39881af7e61SBenjamin Tissoires break; 399387142bbSBenjamin Tissoires } 400387142bbSBenjamin Tissoires 401f81a1295SBenjamin Tissoires return 0; 402f81a1295SBenjamin Tissoires } 403f81a1295SBenjamin Tissoires 404471d1714SBenjamin Tissoires /* 405471d1714SBenjamin Tissoires * Switch the tablet into its most-capable mode. Wacom tablets are 406471d1714SBenjamin Tissoires * typically configured to power-up in a mode which sends mouse-like 407471d1714SBenjamin Tissoires * reports to the OS. To get absolute position, pressure data, etc. 408471d1714SBenjamin Tissoires * from the tablet, it is necessary to switch the tablet out of this 409471d1714SBenjamin Tissoires * mode and into one which sends the full range of tablet data. 410471d1714SBenjamin Tissoires */ 411471d1714SBenjamin Tissoires static int wacom_query_tablet_data(struct hid_device *hdev, 412471d1714SBenjamin Tissoires struct wacom_features *features) 413471d1714SBenjamin Tissoires { 414f81a1295SBenjamin Tissoires if (hdev->bus == BUS_BLUETOOTH) 415f81a1295SBenjamin Tissoires return wacom_bt_query_tablet_data(hdev, 1, features); 416f81a1295SBenjamin Tissoires 4175ae6e89fSBenjamin Tissoires if (features->type == HID_GENERIC) 4185ae6e89fSBenjamin Tissoires return wacom_hid_set_device_mode(hdev); 4195ae6e89fSBenjamin Tissoires 420aa86b18cSJason Gerecke if (features->device_type & WACOM_DEVICETYPE_TOUCH) { 421471d1714SBenjamin Tissoires if (features->type > TABLETPC) { 422471d1714SBenjamin Tissoires /* MT Tablet PC touch */ 423471d1714SBenjamin Tissoires return wacom_set_device_mode(hdev, 3, 4, 4); 424471d1714SBenjamin Tissoires } 425471d1714SBenjamin Tissoires else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) { 426471d1714SBenjamin Tissoires return wacom_set_device_mode(hdev, 18, 3, 2); 427471d1714SBenjamin Tissoires } 428500d4160SPing Cheng else if (features->type == WACOM_27QHDT) { 429500d4160SPing Cheng return wacom_set_device_mode(hdev, 131, 3, 2); 430500d4160SPing Cheng } 4318c97a765SBenjamin Tissoires else if (features->type == BAMBOO_PAD) { 4328c97a765SBenjamin Tissoires return wacom_set_device_mode(hdev, 2, 2, 2); 4338c97a765SBenjamin Tissoires } 434aa86b18cSJason Gerecke } else if (features->device_type & WACOM_DEVICETYPE_PEN) { 435471d1714SBenjamin Tissoires if (features->type <= BAMBOO_PT && features->type != WIRELESS) { 436471d1714SBenjamin Tissoires return wacom_set_device_mode(hdev, 2, 2, 2); 437471d1714SBenjamin Tissoires } 438471d1714SBenjamin Tissoires } 439471d1714SBenjamin Tissoires 440471d1714SBenjamin Tissoires return 0; 441471d1714SBenjamin Tissoires } 442471d1714SBenjamin Tissoires 443471d1714SBenjamin Tissoires static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, 444471d1714SBenjamin Tissoires struct wacom_features *features) 445471d1714SBenjamin Tissoires { 446471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 447471d1714SBenjamin Tissoires struct usb_interface *intf = wacom->intf; 448471d1714SBenjamin Tissoires 449471d1714SBenjamin Tissoires /* default features */ 450471d1714SBenjamin Tissoires features->x_fuzz = 4; 451471d1714SBenjamin Tissoires features->y_fuzz = 4; 452471d1714SBenjamin Tissoires features->pressure_fuzz = 0; 453471d1714SBenjamin Tissoires features->distance_fuzz = 0; 454471d1714SBenjamin Tissoires 455471d1714SBenjamin Tissoires /* 456471d1714SBenjamin Tissoires * The wireless device HID is basic and layout conflicts with 457471d1714SBenjamin Tissoires * other tablets (monitor and touch interface can look like pen). 458471d1714SBenjamin Tissoires * Skip the query for this type and modify defaults based on 459471d1714SBenjamin Tissoires * interface number. 460471d1714SBenjamin Tissoires */ 461471d1714SBenjamin Tissoires if (features->type == WIRELESS) { 4623f14a63aSJason Gerecke if (intf->cur_altsetting->desc.bInterfaceNumber == 0) 463ccad85ccSJason Gerecke features->device_type = WACOM_DEVICETYPE_WL_MONITOR; 4643f14a63aSJason Gerecke else 465aa86b18cSJason Gerecke features->device_type = WACOM_DEVICETYPE_NONE; 4663f14a63aSJason Gerecke return; 467471d1714SBenjamin Tissoires } 468471d1714SBenjamin Tissoires 469471d1714SBenjamin Tissoires wacom_parse_hid(hdev, features); 470471d1714SBenjamin Tissoires } 471471d1714SBenjamin Tissoires 472471d1714SBenjamin Tissoires struct wacom_hdev_data { 473471d1714SBenjamin Tissoires struct list_head list; 474471d1714SBenjamin Tissoires struct kref kref; 475471d1714SBenjamin Tissoires struct hid_device *dev; 476471d1714SBenjamin Tissoires struct wacom_shared shared; 477471d1714SBenjamin Tissoires }; 478471d1714SBenjamin Tissoires 479471d1714SBenjamin Tissoires static LIST_HEAD(wacom_udev_list); 480471d1714SBenjamin Tissoires static DEFINE_MUTEX(wacom_udev_list_lock); 481471d1714SBenjamin Tissoires 482471d1714SBenjamin Tissoires static bool wacom_are_sibling(struct hid_device *hdev, 483471d1714SBenjamin Tissoires struct hid_device *sibling) 484471d1714SBenjamin Tissoires { 485471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 486471d1714SBenjamin Tissoires struct wacom_features *features = &wacom->wacom_wac.features; 487471d1714SBenjamin Tissoires int vid = features->oVid; 488471d1714SBenjamin Tissoires int pid = features->oPid; 489471d1714SBenjamin Tissoires int n1,n2; 490471d1714SBenjamin Tissoires 491471d1714SBenjamin Tissoires if (vid == 0 && pid == 0) { 492471d1714SBenjamin Tissoires vid = hdev->vendor; 493471d1714SBenjamin Tissoires pid = hdev->product; 494471d1714SBenjamin Tissoires } 495471d1714SBenjamin Tissoires 496471d1714SBenjamin Tissoires if (vid != sibling->vendor || pid != sibling->product) 497471d1714SBenjamin Tissoires return false; 498471d1714SBenjamin Tissoires 499471d1714SBenjamin Tissoires /* Compare the physical path. */ 500471d1714SBenjamin Tissoires n1 = strrchr(hdev->phys, '.') - hdev->phys; 501471d1714SBenjamin Tissoires n2 = strrchr(sibling->phys, '.') - sibling->phys; 502471d1714SBenjamin Tissoires if (n1 != n2 || n1 <= 0 || n2 <= 0) 503471d1714SBenjamin Tissoires return false; 504471d1714SBenjamin Tissoires 505471d1714SBenjamin Tissoires return !strncmp(hdev->phys, sibling->phys, n1); 506471d1714SBenjamin Tissoires } 507471d1714SBenjamin Tissoires 508471d1714SBenjamin Tissoires static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev) 509471d1714SBenjamin Tissoires { 510471d1714SBenjamin Tissoires struct wacom_hdev_data *data; 511471d1714SBenjamin Tissoires 512471d1714SBenjamin Tissoires list_for_each_entry(data, &wacom_udev_list, list) { 513471d1714SBenjamin Tissoires if (wacom_are_sibling(hdev, data->dev)) { 514471d1714SBenjamin Tissoires kref_get(&data->kref); 515471d1714SBenjamin Tissoires return data; 516471d1714SBenjamin Tissoires } 517471d1714SBenjamin Tissoires } 518471d1714SBenjamin Tissoires 519471d1714SBenjamin Tissoires return NULL; 520471d1714SBenjamin Tissoires } 521471d1714SBenjamin Tissoires 522471d1714SBenjamin Tissoires static int wacom_add_shared_data(struct hid_device *hdev) 523471d1714SBenjamin Tissoires { 524471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 525471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac = &wacom->wacom_wac; 526471d1714SBenjamin Tissoires struct wacom_hdev_data *data; 527471d1714SBenjamin Tissoires int retval = 0; 528471d1714SBenjamin Tissoires 529471d1714SBenjamin Tissoires mutex_lock(&wacom_udev_list_lock); 530471d1714SBenjamin Tissoires 531471d1714SBenjamin Tissoires data = wacom_get_hdev_data(hdev); 532471d1714SBenjamin Tissoires if (!data) { 533471d1714SBenjamin Tissoires data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL); 534471d1714SBenjamin Tissoires if (!data) { 535471d1714SBenjamin Tissoires retval = -ENOMEM; 536471d1714SBenjamin Tissoires goto out; 537471d1714SBenjamin Tissoires } 538471d1714SBenjamin Tissoires 539471d1714SBenjamin Tissoires kref_init(&data->kref); 540471d1714SBenjamin Tissoires data->dev = hdev; 541471d1714SBenjamin Tissoires list_add_tail(&data->list, &wacom_udev_list); 542471d1714SBenjamin Tissoires } 543471d1714SBenjamin Tissoires 544471d1714SBenjamin Tissoires wacom_wac->shared = &data->shared; 545471d1714SBenjamin Tissoires 546aa86b18cSJason Gerecke if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) 547a97ac104SBenjamin Tissoires wacom_wac->shared->touch = hdev; 548aa86b18cSJason Gerecke else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN) 549a97ac104SBenjamin Tissoires wacom_wac->shared->pen = hdev; 550a97ac104SBenjamin Tissoires 551471d1714SBenjamin Tissoires out: 552471d1714SBenjamin Tissoires mutex_unlock(&wacom_udev_list_lock); 553471d1714SBenjamin Tissoires return retval; 554471d1714SBenjamin Tissoires } 555471d1714SBenjamin Tissoires 556471d1714SBenjamin Tissoires static void wacom_release_shared_data(struct kref *kref) 557471d1714SBenjamin Tissoires { 558471d1714SBenjamin Tissoires struct wacom_hdev_data *data = 559471d1714SBenjamin Tissoires container_of(kref, struct wacom_hdev_data, kref); 560471d1714SBenjamin Tissoires 561471d1714SBenjamin Tissoires mutex_lock(&wacom_udev_list_lock); 562471d1714SBenjamin Tissoires list_del(&data->list); 563471d1714SBenjamin Tissoires mutex_unlock(&wacom_udev_list_lock); 564471d1714SBenjamin Tissoires 565471d1714SBenjamin Tissoires kfree(data); 566471d1714SBenjamin Tissoires } 567471d1714SBenjamin Tissoires 568a97ac104SBenjamin Tissoires static void wacom_remove_shared_data(struct wacom *wacom) 569471d1714SBenjamin Tissoires { 570471d1714SBenjamin Tissoires struct wacom_hdev_data *data; 571a97ac104SBenjamin Tissoires struct wacom_wac *wacom_wac = &wacom->wacom_wac; 572471d1714SBenjamin Tissoires 573a97ac104SBenjamin Tissoires if (wacom_wac->shared) { 574a97ac104SBenjamin Tissoires data = container_of(wacom_wac->shared, struct wacom_hdev_data, 575a97ac104SBenjamin Tissoires shared); 576a97ac104SBenjamin Tissoires 577a97ac104SBenjamin Tissoires if (wacom_wac->shared->touch == wacom->hdev) 578a97ac104SBenjamin Tissoires wacom_wac->shared->touch = NULL; 579a97ac104SBenjamin Tissoires else if (wacom_wac->shared->pen == wacom->hdev) 580a97ac104SBenjamin Tissoires wacom_wac->shared->pen = NULL; 581a97ac104SBenjamin Tissoires 582471d1714SBenjamin Tissoires kref_put(&data->kref, wacom_release_shared_data); 583a97ac104SBenjamin Tissoires wacom_wac->shared = NULL; 584471d1714SBenjamin Tissoires } 585471d1714SBenjamin Tissoires } 586471d1714SBenjamin Tissoires 587471d1714SBenjamin Tissoires static int wacom_led_control(struct wacom *wacom) 588471d1714SBenjamin Tissoires { 589471d1714SBenjamin Tissoires unsigned char *buf; 590471d1714SBenjamin Tissoires int retval; 591912ca216SPing Cheng unsigned char report_id = WAC_CMD_LED_CONTROL; 592912ca216SPing Cheng int buf_size = 9; 593471d1714SBenjamin Tissoires 594912ca216SPing Cheng if (wacom->wacom_wac.pid) { /* wireless connected */ 595912ca216SPing Cheng report_id = WAC_CMD_WL_LED_CONTROL; 596912ca216SPing Cheng buf_size = 13; 597912ca216SPing Cheng } 598912ca216SPing Cheng buf = kzalloc(buf_size, GFP_KERNEL); 599471d1714SBenjamin Tissoires if (!buf) 600471d1714SBenjamin Tissoires return -ENOMEM; 601471d1714SBenjamin Tissoires 602471d1714SBenjamin Tissoires if (wacom->wacom_wac.features.type >= INTUOS5S && 603471d1714SBenjamin Tissoires wacom->wacom_wac.features.type <= INTUOSPL) { 604471d1714SBenjamin Tissoires /* 605471d1714SBenjamin Tissoires * Touch Ring and crop mark LED luminance may take on 606471d1714SBenjamin Tissoires * one of four values: 607471d1714SBenjamin Tissoires * 0 = Low; 1 = Medium; 2 = High; 3 = Off 608471d1714SBenjamin Tissoires */ 609471d1714SBenjamin Tissoires int ring_led = wacom->led.select[0] & 0x03; 610471d1714SBenjamin Tissoires int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03; 611471d1714SBenjamin Tissoires int crop_lum = 0; 612912ca216SPing Cheng unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led); 613471d1714SBenjamin Tissoires 614912ca216SPing Cheng buf[0] = report_id; 615912ca216SPing Cheng if (wacom->wacom_wac.pid) { 616912ca216SPing Cheng wacom_get_report(wacom->hdev, HID_FEATURE_REPORT, 617912ca216SPing Cheng buf, buf_size, WAC_CMD_RETRIES); 618912ca216SPing Cheng buf[0] = report_id; 619912ca216SPing Cheng buf[4] = led_bits; 620912ca216SPing Cheng } else 621912ca216SPing Cheng buf[1] = led_bits; 622471d1714SBenjamin Tissoires } 623471d1714SBenjamin Tissoires else { 624471d1714SBenjamin Tissoires int led = wacom->led.select[0] | 0x4; 625471d1714SBenjamin Tissoires 626471d1714SBenjamin Tissoires if (wacom->wacom_wac.features.type == WACOM_21UX2 || 627471d1714SBenjamin Tissoires wacom->wacom_wac.features.type == WACOM_24HD) 628471d1714SBenjamin Tissoires led |= (wacom->led.select[1] << 4) | 0x40; 629471d1714SBenjamin Tissoires 630912ca216SPing Cheng buf[0] = report_id; 631471d1714SBenjamin Tissoires buf[1] = led; 632471d1714SBenjamin Tissoires buf[2] = wacom->led.llv; 633471d1714SBenjamin Tissoires buf[3] = wacom->led.hlv; 634471d1714SBenjamin Tissoires buf[4] = wacom->led.img_lum; 635471d1714SBenjamin Tissoires } 636471d1714SBenjamin Tissoires 637912ca216SPing Cheng retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, buf_size, 638296b7378SPrzemo Firszt WAC_CMD_RETRIES); 639471d1714SBenjamin Tissoires kfree(buf); 640471d1714SBenjamin Tissoires 641471d1714SBenjamin Tissoires return retval; 642471d1714SBenjamin Tissoires } 643471d1714SBenjamin Tissoires 644849e2f06SBenjamin Tissoires static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id, 645849e2f06SBenjamin Tissoires const unsigned len, const void *img) 646471d1714SBenjamin Tissoires { 647471d1714SBenjamin Tissoires unsigned char *buf; 648471d1714SBenjamin Tissoires int i, retval; 649849e2f06SBenjamin Tissoires const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */ 650471d1714SBenjamin Tissoires 651849e2f06SBenjamin Tissoires buf = kzalloc(chunk_len + 3 , GFP_KERNEL); 652471d1714SBenjamin Tissoires if (!buf) 653471d1714SBenjamin Tissoires return -ENOMEM; 654471d1714SBenjamin Tissoires 655471d1714SBenjamin Tissoires /* Send 'start' command */ 656471d1714SBenjamin Tissoires buf[0] = WAC_CMD_ICON_START; 657471d1714SBenjamin Tissoires buf[1] = 1; 658296b7378SPrzemo Firszt retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2, 659296b7378SPrzemo Firszt WAC_CMD_RETRIES); 660471d1714SBenjamin Tissoires if (retval < 0) 661471d1714SBenjamin Tissoires goto out; 662471d1714SBenjamin Tissoires 663849e2f06SBenjamin Tissoires buf[0] = xfer_id; 664471d1714SBenjamin Tissoires buf[1] = button_id & 0x07; 665471d1714SBenjamin Tissoires for (i = 0; i < 4; i++) { 666471d1714SBenjamin Tissoires buf[2] = i; 667849e2f06SBenjamin Tissoires memcpy(buf + 3, img + i * chunk_len, chunk_len); 668471d1714SBenjamin Tissoires 669471d1714SBenjamin Tissoires retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, 670296b7378SPrzemo Firszt buf, chunk_len + 3, WAC_CMD_RETRIES); 671471d1714SBenjamin Tissoires if (retval < 0) 672471d1714SBenjamin Tissoires break; 673471d1714SBenjamin Tissoires } 674471d1714SBenjamin Tissoires 675471d1714SBenjamin Tissoires /* Send 'stop' */ 676471d1714SBenjamin Tissoires buf[0] = WAC_CMD_ICON_START; 677471d1714SBenjamin Tissoires buf[1] = 0; 678296b7378SPrzemo Firszt wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2, 679296b7378SPrzemo Firszt WAC_CMD_RETRIES); 680471d1714SBenjamin Tissoires 681471d1714SBenjamin Tissoires out: 682471d1714SBenjamin Tissoires kfree(buf); 683471d1714SBenjamin Tissoires return retval; 684471d1714SBenjamin Tissoires } 685471d1714SBenjamin Tissoires 686471d1714SBenjamin Tissoires static ssize_t wacom_led_select_store(struct device *dev, int set_id, 687471d1714SBenjamin Tissoires const char *buf, size_t count) 688471d1714SBenjamin Tissoires { 689471d1714SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 690471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 691471d1714SBenjamin Tissoires unsigned int id; 692471d1714SBenjamin Tissoires int err; 693471d1714SBenjamin Tissoires 694471d1714SBenjamin Tissoires err = kstrtouint(buf, 10, &id); 695471d1714SBenjamin Tissoires if (err) 696471d1714SBenjamin Tissoires return err; 697471d1714SBenjamin Tissoires 698471d1714SBenjamin Tissoires mutex_lock(&wacom->lock); 699471d1714SBenjamin Tissoires 700471d1714SBenjamin Tissoires wacom->led.select[set_id] = id & 0x3; 701471d1714SBenjamin Tissoires err = wacom_led_control(wacom); 702471d1714SBenjamin Tissoires 703471d1714SBenjamin Tissoires mutex_unlock(&wacom->lock); 704471d1714SBenjamin Tissoires 705471d1714SBenjamin Tissoires return err < 0 ? err : count; 706471d1714SBenjamin Tissoires } 707471d1714SBenjamin Tissoires 708471d1714SBenjamin Tissoires #define DEVICE_LED_SELECT_ATTR(SET_ID) \ 709471d1714SBenjamin Tissoires static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ 710471d1714SBenjamin Tissoires struct device_attribute *attr, const char *buf, size_t count) \ 711471d1714SBenjamin Tissoires { \ 712471d1714SBenjamin Tissoires return wacom_led_select_store(dev, SET_ID, buf, count); \ 713471d1714SBenjamin Tissoires } \ 714471d1714SBenjamin Tissoires static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \ 715471d1714SBenjamin Tissoires struct device_attribute *attr, char *buf) \ 716471d1714SBenjamin Tissoires { \ 717471d1714SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev);\ 718471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); \ 71937449adcSPing Cheng return scnprintf(buf, PAGE_SIZE, "%d\n", \ 72037449adcSPing Cheng wacom->led.select[SET_ID]); \ 721471d1714SBenjamin Tissoires } \ 722e0984bc3SPing Cheng static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM, \ 723471d1714SBenjamin Tissoires wacom_led##SET_ID##_select_show, \ 724471d1714SBenjamin Tissoires wacom_led##SET_ID##_select_store) 725471d1714SBenjamin Tissoires 726471d1714SBenjamin Tissoires DEVICE_LED_SELECT_ATTR(0); 727471d1714SBenjamin Tissoires DEVICE_LED_SELECT_ATTR(1); 728471d1714SBenjamin Tissoires 729471d1714SBenjamin Tissoires static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, 730471d1714SBenjamin Tissoires const char *buf, size_t count) 731471d1714SBenjamin Tissoires { 732471d1714SBenjamin Tissoires unsigned int value; 733471d1714SBenjamin Tissoires int err; 734471d1714SBenjamin Tissoires 735471d1714SBenjamin Tissoires err = kstrtouint(buf, 10, &value); 736471d1714SBenjamin Tissoires if (err) 737471d1714SBenjamin Tissoires return err; 738471d1714SBenjamin Tissoires 739471d1714SBenjamin Tissoires mutex_lock(&wacom->lock); 740471d1714SBenjamin Tissoires 741471d1714SBenjamin Tissoires *dest = value & 0x7f; 742471d1714SBenjamin Tissoires err = wacom_led_control(wacom); 743471d1714SBenjamin Tissoires 744471d1714SBenjamin Tissoires mutex_unlock(&wacom->lock); 745471d1714SBenjamin Tissoires 746471d1714SBenjamin Tissoires return err < 0 ? err : count; 747471d1714SBenjamin Tissoires } 748471d1714SBenjamin Tissoires 749471d1714SBenjamin Tissoires #define DEVICE_LUMINANCE_ATTR(name, field) \ 750471d1714SBenjamin Tissoires static ssize_t wacom_##name##_luminance_store(struct device *dev, \ 751471d1714SBenjamin Tissoires struct device_attribute *attr, const char *buf, size_t count) \ 752471d1714SBenjamin Tissoires { \ 753471d1714SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev);\ 754471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); \ 755471d1714SBenjamin Tissoires \ 756471d1714SBenjamin Tissoires return wacom_luminance_store(wacom, &wacom->led.field, \ 757471d1714SBenjamin Tissoires buf, count); \ 758471d1714SBenjamin Tissoires } \ 75937449adcSPing Cheng static ssize_t wacom_##name##_luminance_show(struct device *dev, \ 76037449adcSPing Cheng struct device_attribute *attr, char *buf) \ 76137449adcSPing Cheng { \ 76237449adcSPing Cheng struct wacom *wacom = dev_get_drvdata(dev); \ 76337449adcSPing Cheng return scnprintf(buf, PAGE_SIZE, "%d\n", wacom->led.field); \ 76437449adcSPing Cheng } \ 765e0984bc3SPing Cheng static DEVICE_ATTR(name##_luminance, DEV_ATTR_RW_PERM, \ 76637449adcSPing Cheng wacom_##name##_luminance_show, \ 76737449adcSPing Cheng wacom_##name##_luminance_store) 768471d1714SBenjamin Tissoires 769471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(status0, llv); 770471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(status1, hlv); 771471d1714SBenjamin Tissoires DEVICE_LUMINANCE_ATTR(buttons, img_lum); 772471d1714SBenjamin Tissoires 773471d1714SBenjamin Tissoires static ssize_t wacom_button_image_store(struct device *dev, int button_id, 774471d1714SBenjamin Tissoires const char *buf, size_t count) 775471d1714SBenjamin Tissoires { 776471d1714SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 777471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 778471d1714SBenjamin Tissoires int err; 779849e2f06SBenjamin Tissoires unsigned len; 780849e2f06SBenjamin Tissoires u8 xfer_id; 781471d1714SBenjamin Tissoires 782849e2f06SBenjamin Tissoires if (hdev->bus == BUS_BLUETOOTH) { 783849e2f06SBenjamin Tissoires len = 256; 784849e2f06SBenjamin Tissoires xfer_id = WAC_CMD_ICON_BT_XFER; 785849e2f06SBenjamin Tissoires } else { 786849e2f06SBenjamin Tissoires len = 1024; 787849e2f06SBenjamin Tissoires xfer_id = WAC_CMD_ICON_XFER; 788849e2f06SBenjamin Tissoires } 789849e2f06SBenjamin Tissoires 790849e2f06SBenjamin Tissoires if (count != len) 791471d1714SBenjamin Tissoires return -EINVAL; 792471d1714SBenjamin Tissoires 793471d1714SBenjamin Tissoires mutex_lock(&wacom->lock); 794471d1714SBenjamin Tissoires 795849e2f06SBenjamin Tissoires err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf); 796471d1714SBenjamin Tissoires 797471d1714SBenjamin Tissoires mutex_unlock(&wacom->lock); 798471d1714SBenjamin Tissoires 799471d1714SBenjamin Tissoires return err < 0 ? err : count; 800471d1714SBenjamin Tissoires } 801471d1714SBenjamin Tissoires 802471d1714SBenjamin Tissoires #define DEVICE_BTNIMG_ATTR(BUTTON_ID) \ 803471d1714SBenjamin Tissoires static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \ 804471d1714SBenjamin Tissoires struct device_attribute *attr, const char *buf, size_t count) \ 805471d1714SBenjamin Tissoires { \ 806471d1714SBenjamin Tissoires return wacom_button_image_store(dev, BUTTON_ID, buf, count); \ 807471d1714SBenjamin Tissoires } \ 808e0984bc3SPing Cheng static DEVICE_ATTR(button##BUTTON_ID##_rawimg, DEV_ATTR_WO_PERM, \ 809471d1714SBenjamin Tissoires NULL, wacom_btnimg##BUTTON_ID##_store) 810471d1714SBenjamin Tissoires 811471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(0); 812471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(1); 813471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(2); 814471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(3); 815471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(4); 816471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(5); 817471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(6); 818471d1714SBenjamin Tissoires DEVICE_BTNIMG_ATTR(7); 819471d1714SBenjamin Tissoires 820471d1714SBenjamin Tissoires static struct attribute *cintiq_led_attrs[] = { 821471d1714SBenjamin Tissoires &dev_attr_status_led0_select.attr, 822471d1714SBenjamin Tissoires &dev_attr_status_led1_select.attr, 823471d1714SBenjamin Tissoires NULL 824471d1714SBenjamin Tissoires }; 825471d1714SBenjamin Tissoires 826471d1714SBenjamin Tissoires static struct attribute_group cintiq_led_attr_group = { 827471d1714SBenjamin Tissoires .name = "wacom_led", 828471d1714SBenjamin Tissoires .attrs = cintiq_led_attrs, 829471d1714SBenjamin Tissoires }; 830471d1714SBenjamin Tissoires 831471d1714SBenjamin Tissoires static struct attribute *intuos4_led_attrs[] = { 832471d1714SBenjamin Tissoires &dev_attr_status0_luminance.attr, 833471d1714SBenjamin Tissoires &dev_attr_status1_luminance.attr, 834471d1714SBenjamin Tissoires &dev_attr_status_led0_select.attr, 835471d1714SBenjamin Tissoires &dev_attr_buttons_luminance.attr, 836471d1714SBenjamin Tissoires &dev_attr_button0_rawimg.attr, 837471d1714SBenjamin Tissoires &dev_attr_button1_rawimg.attr, 838471d1714SBenjamin Tissoires &dev_attr_button2_rawimg.attr, 839471d1714SBenjamin Tissoires &dev_attr_button3_rawimg.attr, 840471d1714SBenjamin Tissoires &dev_attr_button4_rawimg.attr, 841471d1714SBenjamin Tissoires &dev_attr_button5_rawimg.attr, 842471d1714SBenjamin Tissoires &dev_attr_button6_rawimg.attr, 843471d1714SBenjamin Tissoires &dev_attr_button7_rawimg.attr, 844471d1714SBenjamin Tissoires NULL 845471d1714SBenjamin Tissoires }; 846471d1714SBenjamin Tissoires 847471d1714SBenjamin Tissoires static struct attribute_group intuos4_led_attr_group = { 848471d1714SBenjamin Tissoires .name = "wacom_led", 849471d1714SBenjamin Tissoires .attrs = intuos4_led_attrs, 850471d1714SBenjamin Tissoires }; 851471d1714SBenjamin Tissoires 852471d1714SBenjamin Tissoires static struct attribute *intuos5_led_attrs[] = { 853471d1714SBenjamin Tissoires &dev_attr_status0_luminance.attr, 854471d1714SBenjamin Tissoires &dev_attr_status_led0_select.attr, 855471d1714SBenjamin Tissoires NULL 856471d1714SBenjamin Tissoires }; 857471d1714SBenjamin Tissoires 858471d1714SBenjamin Tissoires static struct attribute_group intuos5_led_attr_group = { 859471d1714SBenjamin Tissoires .name = "wacom_led", 860471d1714SBenjamin Tissoires .attrs = intuos5_led_attrs, 861471d1714SBenjamin Tissoires }; 862471d1714SBenjamin Tissoires 863471d1714SBenjamin Tissoires static int wacom_initialize_leds(struct wacom *wacom) 864471d1714SBenjamin Tissoires { 865471d1714SBenjamin Tissoires int error; 866471d1714SBenjamin Tissoires 867862cf553SJason Gerecke if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) 868862cf553SJason Gerecke return 0; 869862cf553SJason Gerecke 870471d1714SBenjamin Tissoires /* Initialize default values */ 871471d1714SBenjamin Tissoires switch (wacom->wacom_wac.features.type) { 872471d1714SBenjamin Tissoires case INTUOS4S: 873471d1714SBenjamin Tissoires case INTUOS4: 87481af7e61SBenjamin Tissoires case INTUOS4WL: 875471d1714SBenjamin Tissoires case INTUOS4L: 876471d1714SBenjamin Tissoires wacom->led.select[0] = 0; 877471d1714SBenjamin Tissoires wacom->led.select[1] = 0; 878471d1714SBenjamin Tissoires wacom->led.llv = 10; 879471d1714SBenjamin Tissoires wacom->led.hlv = 20; 880471d1714SBenjamin Tissoires wacom->led.img_lum = 10; 881471d1714SBenjamin Tissoires error = sysfs_create_group(&wacom->hdev->dev.kobj, 882471d1714SBenjamin Tissoires &intuos4_led_attr_group); 883471d1714SBenjamin Tissoires break; 884471d1714SBenjamin Tissoires 885471d1714SBenjamin Tissoires case WACOM_24HD: 886471d1714SBenjamin Tissoires case WACOM_21UX2: 887471d1714SBenjamin Tissoires wacom->led.select[0] = 0; 888471d1714SBenjamin Tissoires wacom->led.select[1] = 0; 889471d1714SBenjamin Tissoires wacom->led.llv = 0; 890471d1714SBenjamin Tissoires wacom->led.hlv = 0; 891471d1714SBenjamin Tissoires wacom->led.img_lum = 0; 892471d1714SBenjamin Tissoires 893471d1714SBenjamin Tissoires error = sysfs_create_group(&wacom->hdev->dev.kobj, 894471d1714SBenjamin Tissoires &cintiq_led_attr_group); 895471d1714SBenjamin Tissoires break; 896471d1714SBenjamin Tissoires 897471d1714SBenjamin Tissoires case INTUOS5S: 898471d1714SBenjamin Tissoires case INTUOS5: 899471d1714SBenjamin Tissoires case INTUOS5L: 900471d1714SBenjamin Tissoires case INTUOSPS: 901471d1714SBenjamin Tissoires case INTUOSPM: 902471d1714SBenjamin Tissoires case INTUOSPL: 903471d1714SBenjamin Tissoires wacom->led.select[0] = 0; 904471d1714SBenjamin Tissoires wacom->led.select[1] = 0; 905471d1714SBenjamin Tissoires wacom->led.llv = 32; 906471d1714SBenjamin Tissoires wacom->led.hlv = 0; 907471d1714SBenjamin Tissoires wacom->led.img_lum = 0; 908471d1714SBenjamin Tissoires 909471d1714SBenjamin Tissoires error = sysfs_create_group(&wacom->hdev->dev.kobj, 910471d1714SBenjamin Tissoires &intuos5_led_attr_group); 911471d1714SBenjamin Tissoires break; 912471d1714SBenjamin Tissoires 913471d1714SBenjamin Tissoires default: 914471d1714SBenjamin Tissoires return 0; 915471d1714SBenjamin Tissoires } 916471d1714SBenjamin Tissoires 917471d1714SBenjamin Tissoires if (error) { 918471d1714SBenjamin Tissoires hid_err(wacom->hdev, 919471d1714SBenjamin Tissoires "cannot create sysfs group err: %d\n", error); 920471d1714SBenjamin Tissoires return error; 921471d1714SBenjamin Tissoires } 922471d1714SBenjamin Tissoires wacom_led_control(wacom); 923c757cbafSBenjamin Tissoires wacom->led_initialized = true; 924471d1714SBenjamin Tissoires 925471d1714SBenjamin Tissoires return 0; 926471d1714SBenjamin Tissoires } 927471d1714SBenjamin Tissoires 928471d1714SBenjamin Tissoires static void wacom_destroy_leds(struct wacom *wacom) 929471d1714SBenjamin Tissoires { 930c757cbafSBenjamin Tissoires if (!wacom->led_initialized) 931c757cbafSBenjamin Tissoires return; 932c757cbafSBenjamin Tissoires 933862cf553SJason Gerecke if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) 934862cf553SJason Gerecke return; 935862cf553SJason Gerecke 936c757cbafSBenjamin Tissoires wacom->led_initialized = false; 937c757cbafSBenjamin Tissoires 938471d1714SBenjamin Tissoires switch (wacom->wacom_wac.features.type) { 939471d1714SBenjamin Tissoires case INTUOS4S: 940471d1714SBenjamin Tissoires case INTUOS4: 94181af7e61SBenjamin Tissoires case INTUOS4WL: 942471d1714SBenjamin Tissoires case INTUOS4L: 943471d1714SBenjamin Tissoires sysfs_remove_group(&wacom->hdev->dev.kobj, 944471d1714SBenjamin Tissoires &intuos4_led_attr_group); 945471d1714SBenjamin Tissoires break; 946471d1714SBenjamin Tissoires 947471d1714SBenjamin Tissoires case WACOM_24HD: 948471d1714SBenjamin Tissoires case WACOM_21UX2: 949471d1714SBenjamin Tissoires sysfs_remove_group(&wacom->hdev->dev.kobj, 950471d1714SBenjamin Tissoires &cintiq_led_attr_group); 951471d1714SBenjamin Tissoires break; 952471d1714SBenjamin Tissoires 953471d1714SBenjamin Tissoires case INTUOS5S: 954471d1714SBenjamin Tissoires case INTUOS5: 955471d1714SBenjamin Tissoires case INTUOS5L: 956471d1714SBenjamin Tissoires case INTUOSPS: 957471d1714SBenjamin Tissoires case INTUOSPM: 958471d1714SBenjamin Tissoires case INTUOSPL: 959471d1714SBenjamin Tissoires sysfs_remove_group(&wacom->hdev->dev.kobj, 960471d1714SBenjamin Tissoires &intuos5_led_attr_group); 961471d1714SBenjamin Tissoires break; 962471d1714SBenjamin Tissoires } 963471d1714SBenjamin Tissoires } 964471d1714SBenjamin Tissoires 965471d1714SBenjamin Tissoires static enum power_supply_property wacom_battery_props[] = { 96671fa641eSJason Gerecke POWER_SUPPLY_PROP_PRESENT, 967ac8d1010SBenjamin Tissoires POWER_SUPPLY_PROP_STATUS, 968471d1714SBenjamin Tissoires POWER_SUPPLY_PROP_SCOPE, 969471d1714SBenjamin Tissoires POWER_SUPPLY_PROP_CAPACITY 970471d1714SBenjamin Tissoires }; 971471d1714SBenjamin Tissoires 9727dbd229eSBenjamin Tissoires static enum power_supply_property wacom_ac_props[] = { 9737dbd229eSBenjamin Tissoires POWER_SUPPLY_PROP_PRESENT, 9747dbd229eSBenjamin Tissoires POWER_SUPPLY_PROP_ONLINE, 9757dbd229eSBenjamin Tissoires POWER_SUPPLY_PROP_SCOPE, 9767dbd229eSBenjamin Tissoires }; 9777dbd229eSBenjamin Tissoires 978471d1714SBenjamin Tissoires static int wacom_battery_get_property(struct power_supply *psy, 979471d1714SBenjamin Tissoires enum power_supply_property psp, 980471d1714SBenjamin Tissoires union power_supply_propval *val) 981471d1714SBenjamin Tissoires { 982297d716fSKrzysztof Kozlowski struct wacom *wacom = power_supply_get_drvdata(psy); 983471d1714SBenjamin Tissoires int ret = 0; 984471d1714SBenjamin Tissoires 985471d1714SBenjamin Tissoires switch (psp) { 98671fa641eSJason Gerecke case POWER_SUPPLY_PROP_PRESENT: 98771fa641eSJason Gerecke val->intval = wacom->wacom_wac.bat_connected; 98871fa641eSJason Gerecke break; 989471d1714SBenjamin Tissoires case POWER_SUPPLY_PROP_SCOPE: 990471d1714SBenjamin Tissoires val->intval = POWER_SUPPLY_SCOPE_DEVICE; 991471d1714SBenjamin Tissoires break; 992471d1714SBenjamin Tissoires case POWER_SUPPLY_PROP_CAPACITY: 993471d1714SBenjamin Tissoires val->intval = 994ac8d1010SBenjamin Tissoires wacom->wacom_wac.battery_capacity; 995ac8d1010SBenjamin Tissoires break; 996ac8d1010SBenjamin Tissoires case POWER_SUPPLY_PROP_STATUS: 997ac8d1010SBenjamin Tissoires if (wacom->wacom_wac.bat_charging) 998ac8d1010SBenjamin Tissoires val->intval = POWER_SUPPLY_STATUS_CHARGING; 999ac8d1010SBenjamin Tissoires else if (wacom->wacom_wac.battery_capacity == 100 && 1000ac8d1010SBenjamin Tissoires wacom->wacom_wac.ps_connected) 1001ac8d1010SBenjamin Tissoires val->intval = POWER_SUPPLY_STATUS_FULL; 1002b0882cb7SJason Gerecke else if (wacom->wacom_wac.ps_connected) 1003b0882cb7SJason Gerecke val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 1004ac8d1010SBenjamin Tissoires else 1005ac8d1010SBenjamin Tissoires val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 1006471d1714SBenjamin Tissoires break; 1007471d1714SBenjamin Tissoires default: 1008471d1714SBenjamin Tissoires ret = -EINVAL; 1009471d1714SBenjamin Tissoires break; 1010471d1714SBenjamin Tissoires } 1011471d1714SBenjamin Tissoires 1012471d1714SBenjamin Tissoires return ret; 1013471d1714SBenjamin Tissoires } 1014471d1714SBenjamin Tissoires 10157dbd229eSBenjamin Tissoires static int wacom_ac_get_property(struct power_supply *psy, 10167dbd229eSBenjamin Tissoires enum power_supply_property psp, 10177dbd229eSBenjamin Tissoires union power_supply_propval *val) 10187dbd229eSBenjamin Tissoires { 1019297d716fSKrzysztof Kozlowski struct wacom *wacom = power_supply_get_drvdata(psy); 10207dbd229eSBenjamin Tissoires int ret = 0; 10217dbd229eSBenjamin Tissoires 10227dbd229eSBenjamin Tissoires switch (psp) { 10237dbd229eSBenjamin Tissoires case POWER_SUPPLY_PROP_PRESENT: 10247dbd229eSBenjamin Tissoires /* fall through */ 10257dbd229eSBenjamin Tissoires case POWER_SUPPLY_PROP_ONLINE: 10267dbd229eSBenjamin Tissoires val->intval = wacom->wacom_wac.ps_connected; 10277dbd229eSBenjamin Tissoires break; 10287dbd229eSBenjamin Tissoires case POWER_SUPPLY_PROP_SCOPE: 10297dbd229eSBenjamin Tissoires val->intval = POWER_SUPPLY_SCOPE_DEVICE; 10307dbd229eSBenjamin Tissoires break; 10317dbd229eSBenjamin Tissoires default: 10327dbd229eSBenjamin Tissoires ret = -EINVAL; 10337dbd229eSBenjamin Tissoires break; 10347dbd229eSBenjamin Tissoires } 10357dbd229eSBenjamin Tissoires return ret; 10367dbd229eSBenjamin Tissoires } 10377dbd229eSBenjamin Tissoires 1038471d1714SBenjamin Tissoires static int wacom_initialize_battery(struct wacom *wacom) 1039471d1714SBenjamin Tissoires { 1040d70420b9SBenjamin Tissoires static atomic_t battery_no = ATOMIC_INIT(0); 1041297d716fSKrzysztof Kozlowski struct power_supply_config psy_cfg = { .drv_data = wacom, }; 1042d70420b9SBenjamin Tissoires unsigned long n; 1043471d1714SBenjamin Tissoires 1044ac8d1010SBenjamin Tissoires if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) { 1045297d716fSKrzysztof Kozlowski struct power_supply_desc *bat_desc = &wacom->battery_desc; 1046297d716fSKrzysztof Kozlowski struct power_supply_desc *ac_desc = &wacom->ac_desc; 1047d70420b9SBenjamin Tissoires n = atomic_inc_return(&battery_no) - 1; 10487dbd229eSBenjamin Tissoires 1049297d716fSKrzysztof Kozlowski bat_desc->properties = wacom_battery_props; 1050297d716fSKrzysztof Kozlowski bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props); 1051297d716fSKrzysztof Kozlowski bat_desc->get_property = wacom_battery_get_property; 1052d70420b9SBenjamin Tissoires sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n); 1053297d716fSKrzysztof Kozlowski bat_desc->name = wacom->wacom_wac.bat_name; 1054297d716fSKrzysztof Kozlowski bat_desc->type = POWER_SUPPLY_TYPE_BATTERY; 1055297d716fSKrzysztof Kozlowski bat_desc->use_for_apm = 0; 1056471d1714SBenjamin Tissoires 1057297d716fSKrzysztof Kozlowski ac_desc->properties = wacom_ac_props; 1058297d716fSKrzysztof Kozlowski ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props); 1059297d716fSKrzysztof Kozlowski ac_desc->get_property = wacom_ac_get_property; 10607dbd229eSBenjamin Tissoires sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n); 1061297d716fSKrzysztof Kozlowski ac_desc->name = wacom->wacom_wac.ac_name; 1062297d716fSKrzysztof Kozlowski ac_desc->type = POWER_SUPPLY_TYPE_MAINS; 1063297d716fSKrzysztof Kozlowski ac_desc->use_for_apm = 0; 10647dbd229eSBenjamin Tissoires 1065297d716fSKrzysztof Kozlowski wacom->battery = power_supply_register(&wacom->hdev->dev, 1066297d716fSKrzysztof Kozlowski &wacom->battery_desc, &psy_cfg); 1067297d716fSKrzysztof Kozlowski if (IS_ERR(wacom->battery)) 1068297d716fSKrzysztof Kozlowski return PTR_ERR(wacom->battery); 1069471d1714SBenjamin Tissoires 1070297d716fSKrzysztof Kozlowski power_supply_powers(wacom->battery, &wacom->hdev->dev); 10717dbd229eSBenjamin Tissoires 1072297d716fSKrzysztof Kozlowski wacom->ac = power_supply_register(&wacom->hdev->dev, 1073297d716fSKrzysztof Kozlowski &wacom->ac_desc, 1074297d716fSKrzysztof Kozlowski &psy_cfg); 1075297d716fSKrzysztof Kozlowski if (IS_ERR(wacom->ac)) { 1076297d716fSKrzysztof Kozlowski power_supply_unregister(wacom->battery); 1077297d716fSKrzysztof Kozlowski return PTR_ERR(wacom->ac); 1078471d1714SBenjamin Tissoires } 1079471d1714SBenjamin Tissoires 1080297d716fSKrzysztof Kozlowski power_supply_powers(wacom->ac, &wacom->hdev->dev); 10817dbd229eSBenjamin Tissoires } 10827dbd229eSBenjamin Tissoires 10837dbd229eSBenjamin Tissoires return 0; 1084471d1714SBenjamin Tissoires } 1085471d1714SBenjamin Tissoires 1086471d1714SBenjamin Tissoires static void wacom_destroy_battery(struct wacom *wacom) 1087471d1714SBenjamin Tissoires { 10888de29a35SLinus Torvalds if (wacom->battery) { 1089297d716fSKrzysztof Kozlowski power_supply_unregister(wacom->battery); 1090297d716fSKrzysztof Kozlowski wacom->battery = NULL; 1091297d716fSKrzysztof Kozlowski power_supply_unregister(wacom->ac); 1092297d716fSKrzysztof Kozlowski wacom->ac = NULL; 1093471d1714SBenjamin Tissoires } 1094471d1714SBenjamin Tissoires } 1095471d1714SBenjamin Tissoires 1096f81a1295SBenjamin Tissoires static ssize_t wacom_show_speed(struct device *dev, 1097f81a1295SBenjamin Tissoires struct device_attribute 1098f81a1295SBenjamin Tissoires *attr, char *buf) 1099f81a1295SBenjamin Tissoires { 1100f81a1295SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 1101f81a1295SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 1102f81a1295SBenjamin Tissoires 1103f81a1295SBenjamin Tissoires return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed); 1104f81a1295SBenjamin Tissoires } 1105f81a1295SBenjamin Tissoires 1106f81a1295SBenjamin Tissoires static ssize_t wacom_store_speed(struct device *dev, 1107f81a1295SBenjamin Tissoires struct device_attribute *attr, 1108f81a1295SBenjamin Tissoires const char *buf, size_t count) 1109f81a1295SBenjamin Tissoires { 1110f81a1295SBenjamin Tissoires struct hid_device *hdev = container_of(dev, struct hid_device, dev); 1111f81a1295SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 1112f81a1295SBenjamin Tissoires u8 new_speed; 1113f81a1295SBenjamin Tissoires 1114f81a1295SBenjamin Tissoires if (kstrtou8(buf, 0, &new_speed)) 1115f81a1295SBenjamin Tissoires return -EINVAL; 1116f81a1295SBenjamin Tissoires 1117f81a1295SBenjamin Tissoires if (new_speed != 0 && new_speed != 1) 1118f81a1295SBenjamin Tissoires return -EINVAL; 1119f81a1295SBenjamin Tissoires 1120f81a1295SBenjamin Tissoires wacom_bt_query_tablet_data(hdev, new_speed, &wacom->wacom_wac.features); 1121f81a1295SBenjamin Tissoires 1122f81a1295SBenjamin Tissoires return count; 1123f81a1295SBenjamin Tissoires } 1124f81a1295SBenjamin Tissoires 1125e0984bc3SPing Cheng static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM, 1126f81a1295SBenjamin Tissoires wacom_show_speed, wacom_store_speed); 1127f81a1295SBenjamin Tissoires 112872b236d6SAaron Skomra 112972b236d6SAaron Skomra static ssize_t wacom_show_remote_mode(struct kobject *kobj, 113072b236d6SAaron Skomra struct kobj_attribute *kattr, 113172b236d6SAaron Skomra char *buf, int index) 113272b236d6SAaron Skomra { 113372b236d6SAaron Skomra struct device *dev = container_of(kobj->parent, struct device, kobj); 113472b236d6SAaron Skomra struct hid_device *hdev = container_of(dev, struct hid_device, dev); 113572b236d6SAaron Skomra struct wacom *wacom = hid_get_drvdata(hdev); 113672b236d6SAaron Skomra u8 mode; 113772b236d6SAaron Skomra 113872b236d6SAaron Skomra mode = wacom->led.select[index]; 113972b236d6SAaron Skomra if (mode >= 0 && mode < 3) 114072b236d6SAaron Skomra return snprintf(buf, PAGE_SIZE, "%d\n", mode); 114172b236d6SAaron Skomra else 114272b236d6SAaron Skomra return snprintf(buf, PAGE_SIZE, "%d\n", -1); 114372b236d6SAaron Skomra } 114472b236d6SAaron Skomra 114572b236d6SAaron Skomra #define DEVICE_EKR_ATTR_GROUP(SET_ID) \ 114672b236d6SAaron Skomra static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \ 114772b236d6SAaron Skomra struct kobj_attribute *kattr, char *buf) \ 114872b236d6SAaron Skomra { \ 114972b236d6SAaron Skomra return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \ 115072b236d6SAaron Skomra } \ 115172b236d6SAaron Skomra static struct kobj_attribute remote##SET_ID##_mode_attr = { \ 115272b236d6SAaron Skomra .attr = {.name = "remote_mode", \ 115372b236d6SAaron Skomra .mode = DEV_ATTR_RO_PERM}, \ 115472b236d6SAaron Skomra .show = wacom_show_remote##SET_ID##_mode, \ 115572b236d6SAaron Skomra }; \ 115672b236d6SAaron Skomra static struct attribute *remote##SET_ID##_serial_attrs[] = { \ 115772b236d6SAaron Skomra &remote##SET_ID##_mode_attr.attr, \ 115872b236d6SAaron Skomra NULL \ 115972b236d6SAaron Skomra }; \ 116072b236d6SAaron Skomra static struct attribute_group remote##SET_ID##_serial_group = { \ 116172b236d6SAaron Skomra .name = NULL, \ 116272b236d6SAaron Skomra .attrs = remote##SET_ID##_serial_attrs, \ 116372b236d6SAaron Skomra } 116472b236d6SAaron Skomra 116572b236d6SAaron Skomra DEVICE_EKR_ATTR_GROUP(0); 116672b236d6SAaron Skomra DEVICE_EKR_ATTR_GROUP(1); 116772b236d6SAaron Skomra DEVICE_EKR_ATTR_GROUP(2); 116872b236d6SAaron Skomra DEVICE_EKR_ATTR_GROUP(3); 116972b236d6SAaron Skomra DEVICE_EKR_ATTR_GROUP(4); 117072b236d6SAaron Skomra 117172b236d6SAaron Skomra int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index) 117272b236d6SAaron Skomra { 117372b236d6SAaron Skomra int error = 0; 117472b236d6SAaron Skomra char *buf; 117572b236d6SAaron Skomra struct wacom_wac *wacom_wac = &wacom->wacom_wac; 117672b236d6SAaron Skomra 117772b236d6SAaron Skomra wacom_wac->serial[index] = serial; 117872b236d6SAaron Skomra 117972b236d6SAaron Skomra buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL); 118072b236d6SAaron Skomra if (!buf) 118172b236d6SAaron Skomra return -ENOMEM; 118272b236d6SAaron Skomra snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial); 118372b236d6SAaron Skomra wacom->remote_group[index].name = buf; 118472b236d6SAaron Skomra 118572b236d6SAaron Skomra error = sysfs_create_group(wacom->remote_dir, 118672b236d6SAaron Skomra &wacom->remote_group[index]); 118772b236d6SAaron Skomra if (error) { 118872b236d6SAaron Skomra hid_err(wacom->hdev, 118972b236d6SAaron Skomra "cannot create sysfs group err: %d\n", error); 119072b236d6SAaron Skomra kobject_put(wacom->remote_dir); 119172b236d6SAaron Skomra return error; 119272b236d6SAaron Skomra } 119372b236d6SAaron Skomra 119472b236d6SAaron Skomra return 0; 119572b236d6SAaron Skomra } 119672b236d6SAaron Skomra 119772b236d6SAaron Skomra void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial) 119872b236d6SAaron Skomra { 119972b236d6SAaron Skomra struct wacom_wac *wacom_wac = &wacom->wacom_wac; 120072b236d6SAaron Skomra int i; 120172b236d6SAaron Skomra 120272b236d6SAaron Skomra if (!serial) 120372b236d6SAaron Skomra return; 120472b236d6SAaron Skomra 120572b236d6SAaron Skomra for (i = 0; i < WACOM_MAX_REMOTES; i++) { 120672b236d6SAaron Skomra if (wacom_wac->serial[i] == serial) { 120772b236d6SAaron Skomra wacom_wac->serial[i] = 0; 120872b236d6SAaron Skomra wacom->led.select[i] = WACOM_STATUS_UNKNOWN; 120972b236d6SAaron Skomra if (wacom->remote_group[i].name) { 121072b236d6SAaron Skomra sysfs_remove_group(wacom->remote_dir, 121172b236d6SAaron Skomra &wacom->remote_group[i]); 121272b236d6SAaron Skomra kfree(wacom->remote_group[i].name); 121372b236d6SAaron Skomra wacom->remote_group[i].name = NULL; 121472b236d6SAaron Skomra } 121572b236d6SAaron Skomra } 121672b236d6SAaron Skomra } 121772b236d6SAaron Skomra } 121872b236d6SAaron Skomra 121972b236d6SAaron Skomra static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector) 122072b236d6SAaron Skomra { 122172b236d6SAaron Skomra const size_t buf_size = 2; 122272b236d6SAaron Skomra unsigned char *buf; 122372b236d6SAaron Skomra int retval; 122472b236d6SAaron Skomra 122572b236d6SAaron Skomra buf = kzalloc(buf_size, GFP_KERNEL); 122672b236d6SAaron Skomra if (!buf) 122772b236d6SAaron Skomra return -ENOMEM; 122872b236d6SAaron Skomra 122972b236d6SAaron Skomra buf[0] = WAC_CMD_DELETE_PAIRING; 123072b236d6SAaron Skomra buf[1] = selector; 123172b236d6SAaron Skomra 123272b236d6SAaron Skomra retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf, 123372b236d6SAaron Skomra buf_size, WAC_CMD_RETRIES); 123472b236d6SAaron Skomra kfree(buf); 123572b236d6SAaron Skomra 123672b236d6SAaron Skomra return retval; 123772b236d6SAaron Skomra } 123872b236d6SAaron Skomra 123972b236d6SAaron Skomra static ssize_t wacom_store_unpair_remote(struct kobject *kobj, 124072b236d6SAaron Skomra struct kobj_attribute *attr, 124172b236d6SAaron Skomra const char *buf, size_t count) 124272b236d6SAaron Skomra { 124372b236d6SAaron Skomra unsigned char selector = 0; 124472b236d6SAaron Skomra struct device *dev = container_of(kobj->parent, struct device, kobj); 124572b236d6SAaron Skomra struct hid_device *hdev = container_of(dev, struct hid_device, dev); 124672b236d6SAaron Skomra struct wacom *wacom = hid_get_drvdata(hdev); 124772b236d6SAaron Skomra int err; 124872b236d6SAaron Skomra 124972b236d6SAaron Skomra if (!strncmp(buf, "*\n", 2)) { 125072b236d6SAaron Skomra selector = WAC_CMD_UNPAIR_ALL; 125172b236d6SAaron Skomra } else { 125272b236d6SAaron Skomra hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n", 125372b236d6SAaron Skomra buf); 125472b236d6SAaron Skomra return -1; 125572b236d6SAaron Skomra } 125672b236d6SAaron Skomra 125772b236d6SAaron Skomra mutex_lock(&wacom->lock); 125872b236d6SAaron Skomra 125972b236d6SAaron Skomra err = wacom_cmd_unpair_remote(wacom, selector); 126072b236d6SAaron Skomra mutex_unlock(&wacom->lock); 126172b236d6SAaron Skomra 126272b236d6SAaron Skomra return err < 0 ? err : count; 126372b236d6SAaron Skomra } 126472b236d6SAaron Skomra 126572b236d6SAaron Skomra static struct kobj_attribute unpair_remote_attr = { 126672b236d6SAaron Skomra .attr = {.name = "unpair_remote", .mode = 0200}, 126772b236d6SAaron Skomra .store = wacom_store_unpair_remote, 126872b236d6SAaron Skomra }; 126972b236d6SAaron Skomra 127072b236d6SAaron Skomra static const struct attribute *remote_unpair_attrs[] = { 127172b236d6SAaron Skomra &unpair_remote_attr.attr, 127272b236d6SAaron Skomra NULL 127372b236d6SAaron Skomra }; 127472b236d6SAaron Skomra 127572b236d6SAaron Skomra static int wacom_initialize_remote(struct wacom *wacom) 127672b236d6SAaron Skomra { 127772b236d6SAaron Skomra int error = 0; 127872b236d6SAaron Skomra struct wacom_wac *wacom_wac = &(wacom->wacom_wac); 127972b236d6SAaron Skomra int i; 128072b236d6SAaron Skomra 128172b236d6SAaron Skomra if (wacom->wacom_wac.features.type != REMOTE) 128272b236d6SAaron Skomra return 0; 128372b236d6SAaron Skomra 128472b236d6SAaron Skomra wacom->remote_group[0] = remote0_serial_group; 128572b236d6SAaron Skomra wacom->remote_group[1] = remote1_serial_group; 128672b236d6SAaron Skomra wacom->remote_group[2] = remote2_serial_group; 128772b236d6SAaron Skomra wacom->remote_group[3] = remote3_serial_group; 128872b236d6SAaron Skomra wacom->remote_group[4] = remote4_serial_group; 128972b236d6SAaron Skomra 129072b236d6SAaron Skomra wacom->remote_dir = kobject_create_and_add("wacom_remote", 129172b236d6SAaron Skomra &wacom->hdev->dev.kobj); 129272b236d6SAaron Skomra if (!wacom->remote_dir) 129372b236d6SAaron Skomra return -ENOMEM; 129472b236d6SAaron Skomra 129572b236d6SAaron Skomra error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs); 129672b236d6SAaron Skomra 129772b236d6SAaron Skomra if (error) { 129872b236d6SAaron Skomra hid_err(wacom->hdev, 129972b236d6SAaron Skomra "cannot create sysfs group err: %d\n", error); 130072b236d6SAaron Skomra return error; 130172b236d6SAaron Skomra } 130272b236d6SAaron Skomra 130372b236d6SAaron Skomra for (i = 0; i < WACOM_MAX_REMOTES; i++) { 130472b236d6SAaron Skomra wacom->led.select[i] = WACOM_STATUS_UNKNOWN; 130572b236d6SAaron Skomra wacom_wac->serial[i] = 0; 130672b236d6SAaron Skomra } 130772b236d6SAaron Skomra 130872b236d6SAaron Skomra return 0; 130972b236d6SAaron Skomra } 131072b236d6SAaron Skomra 1311471d1714SBenjamin Tissoires static struct input_dev *wacom_allocate_input(struct wacom *wacom) 1312471d1714SBenjamin Tissoires { 1313471d1714SBenjamin Tissoires struct input_dev *input_dev; 1314471d1714SBenjamin Tissoires struct hid_device *hdev = wacom->hdev; 1315471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac = &(wacom->wacom_wac); 1316471d1714SBenjamin Tissoires 1317471d1714SBenjamin Tissoires input_dev = input_allocate_device(); 1318471d1714SBenjamin Tissoires if (!input_dev) 1319471d1714SBenjamin Tissoires return NULL; 1320471d1714SBenjamin Tissoires 13212bdd163cSJason Gerecke input_dev->name = wacom_wac->features.name; 1322471d1714SBenjamin Tissoires input_dev->phys = hdev->phys; 1323471d1714SBenjamin Tissoires input_dev->dev.parent = &hdev->dev; 1324471d1714SBenjamin Tissoires input_dev->open = wacom_open; 1325471d1714SBenjamin Tissoires input_dev->close = wacom_close; 1326471d1714SBenjamin Tissoires input_dev->uniq = hdev->uniq; 1327471d1714SBenjamin Tissoires input_dev->id.bustype = hdev->bus; 1328471d1714SBenjamin Tissoires input_dev->id.vendor = hdev->vendor; 132912969e3bSBenjamin Tissoires input_dev->id.product = wacom_wac->pid ? wacom_wac->pid : hdev->product; 1330471d1714SBenjamin Tissoires input_dev->id.version = hdev->version; 1331471d1714SBenjamin Tissoires input_set_drvdata(input_dev, wacom); 1332471d1714SBenjamin Tissoires 1333471d1714SBenjamin Tissoires return input_dev; 1334471d1714SBenjamin Tissoires } 1335471d1714SBenjamin Tissoires 13362546dacdSBenjamin Tissoires static void wacom_clean_inputs(struct wacom *wacom) 13372546dacdSBenjamin Tissoires { 13382a6cdbddSJason Gerecke if (wacom->wacom_wac.pen_input) { 13392a6cdbddSJason Gerecke if (wacom->wacom_wac.pen_registered) 13402a6cdbddSJason Gerecke input_unregister_device(wacom->wacom_wac.pen_input); 13412546dacdSBenjamin Tissoires else 13422a6cdbddSJason Gerecke input_free_device(wacom->wacom_wac.pen_input); 13432a6cdbddSJason Gerecke } 13442a6cdbddSJason Gerecke if (wacom->wacom_wac.touch_input) { 13452a6cdbddSJason Gerecke if (wacom->wacom_wac.touch_registered) 13462a6cdbddSJason Gerecke input_unregister_device(wacom->wacom_wac.touch_input); 13472a6cdbddSJason Gerecke else 13482a6cdbddSJason Gerecke input_free_device(wacom->wacom_wac.touch_input); 13492546dacdSBenjamin Tissoires } 13502546dacdSBenjamin Tissoires if (wacom->wacom_wac.pad_input) { 1351954df6adSPing Cheng if (wacom->wacom_wac.pad_registered) 1352471d1714SBenjamin Tissoires input_unregister_device(wacom->wacom_wac.pad_input); 13532546dacdSBenjamin Tissoires else 13542546dacdSBenjamin Tissoires input_free_device(wacom->wacom_wac.pad_input); 13552546dacdSBenjamin Tissoires } 135672b236d6SAaron Skomra if (wacom->remote_dir) 135772b236d6SAaron Skomra kobject_put(wacom->remote_dir); 13582a6cdbddSJason Gerecke wacom->wacom_wac.pen_input = NULL; 13592a6cdbddSJason Gerecke wacom->wacom_wac.touch_input = NULL; 1360471d1714SBenjamin Tissoires wacom->wacom_wac.pad_input = NULL; 1361912ca216SPing Cheng wacom_destroy_leds(wacom); 1362471d1714SBenjamin Tissoires } 1363471d1714SBenjamin Tissoires 1364d9f2d203SJason Gerecke static int wacom_allocate_inputs(struct wacom *wacom) 1365d9f2d203SJason Gerecke { 1366d9f2d203SJason Gerecke struct wacom_wac *wacom_wac = &(wacom->wacom_wac); 1367d9f2d203SJason Gerecke 1368d9f2d203SJason Gerecke wacom_wac->pen_input = wacom_allocate_input(wacom); 1369d9f2d203SJason Gerecke wacom_wac->touch_input = wacom_allocate_input(wacom); 1370d9f2d203SJason Gerecke wacom_wac->pad_input = wacom_allocate_input(wacom); 1371d9f2d203SJason Gerecke if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) { 1372d9f2d203SJason Gerecke wacom_clean_inputs(wacom); 1373d9f2d203SJason Gerecke return -ENOMEM; 1374d9f2d203SJason Gerecke } 1375d9f2d203SJason Gerecke 13762bdd163cSJason Gerecke wacom_wac->pen_input->name = wacom_wac->pen_name; 1377d9f2d203SJason Gerecke wacom_wac->touch_input->name = wacom_wac->touch_name; 1378d9f2d203SJason Gerecke wacom_wac->pad_input->name = wacom_wac->pad_name; 1379d9f2d203SJason Gerecke 1380d9f2d203SJason Gerecke return 0; 1381d9f2d203SJason Gerecke } 1382d9f2d203SJason Gerecke 1383471d1714SBenjamin Tissoires static int wacom_register_inputs(struct wacom *wacom) 1384471d1714SBenjamin Tissoires { 13852a6cdbddSJason Gerecke struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; 1386471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac = &(wacom->wacom_wac); 13872636a3f2SJason Gerecke int error = 0; 1388471d1714SBenjamin Tissoires 13892a6cdbddSJason Gerecke pen_input_dev = wacom_wac->pen_input; 13902a6cdbddSJason Gerecke touch_input_dev = wacom_wac->touch_input; 13912546dacdSBenjamin Tissoires pad_input_dev = wacom_wac->pad_input; 1392471d1714SBenjamin Tissoires 13932a6cdbddSJason Gerecke if (!pen_input_dev || !touch_input_dev || !pad_input_dev) 13942546dacdSBenjamin Tissoires return -EINVAL; 1395471d1714SBenjamin Tissoires 13962a6cdbddSJason Gerecke error = wacom_setup_pen_input_capabilities(pen_input_dev, wacom_wac); 13972a6cdbddSJason Gerecke if (error) { 13982a6cdbddSJason Gerecke /* no pen in use on this interface */ 13992a6cdbddSJason Gerecke input_free_device(pen_input_dev); 14002a6cdbddSJason Gerecke wacom_wac->pen_input = NULL; 14012a6cdbddSJason Gerecke pen_input_dev = NULL; 14022a6cdbddSJason Gerecke } else { 14032a6cdbddSJason Gerecke error = input_register_device(pen_input_dev); 1404471d1714SBenjamin Tissoires if (error) 14052a6cdbddSJason Gerecke goto fail_register_pen_input; 14062a6cdbddSJason Gerecke wacom_wac->pen_registered = true; 14072a6cdbddSJason Gerecke } 14082a6cdbddSJason Gerecke 14092a6cdbddSJason Gerecke error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); 14102a6cdbddSJason Gerecke if (error) { 14112a6cdbddSJason Gerecke /* no touch in use on this interface */ 14122a6cdbddSJason Gerecke input_free_device(touch_input_dev); 14132a6cdbddSJason Gerecke wacom_wac->touch_input = NULL; 14142a6cdbddSJason Gerecke touch_input_dev = NULL; 14152a6cdbddSJason Gerecke } else { 14162a6cdbddSJason Gerecke error = input_register_device(touch_input_dev); 14172a6cdbddSJason Gerecke if (error) 14182a6cdbddSJason Gerecke goto fail_register_touch_input; 14192a6cdbddSJason Gerecke wacom_wac->touch_registered = true; 142030ebc1aeSPing Cheng } 1421471d1714SBenjamin Tissoires 1422471d1714SBenjamin Tissoires error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); 1423471d1714SBenjamin Tissoires if (error) { 1424471d1714SBenjamin Tissoires /* no pad in use on this interface */ 1425471d1714SBenjamin Tissoires input_free_device(pad_input_dev); 1426471d1714SBenjamin Tissoires wacom_wac->pad_input = NULL; 1427471d1714SBenjamin Tissoires pad_input_dev = NULL; 1428471d1714SBenjamin Tissoires } else { 1429471d1714SBenjamin Tissoires error = input_register_device(pad_input_dev); 1430471d1714SBenjamin Tissoires if (error) 14317fefeec5SBenjamin Tissoires goto fail_register_pad_input; 1432954df6adSPing Cheng wacom_wac->pad_registered = true; 1433912ca216SPing Cheng 1434912ca216SPing Cheng error = wacom_initialize_leds(wacom); 1435912ca216SPing Cheng if (error) 14367fefeec5SBenjamin Tissoires goto fail_leds; 143772b236d6SAaron Skomra 143872b236d6SAaron Skomra error = wacom_initialize_remote(wacom); 143972b236d6SAaron Skomra if (error) 144072b236d6SAaron Skomra goto fail_remote; 1441471d1714SBenjamin Tissoires } 1442471d1714SBenjamin Tissoires 1443471d1714SBenjamin Tissoires return 0; 1444471d1714SBenjamin Tissoires 144572b236d6SAaron Skomra fail_remote: 144672b236d6SAaron Skomra wacom_destroy_leds(wacom); 14477fefeec5SBenjamin Tissoires fail_leds: 1448912ca216SPing Cheng input_unregister_device(pad_input_dev); 1449912ca216SPing Cheng pad_input_dev = NULL; 1450954df6adSPing Cheng wacom_wac->pad_registered = false; 14517fefeec5SBenjamin Tissoires fail_register_pad_input: 14520fd72ff9SDan Carpenter if (touch_input_dev) 14532a6cdbddSJason Gerecke input_unregister_device(touch_input_dev); 14542a6cdbddSJason Gerecke wacom_wac->touch_input = NULL; 14552a6cdbddSJason Gerecke wacom_wac->touch_registered = false; 14562a6cdbddSJason Gerecke fail_register_touch_input: 14570fd72ff9SDan Carpenter if (pen_input_dev) 14582a6cdbddSJason Gerecke input_unregister_device(pen_input_dev); 14592a6cdbddSJason Gerecke wacom_wac->pen_input = NULL; 14602a6cdbddSJason Gerecke wacom_wac->pen_registered = false; 14612a6cdbddSJason Gerecke fail_register_pen_input: 1462471d1714SBenjamin Tissoires return error; 1463471d1714SBenjamin Tissoires } 1464471d1714SBenjamin Tissoires 14650be01712SJason Gerecke /* 14660be01712SJason Gerecke * Not all devices report physical dimensions from HID. 14670be01712SJason Gerecke * Compute the default from hardcoded logical dimension 14680be01712SJason Gerecke * and resolution before driver overwrites them. 14690be01712SJason Gerecke */ 14700be01712SJason Gerecke static void wacom_set_default_phy(struct wacom_features *features) 14710be01712SJason Gerecke { 14720be01712SJason Gerecke if (features->x_resolution) { 14730be01712SJason Gerecke features->x_phy = (features->x_max * 100) / 14740be01712SJason Gerecke features->x_resolution; 14750be01712SJason Gerecke features->y_phy = (features->y_max * 100) / 14760be01712SJason Gerecke features->y_resolution; 14770be01712SJason Gerecke } 14780be01712SJason Gerecke } 14790be01712SJason Gerecke 14800be01712SJason Gerecke static void wacom_calculate_res(struct wacom_features *features) 14810be01712SJason Gerecke { 14820be01712SJason Gerecke /* set unit to "100th of a mm" for devices not reported by HID */ 14830be01712SJason Gerecke if (!features->unit) { 14840be01712SJason Gerecke features->unit = 0x11; 14850be01712SJason Gerecke features->unitExpo = -3; 14860be01712SJason Gerecke } 14870be01712SJason Gerecke 14880be01712SJason Gerecke features->x_resolution = wacom_calc_hid_res(features->x_max, 14890be01712SJason Gerecke features->x_phy, 14900be01712SJason Gerecke features->unit, 14910be01712SJason Gerecke features->unitExpo); 14920be01712SJason Gerecke features->y_resolution = wacom_calc_hid_res(features->y_max, 14930be01712SJason Gerecke features->y_phy, 14940be01712SJason Gerecke features->unit, 14950be01712SJason Gerecke features->unitExpo); 14960be01712SJason Gerecke } 14970be01712SJason Gerecke 1498471d1714SBenjamin Tissoires static void wacom_wireless_work(struct work_struct *work) 1499471d1714SBenjamin Tissoires { 1500471d1714SBenjamin Tissoires struct wacom *wacom = container_of(work, struct wacom, work); 1501471d1714SBenjamin Tissoires struct usb_device *usbdev = wacom->usbdev; 1502471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1503471d1714SBenjamin Tissoires struct hid_device *hdev1, *hdev2; 1504471d1714SBenjamin Tissoires struct wacom *wacom1, *wacom2; 1505471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac1, *wacom_wac2; 1506471d1714SBenjamin Tissoires int error; 1507471d1714SBenjamin Tissoires 1508471d1714SBenjamin Tissoires /* 1509471d1714SBenjamin Tissoires * Regardless if this is a disconnect or a new tablet, 1510471d1714SBenjamin Tissoires * remove any existing input and battery devices. 1511471d1714SBenjamin Tissoires */ 1512471d1714SBenjamin Tissoires 1513471d1714SBenjamin Tissoires wacom_destroy_battery(wacom); 1514471d1714SBenjamin Tissoires 1515471d1714SBenjamin Tissoires /* Stylus interface */ 1516471d1714SBenjamin Tissoires hdev1 = usb_get_intfdata(usbdev->config->interface[1]); 1517471d1714SBenjamin Tissoires wacom1 = hid_get_drvdata(hdev1); 1518471d1714SBenjamin Tissoires wacom_wac1 = &(wacom1->wacom_wac); 15192546dacdSBenjamin Tissoires wacom_clean_inputs(wacom1); 1520471d1714SBenjamin Tissoires 1521471d1714SBenjamin Tissoires /* Touch interface */ 1522471d1714SBenjamin Tissoires hdev2 = usb_get_intfdata(usbdev->config->interface[2]); 1523471d1714SBenjamin Tissoires wacom2 = hid_get_drvdata(hdev2); 1524471d1714SBenjamin Tissoires wacom_wac2 = &(wacom2->wacom_wac); 15252546dacdSBenjamin Tissoires wacom_clean_inputs(wacom2); 1526471d1714SBenjamin Tissoires 1527471d1714SBenjamin Tissoires if (wacom_wac->pid == 0) { 1528471d1714SBenjamin Tissoires hid_info(wacom->hdev, "wireless tablet disconnected\n"); 1529ac8d1010SBenjamin Tissoires wacom_wac1->shared->type = 0; 1530471d1714SBenjamin Tissoires } else { 1531471d1714SBenjamin Tissoires const struct hid_device_id *id = wacom_ids; 1532471d1714SBenjamin Tissoires 1533471d1714SBenjamin Tissoires hid_info(wacom->hdev, "wireless tablet connected with PID %x\n", 1534471d1714SBenjamin Tissoires wacom_wac->pid); 1535471d1714SBenjamin Tissoires 1536471d1714SBenjamin Tissoires while (id->bus) { 1537471d1714SBenjamin Tissoires if (id->vendor == USB_VENDOR_ID_WACOM && 1538471d1714SBenjamin Tissoires id->product == wacom_wac->pid) 1539471d1714SBenjamin Tissoires break; 1540471d1714SBenjamin Tissoires id++; 1541471d1714SBenjamin Tissoires } 1542471d1714SBenjamin Tissoires 1543471d1714SBenjamin Tissoires if (!id->bus) { 1544471d1714SBenjamin Tissoires hid_info(wacom->hdev, "ignoring unknown PID.\n"); 1545471d1714SBenjamin Tissoires return; 1546471d1714SBenjamin Tissoires } 1547471d1714SBenjamin Tissoires 1548471d1714SBenjamin Tissoires /* Stylus interface */ 1549471d1714SBenjamin Tissoires wacom_wac1->features = 1550471d1714SBenjamin Tissoires *((struct wacom_features *)id->driver_data); 1551aa86b18cSJason Gerecke wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN; 15520be01712SJason Gerecke wacom_set_default_phy(&wacom_wac1->features); 15530be01712SJason Gerecke wacom_calculate_res(&wacom_wac1->features); 15542a6cdbddSJason Gerecke snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen", 1555471d1714SBenjamin Tissoires wacom_wac1->features.name); 1556*3b164a00SPing Cheng if (wacom_wac1->features.type < BAMBOO_PEN || 1557*3b164a00SPing Cheng wacom_wac1->features.type > BAMBOO_PT) { 1558471d1714SBenjamin Tissoires snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", 1559471d1714SBenjamin Tissoires wacom_wac1->features.name); 1560*3b164a00SPing Cheng wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD; 1561*3b164a00SPing Cheng } 1562471d1714SBenjamin Tissoires wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max; 1563471d1714SBenjamin Tissoires wacom_wac1->shared->type = wacom_wac1->features.type; 1564912ca216SPing Cheng wacom_wac1->pid = wacom_wac->pid; 15652546dacdSBenjamin Tissoires error = wacom_allocate_inputs(wacom1) || 15662546dacdSBenjamin Tissoires wacom_register_inputs(wacom1); 1567471d1714SBenjamin Tissoires if (error) 1568471d1714SBenjamin Tissoires goto fail; 1569471d1714SBenjamin Tissoires 1570471d1714SBenjamin Tissoires /* Touch interface */ 1571471d1714SBenjamin Tissoires if (wacom_wac1->features.touch_max || 1572471d1714SBenjamin Tissoires wacom_wac1->features.type == INTUOSHT) { 1573471d1714SBenjamin Tissoires wacom_wac2->features = 1574471d1714SBenjamin Tissoires *((struct wacom_features *)id->driver_data); 1575471d1714SBenjamin Tissoires wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; 15760be01712SJason Gerecke wacom_set_default_phy(&wacom_wac2->features); 1577471d1714SBenjamin Tissoires wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; 15780be01712SJason Gerecke wacom_calculate_res(&wacom_wac2->features); 15792a6cdbddSJason Gerecke snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX, 1580471d1714SBenjamin Tissoires "%s (WL) Finger",wacom_wac2->features.name); 1581862cf553SJason Gerecke if (wacom_wac1->features.touch_max) 1582862cf553SJason Gerecke wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH; 1583*3b164a00SPing Cheng if (wacom_wac1->features.type >= INTUOSHT && 1584*3b164a00SPing Cheng wacom_wac1->features.type <= BAMBOO_PT) { 1585*3b164a00SPing Cheng snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX, 1586*3b164a00SPing Cheng "%s (WL) Pad",wacom_wac2->features.name); 1587862cf553SJason Gerecke wacom_wac2->features.device_type |= WACOM_DEVICETYPE_PAD; 1588*3b164a00SPing Cheng } 1589912ca216SPing Cheng wacom_wac2->pid = wacom_wac->pid; 15902546dacdSBenjamin Tissoires error = wacom_allocate_inputs(wacom2) || 15912546dacdSBenjamin Tissoires wacom_register_inputs(wacom2); 1592471d1714SBenjamin Tissoires if (error) 1593471d1714SBenjamin Tissoires goto fail; 1594471d1714SBenjamin Tissoires 1595471d1714SBenjamin Tissoires if (wacom_wac1->features.type == INTUOSHT && 1596471d1714SBenjamin Tissoires wacom_wac1->features.touch_max) 15972a6cdbddSJason Gerecke wacom_wac->shared->touch_input = wacom_wac2->touch_input; 1598471d1714SBenjamin Tissoires } 1599471d1714SBenjamin Tissoires 1600471d1714SBenjamin Tissoires error = wacom_initialize_battery(wacom); 1601471d1714SBenjamin Tissoires if (error) 1602471d1714SBenjamin Tissoires goto fail; 1603471d1714SBenjamin Tissoires } 1604471d1714SBenjamin Tissoires 1605471d1714SBenjamin Tissoires return; 1606471d1714SBenjamin Tissoires 1607471d1714SBenjamin Tissoires fail: 16082546dacdSBenjamin Tissoires wacom_clean_inputs(wacom1); 16092546dacdSBenjamin Tissoires wacom_clean_inputs(wacom2); 1610471d1714SBenjamin Tissoires return; 1611471d1714SBenjamin Tissoires } 1612471d1714SBenjamin Tissoires 1613fce9957dSJason Gerecke void wacom_battery_work(struct work_struct *work) 1614fce9957dSJason Gerecke { 1615fce9957dSJason Gerecke struct wacom *wacom = container_of(work, struct wacom, work); 1616fce9957dSJason Gerecke 1617fce9957dSJason Gerecke if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) && 16188de29a35SLinus Torvalds !wacom->battery) { 1619fce9957dSJason Gerecke wacom_initialize_battery(wacom); 1620fce9957dSJason Gerecke } 1621fce9957dSJason Gerecke else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) && 16228de29a35SLinus Torvalds wacom->battery) { 1623fce9957dSJason Gerecke wacom_destroy_battery(wacom); 1624fce9957dSJason Gerecke } 1625fce9957dSJason Gerecke } 1626fce9957dSJason Gerecke 1627471d1714SBenjamin Tissoires static size_t wacom_compute_pktlen(struct hid_device *hdev) 1628471d1714SBenjamin Tissoires { 1629471d1714SBenjamin Tissoires struct hid_report_enum *report_enum; 1630471d1714SBenjamin Tissoires struct hid_report *report; 1631471d1714SBenjamin Tissoires size_t size = 0; 1632471d1714SBenjamin Tissoires 1633471d1714SBenjamin Tissoires report_enum = hdev->report_enum + HID_INPUT_REPORT; 1634471d1714SBenjamin Tissoires 1635471d1714SBenjamin Tissoires list_for_each_entry(report, &report_enum->report_list, list) { 1636dabb05c6SMathieu Magnaudet size_t report_size = hid_report_len(report); 1637471d1714SBenjamin Tissoires if (report_size > size) 1638471d1714SBenjamin Tissoires size = report_size; 1639471d1714SBenjamin Tissoires } 1640471d1714SBenjamin Tissoires 1641471d1714SBenjamin Tissoires return size; 1642471d1714SBenjamin Tissoires } 1643471d1714SBenjamin Tissoires 1644c24eab4eSPing Cheng static void wacom_update_name(struct wacom *wacom) 1645c24eab4eSPing Cheng { 1646c24eab4eSPing Cheng struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1647c24eab4eSPing Cheng struct wacom_features *features = &wacom_wac->features; 164844b5250bSJason Gerecke char name[WACOM_NAME_MAX]; 1649c24eab4eSPing Cheng 1650c24eab4eSPing Cheng /* Generic devices name unspecified */ 1651c24eab4eSPing Cheng if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { 1652c24eab4eSPing Cheng if (strstr(wacom->hdev->name, "Wacom") || 1653c24eab4eSPing Cheng strstr(wacom->hdev->name, "wacom") || 1654c24eab4eSPing Cheng strstr(wacom->hdev->name, "WACOM")) { 1655c24eab4eSPing Cheng /* name is in HID descriptor, use it */ 165644b5250bSJason Gerecke strlcpy(name, wacom->hdev->name, sizeof(name)); 1657c24eab4eSPing Cheng 1658c24eab4eSPing Cheng /* strip out excess whitespaces */ 1659c24eab4eSPing Cheng while (1) { 166044b5250bSJason Gerecke char *gap = strstr(name, " "); 1661c24eab4eSPing Cheng if (gap == NULL) 1662c24eab4eSPing Cheng break; 1663c24eab4eSPing Cheng /* shift everything including the terminator */ 1664c24eab4eSPing Cheng memmove(gap, gap+1, strlen(gap)); 1665c24eab4eSPing Cheng } 1666c24eab4eSPing Cheng /* get rid of trailing whitespace */ 166744b5250bSJason Gerecke if (name[strlen(name)-1] == ' ') 166844b5250bSJason Gerecke name[strlen(name)-1] = '\0'; 1669c24eab4eSPing Cheng } else { 1670c24eab4eSPing Cheng /* no meaningful name retrieved. use product ID */ 167144b5250bSJason Gerecke snprintf(name, sizeof(name), 1672c24eab4eSPing Cheng "%s %X", features->name, wacom->hdev->product); 1673c24eab4eSPing Cheng } 1674c24eab4eSPing Cheng } else { 167544b5250bSJason Gerecke strlcpy(name, features->name, sizeof(name)); 1676c24eab4eSPing Cheng } 1677c24eab4eSPing Cheng 1678c24eab4eSPing Cheng /* Append the device type to the name */ 16792a6cdbddSJason Gerecke snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name), 16802a6cdbddSJason Gerecke "%s Pen", name); 16812a6cdbddSJason Gerecke snprintf(wacom_wac->touch_name, sizeof(wacom_wac->touch_name), 16822a6cdbddSJason Gerecke "%s Finger", name); 1683c24eab4eSPing Cheng snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), 168444b5250bSJason Gerecke "%s Pad", name); 16858d80f790SJason Gerecke } 1686c24eab4eSPing Cheng 1687471d1714SBenjamin Tissoires static int wacom_probe(struct hid_device *hdev, 1688471d1714SBenjamin Tissoires const struct hid_device_id *id) 1689471d1714SBenjamin Tissoires { 1690471d1714SBenjamin Tissoires struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 1691471d1714SBenjamin Tissoires struct usb_device *dev = interface_to_usbdev(intf); 1692471d1714SBenjamin Tissoires struct wacom *wacom; 1693471d1714SBenjamin Tissoires struct wacom_wac *wacom_wac; 1694471d1714SBenjamin Tissoires struct wacom_features *features; 1695471d1714SBenjamin Tissoires int error; 16967704ac93SBenjamin Tissoires unsigned int connect_mask = HID_CONNECT_HIDRAW; 1697471d1714SBenjamin Tissoires 1698471d1714SBenjamin Tissoires if (!id->driver_data) 1699471d1714SBenjamin Tissoires return -EINVAL; 1700471d1714SBenjamin Tissoires 17018ffffd52SBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 17028ffffd52SBenjamin Tissoires 17035fcad167SBenjamin Tissoires /* hid-core sets this quirk for the boot interface */ 17045fcad167SBenjamin Tissoires hdev->quirks &= ~HID_QUIRK_NOGET; 17055fcad167SBenjamin Tissoires 1706471d1714SBenjamin Tissoires wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); 1707471d1714SBenjamin Tissoires if (!wacom) 1708471d1714SBenjamin Tissoires return -ENOMEM; 1709471d1714SBenjamin Tissoires 1710471d1714SBenjamin Tissoires hid_set_drvdata(hdev, wacom); 1711471d1714SBenjamin Tissoires wacom->hdev = hdev; 1712471d1714SBenjamin Tissoires 1713471d1714SBenjamin Tissoires /* ask for the report descriptor to be loaded by HID */ 1714471d1714SBenjamin Tissoires error = hid_parse(hdev); 1715471d1714SBenjamin Tissoires if (error) { 1716471d1714SBenjamin Tissoires hid_err(hdev, "parse failed\n"); 17177fefeec5SBenjamin Tissoires goto fail_parse; 1718471d1714SBenjamin Tissoires } 1719471d1714SBenjamin Tissoires 1720471d1714SBenjamin Tissoires wacom_wac = &wacom->wacom_wac; 1721471d1714SBenjamin Tissoires wacom_wac->features = *((struct wacom_features *)id->driver_data); 1722471d1714SBenjamin Tissoires features = &wacom_wac->features; 1723471d1714SBenjamin Tissoires features->pktlen = wacom_compute_pktlen(hdev); 1724471d1714SBenjamin Tissoires if (features->pktlen > WACOM_PKGLEN_MAX) { 1725471d1714SBenjamin Tissoires error = -EINVAL; 17267fefeec5SBenjamin Tissoires goto fail_pktlen; 1727471d1714SBenjamin Tissoires } 1728471d1714SBenjamin Tissoires 1729471d1714SBenjamin Tissoires if (features->check_for_hid_type && features->hid_type != hdev->type) { 1730471d1714SBenjamin Tissoires error = -ENODEV; 17317fefeec5SBenjamin Tissoires goto fail_type; 1732471d1714SBenjamin Tissoires } 1733471d1714SBenjamin Tissoires 1734471d1714SBenjamin Tissoires wacom->usbdev = dev; 1735471d1714SBenjamin Tissoires wacom->intf = intf; 1736471d1714SBenjamin Tissoires mutex_init(&wacom->lock); 1737471d1714SBenjamin Tissoires INIT_WORK(&wacom->work, wacom_wireless_work); 1738471d1714SBenjamin Tissoires 1739494078b0SBenjamin Tissoires error = wacom_allocate_inputs(wacom); 1740494078b0SBenjamin Tissoires if (error) 1741494078b0SBenjamin Tissoires goto fail_allocate_inputs; 1742494078b0SBenjamin Tissoires 17438c97a765SBenjamin Tissoires /* 17448c97a765SBenjamin Tissoires * Bamboo Pad has a generic hid handling for the Pen, and we switch it 17458c97a765SBenjamin Tissoires * into debug mode for the touch part. 17468c97a765SBenjamin Tissoires * We ignore the other interfaces. 17478c97a765SBenjamin Tissoires */ 17488c97a765SBenjamin Tissoires if (features->type == BAMBOO_PAD) { 17498c97a765SBenjamin Tissoires if (features->pktlen == WACOM_PKGLEN_PENABLED) { 17508c97a765SBenjamin Tissoires features->type = HID_GENERIC; 17518c97a765SBenjamin Tissoires } else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) && 17528c97a765SBenjamin Tissoires (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) { 17538c97a765SBenjamin Tissoires error = -ENODEV; 17548c97a765SBenjamin Tissoires goto fail_shared_data; 17558c97a765SBenjamin Tissoires } 17568c97a765SBenjamin Tissoires } 17578c97a765SBenjamin Tissoires 1758471d1714SBenjamin Tissoires /* set the default size in case we do not get them from hid */ 1759471d1714SBenjamin Tissoires wacom_set_default_phy(features); 1760471d1714SBenjamin Tissoires 1761471d1714SBenjamin Tissoires /* Retrieve the physical and logical size for touch devices */ 1762471d1714SBenjamin Tissoires wacom_retrieve_hid_descriptor(hdev, features); 176342f4f272SPing Cheng wacom_setup_device_quirks(wacom); 1764042628abSJason Gerecke 1765aa86b18cSJason Gerecke if (features->device_type == WACOM_DEVICETYPE_NONE && 1766aa86b18cSJason Gerecke features->type != WIRELESS) { 17678e116d31SJason Gerecke error = features->type == HID_GENERIC ? -ENODEV : 0; 17688e116d31SJason Gerecke 1769042628abSJason Gerecke dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.", 17708e116d31SJason Gerecke hdev->name, 17718e116d31SJason Gerecke error ? "Ignoring" : "Assuming pen"); 17728e116d31SJason Gerecke 17738e116d31SJason Gerecke if (error) 17748e116d31SJason Gerecke goto fail_shared_data; 1775042628abSJason Gerecke 1776aa86b18cSJason Gerecke features->device_type |= WACOM_DEVICETYPE_PEN; 1777042628abSJason Gerecke } 1778042628abSJason Gerecke 1779*3b164a00SPing Cheng /* Note that if query fails it is not a hard failure */ 1780*3b164a00SPing Cheng wacom_query_tablet_data(hdev, features); 1781*3b164a00SPing Cheng 1782*3b164a00SPing Cheng /* touch only Bamboo doesn't support pen */ 1783*3b164a00SPing Cheng if ((features->type == BAMBOO_TOUCH) && 1784*3b164a00SPing Cheng (features->device_type & WACOM_DEVICETYPE_PEN)) { 1785*3b164a00SPing Cheng error = -ENODEV; 1786*3b164a00SPing Cheng goto fail_shared_data; 1787*3b164a00SPing Cheng } 1788*3b164a00SPing Cheng 1789*3b164a00SPing Cheng /* pen only Bamboo neither support touch nor pad */ 1790*3b164a00SPing Cheng if ((features->type == BAMBOO_PEN) && 1791*3b164a00SPing Cheng ((features->device_type & WACOM_DEVICETYPE_TOUCH) || 1792*3b164a00SPing Cheng (features->device_type & WACOM_DEVICETYPE_PAD))) { 1793*3b164a00SPing Cheng error = -ENODEV; 1794*3b164a00SPing Cheng goto fail_shared_data; 1795*3b164a00SPing Cheng } 1796*3b164a00SPing Cheng 1797471d1714SBenjamin Tissoires wacom_calculate_res(features); 1798471d1714SBenjamin Tissoires 1799c24eab4eSPing Cheng wacom_update_name(wacom); 1800471d1714SBenjamin Tissoires 1801471d1714SBenjamin Tissoires error = wacom_add_shared_data(hdev); 1802471d1714SBenjamin Tissoires if (error) 18037fefeec5SBenjamin Tissoires goto fail_shared_data; 1804471d1714SBenjamin Tissoires 1805ccad85ccSJason Gerecke if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) && 1806f81a1295SBenjamin Tissoires (features->quirks & WACOM_QUIRK_BATTERY)) { 1807f81a1295SBenjamin Tissoires error = wacom_initialize_battery(wacom); 1808f81a1295SBenjamin Tissoires if (error) 18097fefeec5SBenjamin Tissoires goto fail_battery; 1810f81a1295SBenjamin Tissoires } 1811f81a1295SBenjamin Tissoires 1812494078b0SBenjamin Tissoires error = wacom_register_inputs(wacom); 1813471d1714SBenjamin Tissoires if (error) 18147fefeec5SBenjamin Tissoires goto fail_register_inputs; 1815f81a1295SBenjamin Tissoires 1816f81a1295SBenjamin Tissoires if (hdev->bus == BUS_BLUETOOTH) { 1817f81a1295SBenjamin Tissoires error = device_create_file(&hdev->dev, &dev_attr_speed); 1818f81a1295SBenjamin Tissoires if (error) 1819f81a1295SBenjamin Tissoires hid_warn(hdev, 1820f81a1295SBenjamin Tissoires "can't create sysfs speed attribute err: %d\n", 1821f81a1295SBenjamin Tissoires error); 1822471d1714SBenjamin Tissoires } 1823471d1714SBenjamin Tissoires 18247704ac93SBenjamin Tissoires if (features->type == HID_GENERIC) 18257704ac93SBenjamin Tissoires connect_mask |= HID_CONNECT_DRIVER; 18267704ac93SBenjamin Tissoires 1827471d1714SBenjamin Tissoires /* Regular HID work starts now */ 18287704ac93SBenjamin Tissoires error = hid_hw_start(hdev, connect_mask); 1829471d1714SBenjamin Tissoires if (error) { 1830471d1714SBenjamin Tissoires hid_err(hdev, "hw start failed\n"); 18317fefeec5SBenjamin Tissoires goto fail_hw_start; 1832471d1714SBenjamin Tissoires } 1833471d1714SBenjamin Tissoires 1834ccad85ccSJason Gerecke if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) 1835471d1714SBenjamin Tissoires error = hid_hw_open(hdev); 1836471d1714SBenjamin Tissoires 1837862cf553SJason Gerecke if (wacom_wac->features.type == INTUOSHT && 1838862cf553SJason Gerecke wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) { 18392a6cdbddSJason Gerecke wacom_wac->shared->touch_input = wacom_wac->touch_input; 1840471d1714SBenjamin Tissoires } 1841471d1714SBenjamin Tissoires 1842471d1714SBenjamin Tissoires return 0; 1843471d1714SBenjamin Tissoires 18447fefeec5SBenjamin Tissoires fail_hw_start: 18457fefeec5SBenjamin Tissoires if (hdev->bus == BUS_BLUETOOTH) 18467fefeec5SBenjamin Tissoires device_remove_file(&hdev->dev, &dev_attr_speed); 18477fefeec5SBenjamin Tissoires fail_register_inputs: 18482546dacdSBenjamin Tissoires wacom_clean_inputs(wacom); 18497fefeec5SBenjamin Tissoires wacom_destroy_battery(wacom); 18507fefeec5SBenjamin Tissoires fail_battery: 1851a97ac104SBenjamin Tissoires wacom_remove_shared_data(wacom); 18527fefeec5SBenjamin Tissoires fail_shared_data: 1853494078b0SBenjamin Tissoires wacom_clean_inputs(wacom); 1854494078b0SBenjamin Tissoires fail_allocate_inputs: 18557fefeec5SBenjamin Tissoires fail_type: 18567fefeec5SBenjamin Tissoires fail_pktlen: 18577fefeec5SBenjamin Tissoires fail_parse: 18587fefeec5SBenjamin Tissoires kfree(wacom); 1859471d1714SBenjamin Tissoires hid_set_drvdata(hdev, NULL); 1860471d1714SBenjamin Tissoires return error; 1861471d1714SBenjamin Tissoires } 1862471d1714SBenjamin Tissoires 1863471d1714SBenjamin Tissoires static void wacom_remove(struct hid_device *hdev) 1864471d1714SBenjamin Tissoires { 1865471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 1866471d1714SBenjamin Tissoires 1867471d1714SBenjamin Tissoires hid_hw_stop(hdev); 1868471d1714SBenjamin Tissoires 1869471d1714SBenjamin Tissoires cancel_work_sync(&wacom->work); 18702546dacdSBenjamin Tissoires wacom_clean_inputs(wacom); 1871f81a1295SBenjamin Tissoires if (hdev->bus == BUS_BLUETOOTH) 1872f81a1295SBenjamin Tissoires device_remove_file(&hdev->dev, &dev_attr_speed); 1873471d1714SBenjamin Tissoires wacom_destroy_battery(wacom); 1874a97ac104SBenjamin Tissoires wacom_remove_shared_data(wacom); 1875471d1714SBenjamin Tissoires 1876471d1714SBenjamin Tissoires hid_set_drvdata(hdev, NULL); 1877471d1714SBenjamin Tissoires kfree(wacom); 1878471d1714SBenjamin Tissoires } 1879471d1714SBenjamin Tissoires 188041a74581SGeert Uytterhoeven #ifdef CONFIG_PM 1881471d1714SBenjamin Tissoires static int wacom_resume(struct hid_device *hdev) 1882471d1714SBenjamin Tissoires { 1883471d1714SBenjamin Tissoires struct wacom *wacom = hid_get_drvdata(hdev); 1884471d1714SBenjamin Tissoires struct wacom_features *features = &wacom->wacom_wac.features; 1885471d1714SBenjamin Tissoires 1886471d1714SBenjamin Tissoires mutex_lock(&wacom->lock); 1887471d1714SBenjamin Tissoires 1888471d1714SBenjamin Tissoires /* switch to wacom mode first */ 1889471d1714SBenjamin Tissoires wacom_query_tablet_data(hdev, features); 1890471d1714SBenjamin Tissoires wacom_led_control(wacom); 1891471d1714SBenjamin Tissoires 1892471d1714SBenjamin Tissoires mutex_unlock(&wacom->lock); 1893471d1714SBenjamin Tissoires 1894471d1714SBenjamin Tissoires return 0; 1895471d1714SBenjamin Tissoires } 1896471d1714SBenjamin Tissoires 1897471d1714SBenjamin Tissoires static int wacom_reset_resume(struct hid_device *hdev) 1898471d1714SBenjamin Tissoires { 1899471d1714SBenjamin Tissoires return wacom_resume(hdev); 1900471d1714SBenjamin Tissoires } 190141a74581SGeert Uytterhoeven #endif /* CONFIG_PM */ 1902471d1714SBenjamin Tissoires 1903471d1714SBenjamin Tissoires static struct hid_driver wacom_driver = { 1904471d1714SBenjamin Tissoires .name = "wacom", 1905471d1714SBenjamin Tissoires .id_table = wacom_ids, 1906471d1714SBenjamin Tissoires .probe = wacom_probe, 1907471d1714SBenjamin Tissoires .remove = wacom_remove, 19087704ac93SBenjamin Tissoires .report = wacom_wac_report, 1909471d1714SBenjamin Tissoires #ifdef CONFIG_PM 1910471d1714SBenjamin Tissoires .resume = wacom_resume, 1911471d1714SBenjamin Tissoires .reset_resume = wacom_reset_resume, 1912471d1714SBenjamin Tissoires #endif 1913471d1714SBenjamin Tissoires .raw_event = wacom_raw_event, 1914471d1714SBenjamin Tissoires }; 1915471d1714SBenjamin Tissoires module_hid_driver(wacom_driver); 1916f2e0a7d4SBenjamin Tissoires 1917f2e0a7d4SBenjamin Tissoires MODULE_VERSION(DRIVER_VERSION); 1918f2e0a7d4SBenjamin Tissoires MODULE_AUTHOR(DRIVER_AUTHOR); 1919f2e0a7d4SBenjamin Tissoires MODULE_DESCRIPTION(DRIVER_DESC); 1920f2e0a7d4SBenjamin Tissoires MODULE_LICENSE(DRIVER_LICENSE); 1921