d078493bd58b582acb3ae2f2d88f2d74a501a3df
[linux-flexiantxendom0.git] / drivers / input / mouse / sentelic.c
1 /*-
2  * Finger Sensing Pad PS/2 mouse driver.
3  *
4  * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
5  * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation.
6  *
7  *   This program is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU General Public License
9  *   as published by the Free Software Foundation; either version 2
10  *   of the License, or (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <linux/module.h>
23 #include <linux/input.h>
24 #include <linux/ctype.h>
25 #include <linux/libps2.h>
26 #include <linux/serio.h>
27 #include <linux/jiffies.h>
28 #include <linux/slab.h>
29
30 #include "psmouse.h"
31 #include "sentelic.h"
32
33 /*
34  * Timeout for FSP PS/2 command only (in milliseconds).
35  */
36 #define FSP_CMD_TIMEOUT         200
37 #define FSP_CMD_TIMEOUT2        30
38
39 /** Driver version. */
40 static const char fsp_drv_ver[] = "1.0.0-K";
41
42 /*
43  * Make sure that the value being sent to FSP will not conflict with
44  * possible sample rate values.
45  */
46 static unsigned char fsp_test_swap_cmd(unsigned char reg_val)
47 {
48         switch (reg_val) {
49         case 10: case 20: case 40: case 60: case 80: case 100: case 200:
50                 /*
51                  * The requested value being sent to FSP matched to possible
52                  * sample rates, swap the given value such that the hardware
53                  * wouldn't get confused.
54                  */
55                 return (reg_val >> 4) | (reg_val << 4);
56         default:
57                 return reg_val; /* swap isn't necessary */
58         }
59 }
60
61 /*
62  * Make sure that the value being sent to FSP will not conflict with certain
63  * commands.
64  */
65 static unsigned char fsp_test_invert_cmd(unsigned char reg_val)
66 {
67         switch (reg_val) {
68         case 0xe9: case 0xee: case 0xf2: case 0xff:
69                 /*
70                  * The requested value being sent to FSP matched to certain
71                  * commands, inverse the given value such that the hardware
72                  * wouldn't get confused.
73                  */
74                 return ~reg_val;
75         default:
76                 return reg_val; /* inversion isn't necessary */
77         }
78 }
79
80 static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
81 {
82         struct ps2dev *ps2dev = &psmouse->ps2dev;
83         unsigned char param[3];
84         unsigned char addr;
85         int rc = -1;
86
87         /*
88          * We need to shut off the device and switch it into command
89          * mode so we don't confuse our protocol handler. We don't need
90          * to do that for writes because sysfs set helper does this for
91          * us.
92          */
93         psmouse_deactivate(psmouse);
94
95         ps2_begin_command(ps2dev);
96
97         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
98                 goto out;
99
100         /* should return 0xfe(request for resending) */
101         ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
102         /* should return 0xfc(failed) */
103         ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
104
105         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
106                 goto out;
107
108         if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
109                 ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2);
110         } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
111                 /* swapping is required */
112                 ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2);
113                 /* expect 0xfe */
114         } else {
115                 /* swapping isn't necessary */
116                 ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
117                 /* expect 0xfe */
118         }
119         /* should return 0xfc(failed) */
120         ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT);
121
122         if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0)
123                 goto out;
124
125         *reg_val = param[2];
126         rc = 0;
127
128  out:
129         ps2_end_command(ps2dev);
130         psmouse_activate(psmouse);
131         psmouse_dbg(psmouse,
132                     "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
133                     reg_addr, *reg_val, rc);
134         return rc;
135 }
136
137 static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
138 {
139         struct ps2dev *ps2dev = &psmouse->ps2dev;
140         unsigned char v;
141         int rc = -1;
142
143         ps2_begin_command(ps2dev);
144
145         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
146                 goto out;
147
148         if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
149                 /* inversion is required */
150                 ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2);
151         } else {
152                 if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
153                         /* swapping is required */
154                         ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2);
155                 } else {
156                         /* swapping isn't necessary */
157                         ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2);
158                 }
159         }
160         /* write the register address in correct order */
161         ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
162
163         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
164                 goto out;
165
166         if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
167                 /* inversion is required */
168                 ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
169         } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
170                 /* swapping is required */
171                 ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
172         } else {
173                 /* swapping isn't necessary */
174                 ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
175         }
176
177         /* write the register value in correct order */
178         ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
179         rc = 0;
180
181  out:
182         ps2_end_command(ps2dev);
183         psmouse_dbg(psmouse,
184                     "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
185                     reg_addr, reg_val, rc);
186         return rc;
187 }
188
189 /* Enable register clock gating for writing certain registers */
190 static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable)
191 {
192         int v, nv;
193
194         if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
195                 return -1;
196
197         if (enable)
198                 nv = v | FSP_BIT_EN_REG_CLK;
199         else
200                 nv = v & ~FSP_BIT_EN_REG_CLK;
201
202         /* only write if necessary */
203         if (nv != v)
204                 if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
205                         return -1;
206
207         return 0;
208 }
209
210 static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
211 {
212         struct ps2dev *ps2dev = &psmouse->ps2dev;
213         unsigned char param[3];
214         int rc = -1;
215
216         psmouse_deactivate(psmouse);
217
218         ps2_begin_command(ps2dev);
219
220         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
221                 goto out;
222
223         ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
224         ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
225
226         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
227                 goto out;
228
229         ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2);
230         ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
231
232         /* get the returned result */
233         if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
234                 goto out;
235
236         *reg_val = param[2];
237         rc = 0;
238
239  out:
240         ps2_end_command(ps2dev);
241         psmouse_activate(psmouse);
242         psmouse_dbg(psmouse,
243                     "READ PAGE REG: 0x%02x (rc = %d)\n",
244                     *reg_val, rc);
245         return rc;
246 }
247
248 static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
249 {
250         struct ps2dev *ps2dev = &psmouse->ps2dev;
251         unsigned char v;
252         int rc = -1;
253
254         ps2_begin_command(ps2dev);
255
256         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
257                 goto out;
258
259         ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2);
260         ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
261
262         if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
263                 goto out;
264
265         if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
266                 ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
267         } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
268                 /* swapping is required */
269                 ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
270         } else {
271                 /* swapping isn't necessary */
272                 ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
273         }
274
275         ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
276         rc = 0;
277
278  out:
279         ps2_end_command(ps2dev);
280         psmouse_dbg(psmouse,
281                     "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
282                     reg_val, rc);
283         return rc;
284 }
285
286 static int fsp_get_version(struct psmouse *psmouse, int *version)
287 {
288         if (fsp_reg_read(psmouse, FSP_REG_VERSION, version))
289                 return -EIO;
290
291         return 0;
292 }
293
294 static int fsp_get_revision(struct psmouse *psmouse, int *rev)
295 {
296         if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev))
297                 return -EIO;
298
299         return 0;
300 }
301
302 static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
303 {
304         static const int buttons[] = {
305                 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
306                 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */
307                 0x04, /* Left/Middle/Right & Scroll Up/Down */
308                 0x02, /* Left/Middle/Right */
309         };
310         int val;
311
312         if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS, &val) == -1)
313                 return -EIO;
314
315         *btn = buttons[(val & 0x30) >> 4];
316         return 0;
317 }
318
319 /* Enable on-pad command tag output */
320 static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
321 {
322         int v, nv;
323         int res = 0;
324
325         if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
326                 psmouse_err(psmouse, "Unable get OPC state.\n");
327                 return -EIO;
328         }
329
330         if (enable)
331                 nv = v | FSP_BIT_EN_OPC_TAG;
332         else
333                 nv = v & ~FSP_BIT_EN_OPC_TAG;
334
335         /* only write if necessary */
336         if (nv != v) {
337                 fsp_reg_write_enable(psmouse, true);
338                 res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
339                 fsp_reg_write_enable(psmouse, false);
340         }
341
342         if (res != 0) {
343                 psmouse_err(psmouse, "Unable to enable OPC tag.\n");
344                 res = -EIO;
345         }
346
347         return res;
348 }
349
350 static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable)
351 {
352         struct fsp_data *pad = psmouse->private;
353         int val;
354
355         if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
356                 return -EIO;
357
358         pad->vscroll = enable;
359
360         if (enable)
361                 val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
362         else
363                 val &= ~FSP_BIT_FIX_VSCR;
364
365         if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
366                 return -EIO;
367
368         return 0;
369 }
370
371 static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
372 {
373         struct fsp_data *pad = psmouse->private;
374         int val, v2;
375
376         if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
377                 return -EIO;
378
379         if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
380                 return -EIO;
381
382         pad->hscroll = enable;
383
384         if (enable) {
385                 val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
386                 v2 |= FSP_BIT_EN_MSID6;
387         } else {
388                 val &= ~FSP_BIT_FIX_HSCR;
389                 v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
390         }
391
392         if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
393                 return -EIO;
394
395         /* reconfigure horizontal scrolling packet output */
396         if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
397                 return -EIO;
398
399         return 0;
400 }
401
402 /*
403  * Write device specific initial parameters.
404  *
405  * ex: 0xab 0xcd - write oxcd into register 0xab
406  */
407 static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
408                                    const char *buf, size_t count)
409 {
410         unsigned long reg, val;
411         char *rest;
412         ssize_t retval;
413
414         reg = simple_strtoul(buf, &rest, 16);
415         if (rest == buf || *rest != ' ' || reg > 0xff)
416                 return -EINVAL;
417
418         if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
419                 return -EINVAL;
420
421         if (fsp_reg_write_enable(psmouse, true))
422                 return -EIO;
423
424         retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count;
425
426         fsp_reg_write_enable(psmouse, false);
427
428         return count;
429 }
430
431 PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
432
433 static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse,
434                                         void *data, char *buf)
435 {
436         struct fsp_data *pad = psmouse->private;
437
438         return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val);
439 }
440
441 /*
442  * Read a register from device.
443  *
444  * ex: 0xab -- read content from register 0xab
445  */
446 static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
447                                         const char *buf, size_t count)
448 {
449         struct fsp_data *pad = psmouse->private;
450         unsigned long reg;
451         int val;
452
453         if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
454                 return -EINVAL;
455
456         if (fsp_reg_read(psmouse, reg, &val))
457                 return -EIO;
458
459         pad->last_reg = reg;
460         pad->last_val = val;
461
462         return count;
463 }
464
465 PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
466                         fsp_attr_show_getreg, fsp_attr_set_getreg);
467
468 static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
469                                         void *data, char *buf)
470 {
471         int val = 0;
472
473         if (fsp_page_reg_read(psmouse, &val))
474                 return -EIO;
475
476         return sprintf(buf, "%02x\n", val);
477 }
478
479 static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
480                                         const char *buf, size_t count)
481 {
482         unsigned long val;
483
484         if (strict_strtoul(buf, 16, &val) || val > 0xff)
485                 return -EINVAL;
486
487         if (fsp_page_reg_write(psmouse, val))
488                 return -EIO;
489
490         return count;
491 }
492
493 PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
494                         fsp_attr_show_pagereg, fsp_attr_set_pagereg);
495
496 static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
497                                         void *data, char *buf)
498 {
499         struct fsp_data *pad = psmouse->private;
500
501         return sprintf(buf, "%d\n", pad->vscroll);
502 }
503
504 static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
505                                         const char *buf, size_t count)
506 {
507         unsigned long val;
508
509         if (strict_strtoul(buf, 10, &val) || val > 1)
510                 return -EINVAL;
511
512         fsp_onpad_vscr(psmouse, val);
513
514         return count;
515 }
516
517 PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
518                         fsp_attr_show_vscroll, fsp_attr_set_vscroll);
519
520 static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
521                                         void *data, char *buf)
522 {
523         struct fsp_data *pad = psmouse->private;
524
525         return sprintf(buf, "%d\n", pad->hscroll);
526 }
527
528 static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
529                                         const char *buf, size_t count)
530 {
531         unsigned long val;
532
533         if (strict_strtoul(buf, 10, &val) || val > 1)
534                 return -EINVAL;
535
536         fsp_onpad_hscr(psmouse, val);
537
538         return count;
539 }
540
541 PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
542                         fsp_attr_show_hscroll, fsp_attr_set_hscroll);
543
544 static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
545                                         void *data, char *buf)
546 {
547         struct fsp_data *pad = psmouse->private;
548
549         return sprintf(buf, "%c\n",
550                         pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
551 }
552
553 static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
554                                         const char *buf, size_t count)
555 {
556         struct fsp_data *pad = psmouse->private;
557         size_t i;
558
559         for (i = 0; i < count; i++) {
560                 switch (buf[i]) {
561                 case 'C':
562                         pad->flags |= FSPDRV_FLAG_EN_OPC;
563                         break;
564                 case 'c':
565                         pad->flags &= ~FSPDRV_FLAG_EN_OPC;
566                         break;
567                 default:
568                         return -EINVAL;
569                 }
570         }
571         return count;
572 }
573
574 PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
575                         fsp_attr_show_flags, fsp_attr_set_flags);
576
577 static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
578                                         void *data, char *buf)
579 {
580         return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
581 }
582
583 PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
584
585 static struct attribute *fsp_attributes[] = {
586         &psmouse_attr_setreg.dattr.attr,
587         &psmouse_attr_getreg.dattr.attr,
588         &psmouse_attr_page.dattr.attr,
589         &psmouse_attr_vscroll.dattr.attr,
590         &psmouse_attr_hscroll.dattr.attr,
591         &psmouse_attr_flags.dattr.attr,
592         &psmouse_attr_ver.dattr.attr,
593         NULL
594 };
595
596 static struct attribute_group fsp_attribute_group = {
597         .attrs = fsp_attributes,
598 };
599
600 #ifdef FSP_DEBUG
601 static void fsp_packet_debug(unsigned char packet[])
602 {
603         static unsigned int ps2_packet_cnt;
604         static unsigned int ps2_last_second;
605         unsigned int jiffies_msec;
606
607         ps2_packet_cnt++;
608         jiffies_msec = jiffies_to_msecs(jiffies);
609         psmouse_dbg(psmouse,
610                     "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
611                     jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
612
613         if (jiffies_msec - ps2_last_second > 1000) {
614                 psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
615                 ps2_packet_cnt = 0;
616                 ps2_last_second = jiffies_msec;
617         }
618 }
619 #else
620 static void fsp_packet_debug(unsigned char packet[])
621 {
622 }
623 #endif
624
625 static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
626 {
627         struct input_dev *dev = psmouse->dev;
628         struct fsp_data *ad = psmouse->private;
629         unsigned char *packet = psmouse->packet;
630         unsigned char button_status = 0, lscroll = 0, rscroll = 0;
631         int rel_x, rel_y;
632
633         if (psmouse->pktcnt < 4)
634                 return PSMOUSE_GOOD_DATA;
635
636         /*
637          * Full packet accumulated, process it
638          */
639
640         switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
641         case FSP_PKT_TYPE_ABS:
642                 psmouse_warn(psmouse,
643                              "Unexpected absolute mode packet, ignored.\n");
644                 break;
645
646         case FSP_PKT_TYPE_NORMAL_OPC:
647                 /* on-pad click, filter it if necessary */
648                 if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
649                         packet[0] &= ~BIT(0);
650                 /* fall through */
651
652         case FSP_PKT_TYPE_NORMAL:
653                 /* normal packet */
654                 /* special packet data translation from on-pad packets */
655                 if (packet[3] != 0) {
656                         if (packet[3] & BIT(0))
657                                 button_status |= 0x01;  /* wheel down */
658                         if (packet[3] & BIT(1))
659                                 button_status |= 0x0f;  /* wheel up */
660                         if (packet[3] & BIT(2))
661                                 button_status |= BIT(4);/* horizontal left */
662                         if (packet[3] & BIT(3))
663                                 button_status |= BIT(5);/* horizontal right */
664                         /* push back to packet queue */
665                         if (button_status != 0)
666                                 packet[3] = button_status;
667                         rscroll = (packet[3] >> 4) & 1;
668                         lscroll = (packet[3] >> 5) & 1;
669                 }
670                 /*
671                  * Processing wheel up/down and extra button events
672                  */
673                 input_report_rel(dev, REL_WHEEL,
674                                  (int)(packet[3] & 8) - (int)(packet[3] & 7));
675                 input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
676                 input_report_key(dev, BTN_BACK, lscroll);
677                 input_report_key(dev, BTN_FORWARD, rscroll);
678
679                 /*
680                  * Standard PS/2 Mouse
681                  */
682                 input_report_key(dev, BTN_LEFT, packet[0] & 1);
683                 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
684                 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
685
686                 rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
687                 rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
688
689                 input_report_rel(dev, REL_X, rel_x);
690                 input_report_rel(dev, REL_Y, rel_y);
691                 break;
692         }
693
694         input_sync(dev);
695
696         fsp_packet_debug(packet);
697
698         return PSMOUSE_FULL_PACKET;
699 }
700
701 static int fsp_activate_protocol(struct psmouse *psmouse)
702 {
703         struct fsp_data *pad = psmouse->private;
704         struct ps2dev *ps2dev = &psmouse->ps2dev;
705         unsigned char param[2];
706         int val;
707
708         /*
709          * Standard procedure to enter FSP Intellimouse mode
710          * (scrolling wheel, 4th and 5th buttons)
711          */
712         param[0] = 200;
713         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
714         param[0] = 200;
715         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
716         param[0] =  80;
717         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
718
719         ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
720         if (param[0] != 0x04) {
721                 psmouse_err(psmouse,
722                             "Unable to enable 4 bytes packet format.\n");
723                 return -EIO;
724         }
725
726         if (pad->ver < FSP_VER_STL3888_C0) {
727                 /* Preparing relative coordinates output for older hardware */
728                 if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
729                         psmouse_err(psmouse,
730                                     "Unable to read SYSCTL5 register.\n");
731                         return -EIO;
732                 }
733
734                 if (fsp_get_buttons(psmouse, &pad->buttons)) {
735                         psmouse_err(psmouse,
736                                     "Unable to retrieve number of buttons.\n");
737                         return -EIO;
738                 }
739
740                 val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
741                 /* Ensure we are not in absolute mode */
742                 val &= ~FSP_BIT_EN_PKT_G0;
743                 if (pad->buttons == 0x06) {
744                         /* Left/Middle/Right & Scroll Up/Down/Right/Left */
745                         val |= FSP_BIT_EN_MSID6;
746                 }
747
748                 if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
749                         psmouse_err(psmouse,
750                                     "Unable to set up required mode bits.\n");
751                         return -EIO;
752                 }
753
754                 /*
755                  * Enable OPC tags such that driver can tell the difference
756                  * between on-pad and real button click
757                  */
758                 if (fsp_opc_tag_enable(psmouse, true))
759                         psmouse_warn(psmouse,
760                                      "Failed to enable OPC tag mode.\n");
761                 /* enable on-pad click by default */
762                 pad->flags |= FSPDRV_FLAG_EN_OPC;
763
764                 /* Enable on-pad vertical and horizontal scrolling */
765                 fsp_onpad_vscr(psmouse, true);
766                 fsp_onpad_hscr(psmouse, true);
767         }
768
769         return 0;
770 }
771
772 static int fsp_set_input_params(struct psmouse *psmouse)
773 {
774         struct input_dev *dev = psmouse->dev;
775         struct fsp_data *pad = psmouse->private;
776
777         if (pad->ver < FSP_VER_STL3888_C0) {
778                 __set_bit(BTN_MIDDLE, dev->keybit);
779                 __set_bit(BTN_BACK, dev->keybit);
780                 __set_bit(BTN_FORWARD, dev->keybit);
781                 __set_bit(REL_WHEEL, dev->relbit);
782                 __set_bit(REL_HWHEEL, dev->relbit);
783         }
784
785         return 0;
786 }
787
788 int fsp_detect(struct psmouse *psmouse, bool set_properties)
789 {
790         int id;
791
792         if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
793                 return -EIO;
794
795         if (id != 0x01)
796                 return -ENODEV;
797
798         if (set_properties) {
799                 psmouse->vendor = "Sentelic";
800                 psmouse->name = "FingerSensingPad";
801         }
802
803         return 0;
804 }
805
806 static void fsp_reset(struct psmouse *psmouse)
807 {
808         fsp_opc_tag_enable(psmouse, false);
809         fsp_onpad_vscr(psmouse, false);
810         fsp_onpad_hscr(psmouse, false);
811 }
812
813 static void fsp_disconnect(struct psmouse *psmouse)
814 {
815         sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
816                            &fsp_attribute_group);
817
818         fsp_reset(psmouse);
819         kfree(psmouse->private);
820 }
821
822 static int fsp_reconnect(struct psmouse *psmouse)
823 {
824         int version;
825
826         if (fsp_detect(psmouse, 0))
827                 return -ENODEV;
828
829         if (fsp_get_version(psmouse, &version))
830                 return -ENODEV;
831
832         if (fsp_activate_protocol(psmouse))
833                 return -EIO;
834
835         return 0;
836 }
837
838 int fsp_init(struct psmouse *psmouse)
839 {
840         struct fsp_data *priv;
841         int ver, rev;
842         int error;
843
844         if (fsp_get_version(psmouse, &ver) ||
845             fsp_get_revision(psmouse, &rev)) {
846                 return -ENODEV;
847         }
848
849         psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
850                      ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
851
852         psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
853         if (!priv)
854                 return -ENOMEM;
855
856         priv->ver = ver;
857         priv->rev = rev;
858
859         psmouse->protocol_handler = fsp_process_byte;
860         psmouse->disconnect = fsp_disconnect;
861         psmouse->reconnect = fsp_reconnect;
862         psmouse->cleanup = fsp_reset;
863         psmouse->pktsize = 4;
864
865         error = fsp_activate_protocol(psmouse);
866         if (error)
867                 goto err_out;
868
869         /* Set up various supported input event bits */
870         error = fsp_set_input_params(psmouse);
871         if (error)
872                 goto err_out;
873
874         error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
875                                    &fsp_attribute_group);
876         if (error) {
877                 psmouse_err(psmouse,
878                             "Failed to create sysfs attributes (%d)", error);
879                 goto err_out;
880         }
881
882         return 0;
883
884  err_out:
885         kfree(psmouse->private);
886         psmouse->private = NULL;
887         return error;
888 }