diff options
| author | Dmitry Torokhov <dtor@insightbb.com> | 2007-04-25 00:39:53 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-04-25 00:39:53 -0400 |
| commit | 2ebdcc615bde8317058d76ce1f24a67f59185884 (patch) | |
| tree | fb9749384a7c69a8545ae1a9de8c5eb1c6c723dc /drivers/input | |
| parent | 43887ba15a0c1e293be63793541fe444778c0474 (diff) | |
Input: lifebook - split into 2 devices
Have lifebook protocol register 2 separate input devices -
one for the touchscreen reporting absolute coordinates and
touches and another one for touchpad reporting relative
coordinates and left and right button presses.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/mouse/lifebook.c | 113 |
1 files changed, 93 insertions, 20 deletions
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index aa3b245f25d9..1740cadd9594 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | #include "psmouse.h" | 20 | #include "psmouse.h" |
| 21 | #include "lifebook.h" | 21 | #include "lifebook.h" |
| 22 | 22 | ||
| 23 | struct lifebook_data { | ||
| 24 | struct input_dev *dev2; /* Relative device */ | ||
| 25 | char phys[32]; | ||
| 26 | }; | ||
| 27 | |||
| 23 | static const char *desired_serio_phys; | 28 | static const char *desired_serio_phys; |
| 24 | 29 | ||
| 25 | static int lifebook_set_serio_phys(struct dmi_system_id *d) | 30 | static int lifebook_set_serio_phys(struct dmi_system_id *d) |
| @@ -102,7 +107,9 @@ static struct dmi_system_id lifebook_dmi_table[] = { | |||
| 102 | 107 | ||
| 103 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) | 108 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) |
| 104 | { | 109 | { |
| 105 | struct input_dev *dev = psmouse->dev; | 110 | struct lifebook_data *priv = psmouse->private; |
| 111 | struct input_dev *dev1 = psmouse->dev; | ||
| 112 | struct input_dev *dev2 = priv->dev2; | ||
| 106 | unsigned char *packet = psmouse->packet; | 113 | unsigned char *packet = psmouse->packet; |
| 107 | int relative_packet = packet[0] & 0x08; | 114 | int relative_packet = packet[0] & 0x08; |
| 108 | 115 | ||
| @@ -135,27 +142,35 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) | |||
| 135 | } | 142 | } |
| 136 | 143 | ||
| 137 | if (relative_packet) { | 144 | if (relative_packet) { |
| 138 | input_report_rel(dev, REL_X, | 145 | if (!dev2) |
| 139 | ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); | 146 | printk(KERN_WARNING "lifebook.c: got relative packet " |
| 140 | input_report_rel(dev, REL_Y, | 147 | "but no relative device set up\n"); |
| 141 | -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); | ||
| 142 | } else if (lifebook_use_6byte_proto) { | 148 | } else if (lifebook_use_6byte_proto) { |
| 143 | input_report_abs(dev, ABS_X, | 149 | input_report_abs(dev1, ABS_X, |
| 144 | ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); | 150 | ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); |
| 145 | input_report_abs(dev, ABS_Y, | 151 | input_report_abs(dev1, ABS_Y, |
| 146 | 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); | 152 | 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); |
| 147 | } else { | 153 | } else { |
| 148 | input_report_abs(dev, ABS_X, | 154 | input_report_abs(dev1, ABS_X, |
| 149 | (packet[1] | ((packet[0] & 0x30) << 4))); | 155 | (packet[1] | ((packet[0] & 0x30) << 4))); |
| 150 | input_report_abs(dev, ABS_Y, | 156 | input_report_abs(dev1, ABS_Y, |
| 151 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); | 157 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); |
| 152 | } | 158 | } |
| 153 | 159 | ||
| 154 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 160 | input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); |
| 155 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 161 | input_sync(dev1); |
| 156 | input_report_key(dev, BTN_TOUCH, packet[0] & 0x04); | ||
| 157 | 162 | ||
| 158 | input_sync(dev); | 163 | if (dev2) { |
| 164 | if (relative_packet) { | ||
| 165 | input_report_rel(dev2, REL_X, | ||
| 166 | ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); | ||
| 167 | input_report_rel(dev2, REL_Y, | ||
| 168 | -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); | ||
| 169 | } | ||
| 170 | input_report_key(dev2, BTN_LEFT, packet[0] & 0x01); | ||
| 171 | input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02); | ||
| 172 | input_sync(dev2); | ||
| 173 | } | ||
| 159 | 174 | ||
| 160 | return PSMOUSE_FULL_PACKET; | 175 | return PSMOUSE_FULL_PACKET; |
| 161 | } | 176 | } |
| @@ -179,6 +194,14 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) | |||
| 179 | return 0; | 194 | return 0; |
| 180 | } | 195 | } |
| 181 | 196 | ||
| 197 | static void lifebook_relative_mode(struct psmouse *psmouse) | ||
| 198 | { | ||
| 199 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
| 200 | unsigned char param = 0x06; | ||
| 201 | |||
| 202 | ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); | ||
| 203 | } | ||
| 204 | |||
| 182 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 205 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
| 183 | { | 206 | { |
| 184 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; | 207 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
| @@ -195,6 +218,8 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu | |||
| 195 | static void lifebook_disconnect(struct psmouse *psmouse) | 218 | static void lifebook_disconnect(struct psmouse *psmouse) |
| 196 | { | 219 | { |
| 197 | psmouse_reset(psmouse); | 220 | psmouse_reset(psmouse); |
| 221 | kfree(psmouse->private); | ||
| 222 | psmouse->private = NULL; | ||
| 198 | } | 223 | } |
| 199 | 224 | ||
| 200 | int lifebook_detect(struct psmouse *psmouse, int set_properties) | 225 | int lifebook_detect(struct psmouse *psmouse, int set_properties) |
| @@ -214,26 +239,74 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) | |||
| 214 | return 0; | 239 | return 0; |
| 215 | } | 240 | } |
| 216 | 241 | ||
| 242 | static int lifebook_create_relative_device(struct psmouse *psmouse) | ||
| 243 | { | ||
| 244 | struct input_dev *dev2; | ||
| 245 | struct lifebook_data *priv; | ||
| 246 | int error = -ENOMEM; | ||
| 247 | |||
| 248 | priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL); | ||
| 249 | dev2 = input_allocate_device(); | ||
| 250 | if (!priv || !dev2) | ||
| 251 | goto err_out; | ||
| 252 | |||
| 253 | priv->dev2 = dev2; | ||
| 254 | snprintf(priv->phys, sizeof(priv->phys), | ||
| 255 | "%s/input1", psmouse->ps2dev.serio->phys); | ||
| 256 | |||
| 257 | dev2->phys = priv->phys; | ||
| 258 | dev2->name = "PS/2 Touchpad"; | ||
| 259 | dev2->id.bustype = BUS_I8042; | ||
| 260 | dev2->id.vendor = 0x0002; | ||
| 261 | dev2->id.product = PSMOUSE_LIFEBOOK; | ||
| 262 | dev2->id.version = 0x0000; | ||
| 263 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; | ||
| 264 | |||
| 265 | dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
| 266 | dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y); | ||
| 267 | dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); | ||
| 268 | |||
| 269 | error = input_register_device(priv->dev2); | ||
| 270 | if (error) | ||
| 271 | goto err_out; | ||
| 272 | |||
| 273 | psmouse->private = priv; | ||
| 274 | return 0; | ||
| 275 | |||
| 276 | err_out: | ||
| 277 | input_free_device(dev2); | ||
| 278 | kfree(priv); | ||
| 279 | return error; | ||
| 280 | } | ||
| 281 | |||
| 217 | int lifebook_init(struct psmouse *psmouse) | 282 | int lifebook_init(struct psmouse *psmouse) |
| 218 | { | 283 | { |
| 219 | struct input_dev *input_dev = psmouse->dev; | 284 | struct input_dev *dev1 = psmouse->dev; |
| 220 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; | 285 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; |
| 221 | 286 | ||
| 222 | if (lifebook_absolute_mode(psmouse)) | 287 | if (lifebook_absolute_mode(psmouse)) |
| 223 | return -1; | 288 | return -1; |
| 224 | 289 | ||
| 225 | input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); | 290 | dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); |
| 226 | input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | 291 | dev1->relbit[0] = 0; |
| 227 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 292 | dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
| 228 | input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); | 293 | input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); |
| 229 | input_set_abs_params(input_dev, ABS_X, 0, max_coord, 0, 0); | 294 | input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); |
| 230 | input_set_abs_params(input_dev, ABS_Y, 0, max_coord, 0, 0); | 295 | |
| 296 | if (!desired_serio_phys) { | ||
| 297 | if (lifebook_create_relative_device(psmouse)) { | ||
| 298 | lifebook_relative_mode(psmouse); | ||
| 299 | return -1; | ||
| 300 | } | ||
| 301 | } | ||
| 231 | 302 | ||
| 232 | psmouse->protocol_handler = lifebook_process_byte; | 303 | psmouse->protocol_handler = lifebook_process_byte; |
| 233 | psmouse->set_resolution = lifebook_set_resolution; | 304 | psmouse->set_resolution = lifebook_set_resolution; |
| 234 | psmouse->disconnect = lifebook_disconnect; | 305 | psmouse->disconnect = lifebook_disconnect; |
| 235 | psmouse->reconnect = lifebook_absolute_mode; | 306 | psmouse->reconnect = lifebook_absolute_mode; |
| 236 | 307 | ||
| 308 | psmouse->model = lifebook_use_6byte_proto ? 6 : 3; | ||
| 309 | |||
| 237 | /* | 310 | /* |
| 238 | * Use packet size = 3 even when using 6-byte protocol because | 311 | * Use packet size = 3 even when using 6-byte protocol because |
| 239 | * that's what POLL will return on Lifebooks (according to spec). | 312 | * that's what POLL will return on Lifebooks (according to spec). |
