Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: hanwang - add support for Art Master HD 5012 tablet

This adds support for hanwang Art Master HD 5012 electromagnetic tablet.

Signed-off-by: Xing Wei <weixing@hanwang.com.cn>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Xing Wei and committed by
Dmitry Torokhov
727eeb7d f5854fad

+73 -21
+73 -21
drivers/input/tablet/hanwang.c
··· 42 42 #define HANWANG_TABLET_INT_SUB_CLASS 0x0001 43 43 #define HANWANG_TABLET_INT_PROTOCOL 0x0002 44 44 45 - #define ART_MASTERIII_PKGLEN_MAX 10 45 + #define ART_MASTER_PKGLEN_MAX 10 46 46 47 47 /* device IDs */ 48 48 #define STYLUS_DEVICE_ID 0x02 ··· 60 60 .bInterfaceSubClass = (sc), \ 61 61 .bInterfaceProtocol = (pr) 62 62 63 + enum hanwang_tablet_type { 64 + HANWANG_ART_MASTER_III, 65 + HANWANG_ART_MASTER_HD, 66 + }; 67 + 63 68 struct hanwang { 64 69 unsigned char *data; 65 70 dma_addr_t data_dma; ··· 81 76 struct hanwang_features { 82 77 unsigned short pid; 83 78 char *name; 79 + enum hanwang_tablet_type type; 84 80 int pkg_len; 85 81 int max_x; 86 82 int max_y; ··· 91 85 }; 92 86 93 87 static const struct hanwang_features features_array[] = { 94 - { 0x8528, "Hanwang Art Master III 0906", 95 - ART_MASTERIII_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 }, 96 - { 0x8529, "Hanwang Art Master III 0604", 97 - ART_MASTERIII_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 }, 98 - { 0x852a, "Hanwang Art Master III 1308", 99 - ART_MASTERIII_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 }, 88 + { 0x8528, "Hanwang Art Master III 0906", HANWANG_ART_MASTER_III, 89 + ART_MASTER_PKGLEN_MAX, 0x5757, 0x3692, 0x3f, 0x7f, 2048 }, 90 + { 0x8529, "Hanwang Art Master III 0604", HANWANG_ART_MASTER_III, 91 + ART_MASTER_PKGLEN_MAX, 0x3d84, 0x2672, 0x3f, 0x7f, 2048 }, 92 + { 0x852a, "Hanwang Art Master III 1308", HANWANG_ART_MASTER_III, 93 + ART_MASTER_PKGLEN_MAX, 0x7f00, 0x4f60, 0x3f, 0x7f, 2048 }, 94 + { 0x8401, "Hanwang Art Master HD 5012", HANWANG_ART_MASTER_HD, 95 + ART_MASTER_PKGLEN_MAX, 0x678e, 0x4150, 0x3f, 0x7f, 1024 }, 100 96 }; 101 97 102 98 static const int hw_eventtypes[] = { ··· 107 99 108 100 static const int hw_absevents[] = { 109 101 ABS_X, ABS_Y, ABS_TILT_X, ABS_TILT_Y, ABS_WHEEL, 110 - ABS_PRESSURE, ABS_MISC, 102 + ABS_RX, ABS_RY, ABS_PRESSURE, ABS_MISC, 111 103 }; 112 104 113 105 static const int hw_btnevents[] = { ··· 125 117 unsigned char *data = hanwang->data; 126 118 struct input_dev *input_dev = hanwang->dev; 127 119 struct usb_device *dev = hanwang->usbdev; 120 + enum hanwang_tablet_type type = hanwang->features->type; 128 121 int i; 122 + u16 x, y, p; 129 123 130 124 switch (data[0]) { 131 125 case 0x02: /* data packet */ ··· 139 129 140 130 case 0xc2: /* first time tool prox in */ 141 131 switch (data[3] & 0xf0) { 142 - case 0x20: 132 + case 0x20: /* art_master III */ 133 + case 0x30: /* art_master_HD */ 143 134 hanwang->current_id = STYLUS_DEVICE_ID; 144 135 hanwang->current_tool = BTN_TOOL_PEN; 145 136 input_report_key(input_dev, BTN_TOOL_PEN, 1); 146 137 break; 147 - case 0xa0: 138 + case 0xa0: /* art_master III */ 139 + case 0xb0: /* art_master_HD */ 148 140 hanwang->current_id = ERASER_DEVICE_ID; 149 141 hanwang->current_tool = BTN_TOOL_RUBBER; 150 142 input_report_key(input_dev, BTN_TOOL_RUBBER, 1); ··· 160 148 break; 161 149 162 150 default: /* tool data packet */ 151 + x = (data[2] << 8) | data[3]; 152 + y = (data[4] << 8) | data[5]; 153 + 154 + switch (type) { 155 + case HANWANG_ART_MASTER_III: 156 + p = (data[6] << 3) | 157 + ((data[7] & 0xc0) >> 5) | 158 + (data[1] & 0x01); 159 + break; 160 + 161 + case HANWANG_ART_MASTER_HD: 162 + p = (data[7] >> 6) | (data[6] << 2); 163 + break; 164 + 165 + default: 166 + p = 0; 167 + break; 168 + } 169 + 163 170 input_report_abs(input_dev, ABS_X, 164 - (data[2] << 8) | data[3]); 171 + le16_to_cpup((__le16 *)&x)); 165 172 input_report_abs(input_dev, ABS_Y, 166 - (data[4] << 8) | data[5]); 173 + le16_to_cpup((__le16 *)&y)); 167 174 input_report_abs(input_dev, ABS_PRESSURE, 168 - (data[6] << 3) | 169 - ((data[7] & 0xc0) >> 5) | 170 - (data[1] & 0x01)); 175 + le16_to_cpup((__le16 *)&p)); 171 176 input_report_abs(input_dev, ABS_TILT_X, data[7] & 0x3f); 172 177 input_report_abs(input_dev, ABS_TILT_Y, data[8] & 0x7f); 173 178 input_report_key(input_dev, BTN_STYLUS, data[1] & 0x02); ··· 199 170 case 0x0c: 200 171 /* roll wheel */ 201 172 hanwang->current_id = PAD_DEVICE_ID; 202 - input_report_key(input_dev, BTN_TOOL_FINGER, data[1] || 203 - data[2] || data[3]); 204 - input_report_abs(input_dev, ABS_WHEEL, data[1]); 205 - input_report_key(input_dev, BTN_0, data[2]); 206 - for (i = 0; i < 8; i++) 207 - input_report_key(input_dev, 173 + 174 + switch (type) { 175 + case HANWANG_ART_MASTER_III: 176 + input_report_key(input_dev, BTN_TOOL_FINGER, data[1] || 177 + data[2] || data[3]); 178 + input_report_abs(input_dev, ABS_WHEEL, data[1]); 179 + input_report_key(input_dev, BTN_0, data[2]); 180 + for (i = 0; i < 8; i++) 181 + input_report_key(input_dev, 208 182 BTN_1 + i, data[3] & (1 << i)); 183 + break; 184 + 185 + case HANWANG_ART_MASTER_HD: 186 + input_report_key(input_dev, BTN_TOOL_FINGER, data[1] || 187 + data[2] || data[3] || data[4] || 188 + data[5] || data[6]); 189 + input_report_abs(input_dev, ABS_RX, 190 + ((data[1] & 0x1f) << 8) | data[2]); 191 + input_report_abs(input_dev, ABS_RY, 192 + ((data[3] & 0x1f) << 8) | data[4]); 193 + input_report_key(input_dev, BTN_0, data[5] & 0x01); 194 + for (i = 0; i < 4; i++) { 195 + input_report_key(input_dev, 196 + BTN_1 + i, data[5] & (1 << i)); 197 + input_report_key(input_dev, 198 + BTN_5 + i, data[6] & (1 << i)); 199 + } 200 + break; 201 + } 202 + 209 203 input_report_abs(input_dev, ABS_MISC, hanwang->current_id); 210 204 input_event(input_dev, EV_MSC, MSC_SERIAL, 0xffffffff); 211 205 break;