0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/input.h>
0013 #include <linux/serio.h>
0014 #include <linux/libps2.h>
0015 #include <linux/dmi.h>
0016 #include <linux/slab.h>
0017 #include <linux/types.h>
0018
0019 #include "psmouse.h"
0020 #include "lifebook.h"
0021
0022 struct lifebook_data {
0023 struct input_dev *dev2;
0024 char phys[32];
0025 };
0026
0027 static bool lifebook_present;
0028
0029 static const char *desired_serio_phys;
0030
0031 static int lifebook_limit_serio3(const struct dmi_system_id *d)
0032 {
0033 desired_serio_phys = "isa0060/serio3";
0034 return 1;
0035 }
0036
0037 static bool lifebook_use_6byte_proto;
0038
0039 static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
0040 {
0041 lifebook_use_6byte_proto = true;
0042 return 1;
0043 }
0044
0045 static const struct dmi_system_id lifebook_dmi_table[] __initconst = {
0046 {
0047
0048 .matches = {
0049 DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
0050 },
0051 },
0052 {
0053
0054 .matches = {
0055 DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"),
0056 },
0057 },
0058 {
0059
0060 .matches = {
0061 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
0062 },
0063 },
0064 {
0065
0066 .matches = {
0067 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
0068 },
0069 },
0070 {
0071
0072 .matches = {
0073 DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"),
0074 },
0075 },
0076 {
0077
0078 .matches = {
0079 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
0080 },
0081 },
0082 {
0083
0084 .matches = {
0085 DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
0086 },
0087 },
0088 {
0089
0090 .matches = {
0091 DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
0092 },
0093 .callback = lifebook_limit_serio3,
0094 },
0095 {
0096
0097 .matches = {
0098 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
0099 DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
0100 },
0101 .callback = lifebook_set_6byte_proto,
0102 },
0103 {
0104
0105 .matches = {
0106 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
0107 DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
0108 },
0109 .callback = lifebook_set_6byte_proto,
0110 },
0111 {
0112
0113 .matches = {
0114 DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
0115 },
0116 .callback = lifebook_set_6byte_proto,
0117 },
0118 {
0119
0120 .matches = {
0121 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
0122 },
0123 },
0124 { }
0125 };
0126
0127 void __init lifebook_module_init(void)
0128 {
0129 lifebook_present = dmi_check_system(lifebook_dmi_table);
0130 }
0131
0132 static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
0133 {
0134 struct lifebook_data *priv = psmouse->private;
0135 struct input_dev *dev1 = psmouse->dev;
0136 struct input_dev *dev2 = priv ? priv->dev2 : NULL;
0137 u8 *packet = psmouse->packet;
0138 bool relative_packet = packet[0] & 0x08;
0139
0140 if (relative_packet || !lifebook_use_6byte_proto) {
0141 if (psmouse->pktcnt != 3)
0142 return PSMOUSE_GOOD_DATA;
0143 } else {
0144 switch (psmouse->pktcnt) {
0145 case 1:
0146 return (packet[0] & 0xf8) == 0x00 ?
0147 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
0148 case 2:
0149 return PSMOUSE_GOOD_DATA;
0150 case 3:
0151 return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
0152 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
0153 case 4:
0154 return (packet[3] & 0xf8) == 0xc0 ?
0155 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
0156 case 5:
0157 return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
0158 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
0159 case 6:
0160 if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
0161 return PSMOUSE_BAD_DATA;
0162 if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
0163 return PSMOUSE_BAD_DATA;
0164 break;
0165 }
0166 }
0167
0168 if (relative_packet) {
0169 if (!dev2)
0170 psmouse_warn(psmouse,
0171 "got relative packet but no relative device set up\n");
0172 } else {
0173 if (lifebook_use_6byte_proto) {
0174 input_report_abs(dev1, ABS_X,
0175 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
0176 input_report_abs(dev1, ABS_Y,
0177 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
0178 } else {
0179 input_report_abs(dev1, ABS_X,
0180 (packet[1] | ((packet[0] & 0x30) << 4)));
0181 input_report_abs(dev1, ABS_Y,
0182 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
0183 }
0184 input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
0185 input_sync(dev1);
0186 }
0187
0188 if (dev2) {
0189 if (relative_packet)
0190 psmouse_report_standard_motion(dev2, packet);
0191
0192 psmouse_report_standard_buttons(dev2, packet[0]);
0193 input_sync(dev2);
0194 }
0195
0196 return PSMOUSE_FULL_PACKET;
0197 }
0198
0199 static int lifebook_absolute_mode(struct psmouse *psmouse)
0200 {
0201 struct ps2dev *ps2dev = &psmouse->ps2dev;
0202 u8 param;
0203 int error;
0204
0205 error = psmouse_reset(psmouse);
0206 if (error)
0207 return error;
0208
0209
0210
0211
0212
0213
0214 param = lifebook_use_6byte_proto ? 0x08 : 0x07;
0215 ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
0216
0217 return 0;
0218 }
0219
0220 static void lifebook_relative_mode(struct psmouse *psmouse)
0221 {
0222 struct ps2dev *ps2dev = &psmouse->ps2dev;
0223 u8 param = 0x06;
0224
0225 ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
0226 }
0227
0228 static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
0229 {
0230 static const u8 params[] = { 0, 1, 2, 2, 3 };
0231 u8 p;
0232
0233 if (resolution == 0 || resolution > 400)
0234 resolution = 400;
0235
0236 p = params[resolution / 100];
0237 ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
0238 psmouse->resolution = 50 << p;
0239 }
0240
0241 static void lifebook_disconnect(struct psmouse *psmouse)
0242 {
0243 struct lifebook_data *priv = psmouse->private;
0244
0245 psmouse_reset(psmouse);
0246 if (priv) {
0247 input_unregister_device(priv->dev2);
0248 kfree(priv);
0249 }
0250 psmouse->private = NULL;
0251 }
0252
0253 int lifebook_detect(struct psmouse *psmouse, bool set_properties)
0254 {
0255 if (!lifebook_present)
0256 return -ENXIO;
0257
0258 if (desired_serio_phys &&
0259 strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
0260 return -ENXIO;
0261
0262 if (set_properties) {
0263 psmouse->vendor = "Fujitsu";
0264 psmouse->name = "Lifebook TouchScreen";
0265 }
0266
0267 return 0;
0268 }
0269
0270 static int lifebook_create_relative_device(struct psmouse *psmouse)
0271 {
0272 struct input_dev *dev2;
0273 struct lifebook_data *priv;
0274 int error = -ENOMEM;
0275
0276 priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
0277 dev2 = input_allocate_device();
0278 if (!priv || !dev2)
0279 goto err_out;
0280
0281 priv->dev2 = dev2;
0282 snprintf(priv->phys, sizeof(priv->phys),
0283 "%s/input1", psmouse->ps2dev.serio->phys);
0284
0285 dev2->phys = priv->phys;
0286 dev2->name = "LBPS/2 Fujitsu Lifebook Touchpad";
0287 dev2->id.bustype = BUS_I8042;
0288 dev2->id.vendor = 0x0002;
0289 dev2->id.product = PSMOUSE_LIFEBOOK;
0290 dev2->id.version = 0x0000;
0291 dev2->dev.parent = &psmouse->ps2dev.serio->dev;
0292
0293 input_set_capability(dev2, EV_REL, REL_X);
0294 input_set_capability(dev2, EV_REL, REL_Y);
0295 input_set_capability(dev2, EV_KEY, BTN_LEFT);
0296 input_set_capability(dev2, EV_KEY, BTN_RIGHT);
0297
0298 error = input_register_device(priv->dev2);
0299 if (error)
0300 goto err_out;
0301
0302 psmouse->private = priv;
0303 return 0;
0304
0305 err_out:
0306 input_free_device(dev2);
0307 kfree(priv);
0308 return error;
0309 }
0310
0311 int lifebook_init(struct psmouse *psmouse)
0312 {
0313 struct input_dev *dev1 = psmouse->dev;
0314 int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
0315 int error;
0316
0317 error = lifebook_absolute_mode(psmouse);
0318 if (error)
0319 return error;
0320
0321
0322 bitmap_zero(dev1->evbit, EV_CNT);
0323 bitmap_zero(dev1->relbit, REL_CNT);
0324 bitmap_zero(dev1->keybit, KEY_CNT);
0325
0326 input_set_capability(dev1, EV_KEY, BTN_TOUCH);
0327 input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
0328 input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
0329
0330 if (!desired_serio_phys) {
0331 error = lifebook_create_relative_device(psmouse);
0332 if (error) {
0333 lifebook_relative_mode(psmouse);
0334 return error;
0335 }
0336 }
0337
0338 psmouse->protocol_handler = lifebook_process_byte;
0339 psmouse->set_resolution = lifebook_set_resolution;
0340 psmouse->disconnect = lifebook_disconnect;
0341 psmouse->reconnect = lifebook_absolute_mode;
0342
0343 psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
0344
0345
0346
0347
0348
0349 psmouse->pktsize = 3;
0350
0351 return 0;
0352 }
0353