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