Commit fc69f4a6af49ee69475dc4217924d9edf77760e0

Authored by Tai-hwa Liang
Committed by Dmitry Torokhov
1 parent 3b72094409

Input: add new driver for Sentelic Finger Sensing Pad

This is the driver for Sentelic Finger Sensing Pad which can be found
on MSI WIND Netbook.

Signed-off-by: Tai-hwa Liang <avatar@sentelic.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

Showing 9 changed files with 1488 additions and 4 deletions Side-by-side Diff

Documentation/input/sentelic.txt
  1 +Copyright (C) 2002-2008 Sentelic Corporation.
  2 +Last update: Oct-31-2008
  3 +
  4 +==============================================================================
  5 +* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
  6 +==============================================================================
  7 +A) MSID 4: Scrolling wheel mode plus Forward page(4th button) and Backward
  8 + page (5th button)
  9 +@1. Set sample rate to 200;
  10 +@2. Set sample rate to 200;
  11 +@3. Set sample rate to 80;
  12 +@4. Issuing the "Get device ID" command (0xF2) and waits for the response;
  13 +@5. FSP will respond 0x04.
  14 +
  15 +Packet 1
  16 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  17 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  18 + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|W|W|W|W|
  19 + |---------------| |---------------| |---------------| |---------------|
  20 +
  21 +Byte 1: Bit7 => Y overflow
  22 + Bit6 => X overflow
  23 + Bit5 => Y sign bit
  24 + Bit4 => X sign bit
  25 + Bit3 => 1
  26 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
  27 + Bit1 => Right Button, 1 is pressed, 0 is not pressed.
  28 + Bit0 => Left Button, 1 is pressed, 0 is not pressed.
  29 +Byte 2: X Movement(9-bit 2's complement integers)
  30 +Byte 3: Y Movement(9-bit 2's complement integers)
  31 +Byte 4: Bit3~Bit0 => the scrolling wheel's movement since the last data report.
  32 + valid values, -8 ~ +7
  33 + Bit4 => 1 = 4th mouse button is pressed, Forward one page.
  34 + 0 = 4th mouse button is not pressed.
  35 + Bit5 => 1 = 5th mouse button is pressed, Backward one page.
  36 + 0 = 5th mouse button is not pressed.
  37 +
  38 +B) MSID 6: Horizontal and Vertical scrolling.
  39 +@ Set bit 1 in register 0x40 to 1
  40 +
  41 +# FSP replaces scrolling wheel's movement as 4 bits to show horizontal and
  42 + vertical scrolling.
  43 +
  44 +Packet 1
  45 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  46 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  47 + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|l|r|u|d|
  48 + |---------------| |---------------| |---------------| |---------------|
  49 +
  50 +Byte 1: Bit7 => Y overflow
  51 + Bit6 => X overflow
  52 + Bit5 => Y sign bit
  53 + Bit4 => X sign bit
  54 + Bit3 => 1
  55 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
  56 + Bit1 => Right Button, 1 is pressed, 0 is not pressed.
  57 + Bit0 => Left Button, 1 is pressed, 0 is not pressed.
  58 +Byte 2: X Movement(9-bit 2's complement integers)
  59 +Byte 3: Y Movement(9-bit 2's complement integers)
  60 +Byte 4: Bit0 => the Vertical scrolling movement downward.
  61 + Bit1 => the Vertical scrolling movement upward.
  62 + Bit2 => the Vertical scrolling movement rightward.
  63 + Bit3 => the Vertical scrolling movement leftward.
  64 + Bit4 => 1 = 4th mouse button is pressed, Forward one page.
  65 + 0 = 4th mouse button is not pressed.
  66 + Bit5 => 1 = 5th mouse button is pressed, Backward one page.
  67 + 0 = 5th mouse button is not pressed.
  68 +
  69 +C) MSID 7:
  70 +# FSP uses 2 packets(8 Bytes) data to represent Absolute Position
  71 + so we have PACKET NUMBER to identify packets.
  72 + If PACKET NUMBER is 0, the packet is Packet 1.
  73 + If PACKET NUMBER is 1, the packet is Packet 2.
  74 + Please count this number in program.
  75 +
  76 +# MSID6 special packet will be enable at the same time when enable MSID 7.
  77 +
  78 +==============================================================================
  79 +* Absolute position for STL3886-G0.
  80 +==============================================================================
  81 +@ Set bit 2 or 3 in register 0x40 to 1
  82 +@ Set bit 6 in register 0x40 to 1
  83 +
  84 +Packet 1 (ABSOLUTE POSITION)
  85 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  86 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  87 + 1 |0|1|V|1|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|d|u|X|X|Y|Y|
  88 + |---------------| |---------------| |---------------| |---------------|
  89 +
  90 +Byte 1: Bit7~Bit6 => 00, Normal data packet
  91 + => 01, Absolute coordination packet
  92 + => 10, Notify packet
  93 + Bit5 => valid bit
  94 + Bit4 => 1
  95 + Bit3 => 1
  96 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
  97 + Bit1 => Right Button, 1 is pressed, 0 is not pressed.
  98 + Bit0 => Left Button, 1 is pressed, 0 is not pressed.
  99 +Byte 2: X coordinate (xpos[9:2])
  100 +Byte 3: Y coordinate (ypos[9:2])
  101 +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
  102 + Bit3~Bit2 => X coordinate (ypos[1:0])
  103 + Bit4 => scroll up
  104 + Bit5 => scroll down
  105 + Bit6 => scroll left
  106 + Bit7 => scroll right
  107 +
  108 +Notify Packet for G0
  109 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  110 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  111 + 1 |1|0|0|1|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |M|M|M|M|M|M|M|M| 4 |0|0|0|0|0|0|0|0|
  112 + |---------------| |---------------| |---------------| |---------------|
  113 +
  114 +Byte 1: Bit7~Bit6 => 00, Normal data packet
  115 + => 01, Absolute coordination packet
  116 + => 10, Notify packet
  117 + Bit5 => 0
  118 + Bit4 => 1
  119 + Bit3 => 1
  120 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
  121 + Bit1 => Right Button, 1 is pressed, 0 is not pressed.
  122 + Bit0 => Left Button, 1 is pressed, 0 is not pressed.
  123 +Byte 2: Message Type => 0x5A (Enable/Disable status packet)
  124 + Mode Type => 0xA5 (Normal/Icon mode status)
  125 +Byte 3: Message Type => 0x00 (Disabled)
  126 + => 0x01 (Enabled)
  127 + Mode Type => 0x00 (Normal)
  128 + => 0x01 (Icon)
  129 +Byte 4: Bit7~Bit0 => Don't Care
  130 +
  131 +==============================================================================
  132 +* Absolute position for STL3888-A0.
  133 +==============================================================================
  134 +Packet 1 (ABSOLUTE POSITION)
  135 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  136 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  137 + 1 |0|1|V|A|1|L|0|1| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y|
  138 + |---------------| |---------------| |---------------| |---------------|
  139 +
  140 +Byte 1: Bit7~Bit6 => 00, Normal data packet
  141 + => 01, Absolute coordination packet
  142 + => 10, Notify packet
  143 + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
  144 + When both fingers are up, the last two reports have zero valid
  145 + bit.
  146 + Bit4 => arc
  147 + Bit3 => 1
  148 + Bit2 => Left Button, 1 is pressed, 0 is released.
  149 + Bit1 => 0
  150 + Bit0 => 1
  151 +Byte 2: X coordinate (xpos[9:2])
  152 +Byte 3: Y coordinate (ypos[9:2])
  153 +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
  154 + Bit3~Bit2 => X coordinate (ypos[1:0])
  155 + Bit5~Bit4 => y1_g
  156 + Bit7~Bit6 => x1_g
  157 +
  158 +Packet 2 (ABSOLUTE POSITION)
  159 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  160 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  161 + 1 |0|1|V|A|1|R|1|0| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y|
  162 + |---------------| |---------------| |---------------| |---------------|
  163 +
  164 +Byte 1: Bit7~Bit6 => 00, Normal data packet
  165 + => 01, Absolute coordinates packet
  166 + => 10, Notify packet
  167 + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
  168 + When both fingers are up, the last two reports have zero valid
  169 + bit.
  170 + Bit4 => arc
  171 + Bit3 => 1
  172 + Bit2 => Right Button, 1 is pressed, 0 is released.
  173 + Bit1 => 1
  174 + Bit0 => 0
  175 +Byte 2: X coordinate (xpos[9:2])
  176 +Byte 3: Y coordinate (ypos[9:2])
  177 +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
  178 + Bit3~Bit2 => X coordinate (ypos[1:0])
  179 + Bit5~Bit4 => y2_g
  180 + Bit7~Bit6 => x2_g
  181 +
  182 +Notify Packet for STL3888-A0
  183 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  184 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  185 + 1 |1|0|1|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|d|u|0|0|0|0|
  186 + |---------------| |---------------| |---------------| |---------------|
  187 +
  188 +Byte 1: Bit7~Bit6 => 00, Normal data packet
  189 + => 01, Absolute coordination packet
  190 + => 10, Notify packet
  191 + Bit5 => 1
  192 + Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
  193 + 0: left button is generated by the on-pad command
  194 + 1: left button is generated by the external button
  195 + Bit3 => 1
  196 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
  197 + Bit1 => Right Button, 1 is pressed, 0 is not pressed.
  198 + Bit0 => Left Button, 1 is pressed, 0 is not pressed.
  199 +Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode)
  200 +Byte 3: Bit7~Bit6 => Don't care
  201 + Bit5~Bit4 => Number of fingers
  202 + Bit3~Bit1 => Reserved
  203 + Bit0 => 1: enter gesture mode; 0: leaving gesture mode
  204 +Byte 4: Bit7 => scroll right button
  205 + Bit6 => scroll left button
  206 + Bit5 => scroll down button
  207 + Bit4 => scroll up button
  208 + * Note that if gesture and additional button (Bit4~Bit7)
  209 + happen at the same time, the button information will not
  210 + be sent.
  211 + Bit3~Bit0 => Reserved
  212 +
  213 +Sample sequence of Multi-finger, Multi-coordinate mode:
  214 +
  215 + notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
  216 + abs pkt 2, ..., notify packet(valid bit == 0)
  217 +
  218 +==============================================================================
  219 +* FSP Enable/Disable packet
  220 +==============================================================================
  221 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  222 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
  223 + 1 |Y|X|0|0|1|M|R|L| 2 |0|1|0|1|1|0|1|E| 3 | | | | | | | | | 4 | | | | | | | | |
  224 + |---------------| |---------------| |---------------| |---------------|
  225 +
  226 +FSP will send out enable/disable packet when FSP receive PS/2 enable/disable
  227 +command. Host will receive the packet which Middle, Right, Left button will
  228 +be set. The packet only use byte 0 and byte 1 as a pattern of original packet.
  229 +Ignore the other bytes of the packet.
  230 +
  231 +Byte 1: Bit7 => 0, Y overflow
  232 + Bit6 => 0, X overflow
  233 + Bit5 => 0, Y sign bit
  234 + Bit4 => 0, X sign bit
  235 + Bit3 => 1
  236 + Bit2 => 1, Middle Button
  237 + Bit1 => 1, Right Button
  238 + Bit0 => 1, Left Button
  239 +Byte 2: Bit7~1 => (0101101b)
  240 + Bit0 => 1 = Enable
  241 + 0 = Disable
  242 +Byte 3: Don't care
  243 +Byte 4: Don't care (MOUSE ID 3, 4)
  244 +Byte 5~8: Don't care (Absolute packet)
  245 +
  246 +==============================================================================
  247 +* PS/2 Command Set
  248 +==============================================================================
  249 +
  250 +FSP supports basic PS/2 commanding set and modes, refer to following URL for
  251 +details about PS/2 commands:
  252 +
  253 +http://www.computer-engineering.org/index.php?title=PS/2_Mouse_Interface
  254 +
  255 +==============================================================================
  256 +* Programming Sequence for Determining Packet Parsing Flow
  257 +==============================================================================
  258 +1. Identify FSP by reading device ID(0x00) and version(0x01) register
  259 +
  260 +2. Determine number of buttons by reading status2 (0x0b) register
  261 +
  262 + buttons = reg[0x0b] & 0x30
  263 +
  264 + if buttons == 0x30 or buttons == 0x20:
  265 + # two/four buttons
  266 + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
  267 + section A for packet parsing detail(ignore byte 4, bit ~ 7)
  268 + elif buttons == 0x10:
  269 + # 6 buttons
  270 + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
  271 + section B for packet parsing detail
  272 + elif buttons == 0x00:
  273 + # 6 buttons
  274 + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
  275 + section A for packet parsing detail
  276 +
  277 +==============================================================================
  278 +* Programming Sequence for Register Reading/Writing
  279 +==============================================================================
  280 +
  281 +Register inversion requirement:
  282 +
  283 + Following values needed to be inverted(the '~' operator in C) before being
  284 +sent to FSP:
  285 +
  286 + 0xe9, 0xee, 0xf2 and 0xff.
  287 +
  288 +Register swapping requirement:
  289 +
  290 + Following values needed to have their higher 4 bits and lower 4 bits being
  291 +swapped before being sent to FSP:
  292 +
  293 + 10, 20, 40, 60, 80, 100 and 200.
  294 +
  295 +Register reading sequence:
  296 +
  297 + 1. send 0xf3 PS/2 command to FSP;
  298 +
  299 + 2. send 0x66 PS/2 command to FSP;
  300 +
  301 + 3. send 0x88 PS/2 command to FSP;
  302 +
  303 + 4. send 0xf3 PS/2 command to FSP;
  304 +
  305 + 5. if the register address being to read is not required to be
  306 + inverted(refer to the 'Register inversion requirement' section),
  307 + goto step 6
  308 +
  309 + 5a. send 0x68 PS/2 command to FSP;
  310 +
  311 + 5b. send the inverted register address to FSP and goto step 8;
  312 +
  313 + 6. if the register address being to read is not required to be
  314 + swapped(refer to the 'Register swapping requirement' section),
  315 + goto step 7
  316 +
  317 + 6a. send 0xcc PS/2 command to FSP;
  318 +
  319 + 6b. send the swapped register address to FSP and goto step 8;
  320 +
  321 + 7. send 0x66 PS/2 command to FSP;
  322 +
  323 + 7a. send the original register address to FSP and goto step 8;
  324 +
  325 + 8. send 0xe9(status request) PS/2 command to FSP;
  326 +
  327 + 9. the response read from FSP should be the requested register value.
  328 +
  329 +Register writing sequence:
  330 +
  331 + 1. send 0xf3 PS/2 command to FSP;
  332 +
  333 + 2. if the register address being to write is not required to be
  334 + inverted(refer to the 'Register inversion requirement' section),
  335 + goto step 3
  336 +
  337 + 2a. send 0x74 PS/2 command to FSP;
  338 +
  339 + 2b. send the inverted register address to FSP and goto step 5;
  340 +
  341 + 3. if the register address being to write is not required to be
  342 + swapped(refer to the 'Register swapping requirement' section),
  343 + goto step 4
  344 +
  345 + 3a. send 0x77 PS/2 command to FSP;
  346 +
  347 + 3b. send the swapped register address to FSP and goto step 5;
  348 +
  349 + 4. send 0x55 PS/2 command to FSP;
  350 +
  351 + 4a. send the register address to FSP and goto step 5;
  352 +
  353 + 5. send 0xf3 PS/2 command to FSP;
  354 +
  355 + 6. if the register value being to write is not required to be
  356 + inverted(refer to the 'Register inversion requirement' section),
  357 + goto step 7
  358 +
  359 + 6a. send 0x47 PS/2 command to FSP;
  360 +
  361 + 6b. send the inverted register value to FSP and goto step 9;
  362 +
  363 + 7. if the register value being to write is not required to be
  364 + swapped(refer to the 'Register swapping requirement' section),
  365 + goto step 8
  366 +
  367 + 7a. send 0x44 PS/2 command to FSP;
  368 +
  369 + 7b. send the swapped register value to FSP and goto step 9;
  370 +
  371 + 8. send 0x33 PS/2 command to FSP;
  372 +
  373 + 8a. send the register value to FSP;
  374 +
  375 + 9. the register writing sequence is completed.
  376 +
  377 +==============================================================================
  378 +* Register Listing
  379 +==============================================================================
  380 +
  381 +offset width default r/w name
  382 +0x00 bit7~bit0 0x01 RO device ID
  383 +
  384 +0x01 bit7~bit0 0xc0 RW version ID
  385 +
  386 +0x02 bit7~bit0 0x01 RO vendor ID
  387 +
  388 +0x03 bit7~bit0 0x01 RO product ID
  389 +
  390 +0x04 bit3~bit0 0x01 RW revision ID
  391 +
  392 +0x0b RO test mode status 1
  393 + bit3 1 RO 0: rotate 180 degree, 1: no rotation
  394 +
  395 + bit5~bit4 RO number of buttons
  396 + 11 => 2, lbtn/rbtn
  397 + 10 => 4, lbtn/rbtn/scru/scrd
  398 + 01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr
  399 + 00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn
  400 +
  401 +0x0f RW register file page control
  402 + bit0 0 RW 1 to enable page 1 register files
  403 +
  404 +0x10 RW system control 1
  405 + bit0 1 RW Reserved, must be 1
  406 + bit1 0 RW Reserved, must be 0
  407 + bit4 1 RW Reserved, must be 0
  408 + bit5 0 RW register clock gating enable
  409 + 0: read only, 1: read/write enable
  410 + (Note that following registers does not require clock gating being
  411 + enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
  412 + 40 41 42 43.)
  413 +
  414 +0x31 RW on-pad command detection
  415 + bit7 0 RW on-pad command left button down tag
  416 + enable
  417 + 0: disable, 1: enable
  418 +
  419 +0x34 RW on-pad command control 5
  420 + bit4~bit0 0x05 RW XLO in 0s/4/1, so 03h = 0010.1b = 2.5
  421 + (Note that position unit is in 0.5 scanline)
  422 +
  423 + bit7 0 RW on-pad tap zone enable
  424 + 0: disable, 1: enable
  425 +
  426 +0x35 RW on-pad command control 6
  427 + bit4~bit0 0x1d RW XHI in 0s/4/1, so 19h = 1100.1b = 12.5
  428 + (Note that position unit is in 0.5 scanline)
  429 +
  430 +0x36 RW on-pad command control 7
  431 + bit4~bit0 0x04 RW YLO in 0s/4/1, so 03h = 0010.1b = 2.5
  432 + (Note that position unit is in 0.5 scanline)
  433 +
  434 +0x37 RW on-pad command control 8
  435 + bit4~bit0 0x13 RW YHI in 0s/4/1, so 11h = 1000.1b = 8.5
  436 + (Note that position unit is in 0.5 scanline)
  437 +
  438 +0x40 RW system control 5
  439 + bit1 0 RW FSP Intellimouse mode enable
  440 + 0: disable, 1: enable
  441 +
  442 + bit2 0 RW movement + abs. coordinate mode enable
  443 + 0: disable, 1: enable
  444 + (Note that this function has the functionality of bit 1 even when
  445 + bit 1 is not set. However, the format is different from that of bit 1.
  446 + In addition, when bit 1 and bit 2 are set at the same time, bit 2 will
  447 + override bit 1.)
  448 +
  449 + bit3 0 RW abs. coordinate only mode enable
  450 + 0: disable, 1: enable
  451 + (Note that this function has the functionality of bit 1 even when
  452 + bit 1 is not set. However, the format is different from that of bit 1.
  453 + In addition, when bit 1, bit 2 and bit 3 are set at the same time,
  454 + bit 3 will override bit 1 and 2.)
  455 +
  456 + bit5 0 RW auto switch enable
  457 + 0: disable, 1: enable
  458 +
  459 + bit6 0 RW G0 abs. + notify packet format enable
  460 + 0: disable, 1: enable
  461 + (Note that the absolute/relative coordinate output still depends on
  462 + bit 2 and 3. That is, if any of those bit is 1, host will receive
  463 + absolute coordinates; otherwise, host only receives packets with
  464 + relative coordinate.)
  465 +
  466 +0x43 RW on-pad control
  467 + bit0 0 RW on-pad control enable
  468 + 0: disable, 1: enable
  469 + (Note that if this bit is cleared, bit 3/5 will be ineffective)
  470 +
  471 + bit3 0 RW on-pad fix vertical scrolling enable
  472 + 0: disable, 1: enable
  473 +
  474 + bit5 0 RW on-pad fix horizontal scrolling enable
  475 + 0: disable, 1: enable
drivers/input/mouse/Kconfig
... ... @@ -107,6 +107,14 @@
107 107 entries. For further information,
108 108 see <file:Documentation/input/elantech.txt>.
109 109  
  110 +config MOUSE_PS2_SENTELIC
  111 + bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
  112 + depends on MOUSE_PS2
  113 + help
  114 + Say Y here if you have a laptop (such as MSI WIND Netbook)
  115 + with Sentelic Finger Sensing Pad touchpad.
  116 +
  117 + If unsure, say N.
110 118  
111 119 config MOUSE_PS2_TOUCHKIT
112 120 bool "eGalax TouchKit PS/2 protocol extension"
drivers/input/mouse/Makefile
... ... @@ -27,6 +27,7 @@
27 27 psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
28 28 psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
29 29 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
  30 +psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
30 31 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
31 32 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
drivers/input/mouse/psmouse-base.c
... ... @@ -30,6 +30,7 @@
30 30 #include "trackpoint.h"
31 31 #include "touchkit_ps2.h"
32 32 #include "elantech.h"
  33 +#include "sentelic.h"
33 34  
34 35 #define DRIVER_DESC "PS/2 mouse driver"
35 36  
36 37  
... ... @@ -666,7 +667,21 @@
666 667 max_proto = PSMOUSE_IMEX;
667 668 }
668 669  
  670 +/*
  671 + * Try Finger Sensing Pad
  672 + */
669 673 if (max_proto > PSMOUSE_IMEX) {
  674 + if (fsp_detect(psmouse, set_properties) == 0) {
  675 + if (!set_properties || fsp_init(psmouse) == 0)
  676 + return PSMOUSE_FSP;
  677 +/*
  678 + * Init failed, try basic relative protocols
  679 + */
  680 + max_proto = PSMOUSE_IMEX;
  681 + }
  682 + }
  683 +
  684 + if (max_proto > PSMOUSE_IMEX) {
670 685 if (genius_detect(psmouse, set_properties) == 0)
671 686 return PSMOUSE_GENPS;
672 687  
... ... @@ -813,7 +828,16 @@
813 828 .detect = elantech_detect,
814 829 .init = elantech_init,
815 830 },
816   - #endif
  831 +#endif
  832 +#ifdef CONFIG_MOUSE_PS2_SENTELIC
  833 + {
  834 + .type = PSMOUSE_FSP,
  835 + .name = "FSPPS/2",
  836 + .alias = "fsp",
  837 + .detect = fsp_detect,
  838 + .init = fsp_init,
  839 + },
  840 +#endif
817 841 {
818 842 .type = PSMOUSE_CORTRON,
819 843 .name = "CortronPS/2",
drivers/input/mouse/psmouse.h
... ... @@ -91,6 +91,7 @@
91 91 PSMOUSE_CORTRON,
92 92 PSMOUSE_HGPK,
93 93 PSMOUSE_ELANTECH,
  94 + PSMOUSE_FSP,
94 95 PSMOUSE_AUTO /* This one should always be last */
95 96 };
96 97  
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-2009 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 +
  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 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
  94 + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
  95 + mutex_lock(&ps2dev->cmd_mutex);
  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 + mutex_unlock(&ps2dev->cmd_mutex);
  130 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
  131 + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
  132 + dev_dbg(&ps2dev->serio->dev, "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 + mutex_lock(&ps2dev->cmd_mutex);
  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 + return -1;
  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 + mutex_unlock(&ps2dev->cmd_mutex);
  183 + dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
  184 + reg_addr, reg_val, rc);
  185 + return rc;
  186 +}
  187 +
  188 +/* Enable register clock gating for writing certain registers */
  189 +static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable)
  190 +{
  191 + int v, nv;
  192 +
  193 + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
  194 + return -1;
  195 +
  196 + if (enable)
  197 + nv = v | FSP_BIT_EN_REG_CLK;
  198 + else
  199 + nv = v & ~FSP_BIT_EN_REG_CLK;
  200 +
  201 + /* only write if necessary */
  202 + if (nv != v)
  203 + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
  204 + return -1;
  205 +
  206 + return 0;
  207 +}
  208 +
  209 +static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
  210 +{
  211 + struct ps2dev *ps2dev = &psmouse->ps2dev;
  212 + unsigned char param[3];
  213 + int rc = -1;
  214 +
  215 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
  216 + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
  217 + mutex_lock(&ps2dev->cmd_mutex);
  218 +
  219 + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
  220 + goto out;
  221 +
  222 + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
  223 + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
  224 +
  225 + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
  226 + goto out;
  227 +
  228 + ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2);
  229 + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
  230 +
  231 + /* get the returned result */
  232 + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
  233 + goto out;
  234 +
  235 + *reg_val = param[2];
  236 + rc = 0;
  237 +
  238 + out:
  239 + mutex_unlock(&ps2dev->cmd_mutex);
  240 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
  241 + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
  242 + dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
  243 + *reg_val, rc);
  244 + return rc;
  245 +}
  246 +
  247 +static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
  248 +{
  249 + struct ps2dev *ps2dev = &psmouse->ps2dev;
  250 + unsigned char v;
  251 + int rc = -1;
  252 +
  253 + mutex_lock(&ps2dev->cmd_mutex);
  254 +
  255 + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
  256 + goto out;
  257 +
  258 + ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2);
  259 + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
  260 +
  261 + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
  262 + return -1;
  263 +
  264 + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
  265 + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
  266 + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
  267 + /* swapping is required */
  268 + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
  269 + } else {
  270 + /* swapping isn't necessary */
  271 + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
  272 + }
  273 +
  274 + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
  275 + rc = 0;
  276 +
  277 + out:
  278 + mutex_unlock(&ps2dev->cmd_mutex);
  279 + dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
  280 + reg_val, rc);
  281 + return rc;
  282 +}
  283 +
  284 +static int fsp_get_version(struct psmouse *psmouse, int *version)
  285 +{
  286 + if (fsp_reg_read(psmouse, FSP_REG_VERSION, version))
  287 + return -EIO;
  288 +
  289 + return 0;
  290 +}
  291 +
  292 +static int fsp_get_revision(struct psmouse *psmouse, int *rev)
  293 +{
  294 + if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev))
  295 + return -EIO;
  296 +
  297 + return 0;
  298 +}
  299 +
  300 +static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
  301 +{
  302 + static const int buttons[] = {
  303 + 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
  304 + 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */
  305 + 0x04, /* Left/Middle/Right & Scroll Up/Down */
  306 + 0x02, /* Left/Middle/Right */
  307 + };
  308 + int val;
  309 +
  310 + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1)
  311 + return -EIO;
  312 +
  313 + *btn = buttons[(val & 0x30) >> 4];
  314 + return 0;
  315 +}
  316 +
  317 +/* Enable on-pad command tag output */
  318 +static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
  319 +{
  320 + int v, nv;
  321 + int res = 0;
  322 +
  323 + if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
  324 + dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
  325 + return -EIO;
  326 + }
  327 +
  328 + if (enable)
  329 + nv = v | FSP_BIT_EN_OPC_TAG;
  330 + else
  331 + nv = v & ~FSP_BIT_EN_OPC_TAG;
  332 +
  333 + /* only write if necessary */
  334 + if (nv != v) {
  335 + fsp_reg_write_enable(psmouse, true);
  336 + res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
  337 + fsp_reg_write_enable(psmouse, false);
  338 + }
  339 +
  340 + if (res != 0) {
  341 + dev_err(&psmouse->ps2dev.serio->dev,
  342 + "Unable to enable OPC tag.\n");
  343 + res = -EIO;
  344 + }
  345 +
  346 + return res;
  347 +}
  348 +
  349 +static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable)
  350 +{
  351 + struct fsp_data *pad = psmouse->private;
  352 + int val;
  353 +
  354 + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
  355 + return -EIO;
  356 +
  357 + pad->vscroll = enable;
  358 +
  359 + if (enable)
  360 + val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
  361 + else
  362 + val &= ~FSP_BIT_FIX_VSCR;
  363 +
  364 + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
  365 + return -EIO;
  366 +
  367 + return 0;
  368 +}
  369 +
  370 +static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
  371 +{
  372 + struct fsp_data *pad = psmouse->private;
  373 + int val, v2;
  374 +
  375 + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
  376 + return -EIO;
  377 +
  378 + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
  379 + return -EIO;
  380 +
  381 + pad->hscroll = enable;
  382 +
  383 + if (enable) {
  384 + val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
  385 + v2 |= FSP_BIT_EN_MSID6;
  386 + } else {
  387 + val &= ~FSP_BIT_FIX_HSCR;
  388 + v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
  389 + }
  390 +
  391 + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
  392 + return -EIO;
  393 +
  394 + /* reconfigure horizontal scrolling packet output */
  395 + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
  396 + return -EIO;
  397 +
  398 + return 0;
  399 +}
  400 +
  401 +/*
  402 + * Write device specific initial parameters.
  403 + *
  404 + * ex: 0xab 0xcd - write oxcd into register 0xab
  405 + */
  406 +static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
  407 + const char *buf, size_t count)
  408 +{
  409 + unsigned long reg, val;
  410 + char *rest;
  411 + ssize_t retval;
  412 +
  413 + reg = simple_strtoul(buf, &rest, 16);
  414 + if (rest == buf || *rest != ' ' || reg > 0xff)
  415 + return -EINVAL;
  416 +
  417 + if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
  418 + return -EINVAL;
  419 +
  420 + if (fsp_reg_write_enable(psmouse, true))
  421 + return -EIO;
  422 +
  423 + retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count;
  424 +
  425 + fsp_reg_write_enable(psmouse, false);
  426 +
  427 + return count;
  428 +}
  429 +
  430 +PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
  431 +
  432 +static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse,
  433 + void *data, char *buf)
  434 +{
  435 + struct fsp_data *pad = psmouse->private;
  436 +
  437 + return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val);
  438 +}
  439 +
  440 +/*
  441 + * Read a register from device.
  442 + *
  443 + * ex: 0xab -- read content from register 0xab
  444 + */
  445 +static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
  446 + const char *buf, size_t count)
  447 +{
  448 + struct fsp_data *pad = psmouse->private;
  449 + unsigned long reg;
  450 + int val;
  451 +
  452 + if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
  453 + return -EINVAL;
  454 +
  455 + if (fsp_reg_read(psmouse, reg, &val))
  456 + return -EIO;
  457 +
  458 + pad->last_reg = reg;
  459 + pad->last_val = val;
  460 +
  461 + return count;
  462 +}
  463 +
  464 +PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
  465 + fsp_attr_show_getreg, fsp_attr_set_getreg);
  466 +
  467 +static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
  468 + void *data, char *buf)
  469 +{
  470 + int val = 0;
  471 +
  472 + if (fsp_page_reg_read(psmouse, &val))
  473 + return -EIO;
  474 +
  475 + return sprintf(buf, "%02x\n", val);
  476 +}
  477 +
  478 +static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
  479 + const char *buf, size_t count)
  480 +{
  481 + unsigned long val;
  482 +
  483 + if (strict_strtoul(buf, 16, &val) || val > 0xff)
  484 + return -EINVAL;
  485 +
  486 + if (fsp_page_reg_write(psmouse, val))
  487 + return -EIO;
  488 +
  489 + return count;
  490 +}
  491 +
  492 +PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
  493 + fsp_attr_show_pagereg, fsp_attr_set_pagereg);
  494 +
  495 +static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
  496 + void *data, char *buf)
  497 +{
  498 + struct fsp_data *pad = psmouse->private;
  499 +
  500 + return sprintf(buf, "%d\n", pad->vscroll);
  501 +}
  502 +
  503 +static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
  504 + const char *buf, size_t count)
  505 +{
  506 + unsigned long val;
  507 +
  508 + if (strict_strtoul(buf, 10, &val) || val > 1)
  509 + return -EINVAL;
  510 +
  511 + fsp_onpad_vscr(psmouse, val);
  512 +
  513 + return count;
  514 +}
  515 +
  516 +PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
  517 + fsp_attr_show_vscroll, fsp_attr_set_vscroll);
  518 +
  519 +static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
  520 + void *data, char *buf)
  521 +{
  522 + struct fsp_data *pad = psmouse->private;
  523 +
  524 + return sprintf(buf, "%d\n", pad->hscroll);
  525 +}
  526 +
  527 +static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
  528 + const char *buf, size_t count)
  529 +{
  530 + unsigned long val;
  531 +
  532 + if (strict_strtoul(buf, 10, &val) || val > 1)
  533 + return -EINVAL;
  534 +
  535 + fsp_onpad_hscr(psmouse, val);
  536 +
  537 + return count;
  538 +}
  539 +
  540 +PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
  541 + fsp_attr_show_hscroll, fsp_attr_set_hscroll);
  542 +
  543 +static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
  544 + void *data, char *buf)
  545 +{
  546 + struct fsp_data *pad = psmouse->private;
  547 +
  548 + return sprintf(buf, "%c\n",
  549 + pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
  550 +}
  551 +
  552 +static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
  553 + const char *buf, size_t count)
  554 +{
  555 + struct fsp_data *pad = psmouse->private;
  556 + size_t i;
  557 +
  558 + for (i = 0; i < count; i++) {
  559 + switch (buf[i]) {
  560 + case 'C':
  561 + pad->flags |= FSPDRV_FLAG_EN_OPC;
  562 + break;
  563 + case 'c':
  564 + pad->flags &= ~FSPDRV_FLAG_EN_OPC;
  565 + break;
  566 + default:
  567 + return -EINVAL;
  568 + }
  569 + }
  570 + return count;
  571 +}
  572 +
  573 +PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
  574 + fsp_attr_show_flags, fsp_attr_set_flags);
  575 +
  576 +static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
  577 + void *data, char *buf)
  578 +{
  579 + return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
  580 +}
  581 +
  582 +PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
  583 +
  584 +static struct attribute *fsp_attributes[] = {
  585 + &psmouse_attr_setreg.dattr.attr,
  586 + &psmouse_attr_getreg.dattr.attr,
  587 + &psmouse_attr_page.dattr.attr,
  588 + &psmouse_attr_vscroll.dattr.attr,
  589 + &psmouse_attr_hscroll.dattr.attr,
  590 + &psmouse_attr_flags.dattr.attr,
  591 + &psmouse_attr_ver.dattr.attr,
  592 + NULL
  593 +};
  594 +
  595 +static struct attribute_group fsp_attribute_group = {
  596 + .attrs = fsp_attributes,
  597 +};
  598 +
  599 +#ifdef FSP_DEBUG
  600 +static void fsp_packet_debug(unsigned char packet[])
  601 +{
  602 + static unsigned int ps2_packet_cnt;
  603 + static unsigned int ps2_last_second;
  604 + unsigned int jiffies_msec;
  605 +
  606 + ps2_packet_cnt++;
  607 + jiffies_msec = jiffies_to_msecs(jiffies);
  608 + printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
  609 + jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
  610 +
  611 + if (jiffies_msec - ps2_last_second > 1000) {
  612 + printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
  613 + ps2_packet_cnt = 0;
  614 + ps2_last_second = jiffies_msec;
  615 + }
  616 +}
  617 +#else
  618 +static void fsp_packet_debug(unsigned char packet[])
  619 +{
  620 +}
  621 +#endif
  622 +
  623 +static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
  624 +{
  625 + struct input_dev *dev = psmouse->dev;
  626 + struct fsp_data *ad = psmouse->private;
  627 + unsigned char *packet = psmouse->packet;
  628 + unsigned char button_status = 0, lscroll = 0, rscroll = 0;
  629 + int rel_x, rel_y;
  630 +
  631 + if (psmouse->pktcnt < 4)
  632 + return PSMOUSE_GOOD_DATA;
  633 +
  634 + /*
  635 + * Full packet accumulated, process it
  636 + */
  637 +
  638 + switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
  639 + case FSP_PKT_TYPE_ABS:
  640 + dev_warn(&psmouse->ps2dev.serio->dev,
  641 + "Unexpected absolute mode packet, ignored.\n");
  642 + break;
  643 +
  644 + case FSP_PKT_TYPE_NORMAL_OPC:
  645 + /* on-pad click, filter it if necessary */
  646 + if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
  647 + packet[0] &= ~BIT(0);
  648 + /* fall through */
  649 +
  650 + case FSP_PKT_TYPE_NORMAL:
  651 + /* normal packet */
  652 + /* special packet data translation from on-pad packets */
  653 + if (packet[3] != 0) {
  654 + if (packet[3] & BIT(0))
  655 + button_status |= 0x01; /* wheel down */
  656 + if (packet[3] & BIT(1))
  657 + button_status |= 0x0f; /* wheel up */
  658 + if (packet[3] & BIT(2))
  659 + button_status |= BIT(5);/* horizontal left */
  660 + if (packet[3] & BIT(3))
  661 + button_status |= BIT(4);/* horizontal right */
  662 + /* push back to packet queue */
  663 + if (button_status != 0)
  664 + packet[3] = button_status;
  665 + rscroll = (packet[3] >> 4) & 1;
  666 + lscroll = (packet[3] >> 5) & 1;
  667 + }
  668 + /*
  669 + * Processing wheel up/down and extra button events
  670 + */
  671 + input_report_rel(dev, REL_WHEEL,
  672 + (int)(packet[3] & 8) - (int)(packet[3] & 7));
  673 + input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
  674 + input_report_key(dev, BTN_BACK, lscroll);
  675 + input_report_key(dev, BTN_FORWARD, rscroll);
  676 +
  677 + /*
  678 + * Standard PS/2 Mouse
  679 + */
  680 + input_report_key(dev, BTN_LEFT, packet[0] & 1);
  681 + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
  682 + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
  683 +
  684 + rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
  685 + rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
  686 +
  687 + input_report_rel(dev, REL_X, rel_x);
  688 + input_report_rel(dev, REL_Y, rel_y);
  689 + break;
  690 + }
  691 +
  692 + input_sync(dev);
  693 +
  694 + fsp_packet_debug(packet);
  695 +
  696 + return PSMOUSE_FULL_PACKET;
  697 +}
  698 +
  699 +static int fsp_activate_protocol(struct psmouse *psmouse)
  700 +{
  701 + struct fsp_data *pad = psmouse->private;
  702 + struct ps2dev *ps2dev = &psmouse->ps2dev;
  703 + unsigned char param[2];
  704 + int val;
  705 +
  706 + /*
  707 + * Standard procedure to enter FSP Intellimouse mode
  708 + * (scrolling wheel, 4th and 5th buttons)
  709 + */
  710 + param[0] = 200;
  711 + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
  712 + param[0] = 200;
  713 + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
  714 + param[0] = 80;
  715 + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
  716 +
  717 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
  718 + if (param[0] != 0x04) {
  719 + dev_err(&psmouse->ps2dev.serio->dev,
  720 + "Unable to enable 4 bytes packet format.\n");
  721 + return -EIO;
  722 + }
  723 +
  724 + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
  725 + dev_err(&psmouse->ps2dev.serio->dev,
  726 + "Unable to read SYSCTL5 register.\n");
  727 + return -EIO;
  728 + }
  729 +
  730 + val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
  731 + /* Ensure we are not in absolute mode */
  732 + val &= ~FSP_BIT_EN_PKT_G0;
  733 + if (pad->buttons == 0x06) {
  734 + /* Left/Middle/Right & Scroll Up/Down/Right/Left */
  735 + val |= FSP_BIT_EN_MSID6;
  736 + }
  737 +
  738 + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
  739 + dev_err(&psmouse->ps2dev.serio->dev,
  740 + "Unable to set up required mode bits.\n");
  741 + return -EIO;
  742 + }
  743 +
  744 + /*
  745 + * Enable OPC tags such that driver can tell the difference between
  746 + * on-pad and real button click
  747 + */
  748 + if (fsp_opc_tag_enable(psmouse, true))
  749 + dev_warn(&psmouse->ps2dev.serio->dev,
  750 + "Failed to enable OPC tag mode.\n");
  751 +
  752 + /* Enable on-pad vertical and horizontal scrolling */
  753 + fsp_onpad_vscr(psmouse, true);
  754 + fsp_onpad_hscr(psmouse, true);
  755 +
  756 + return 0;
  757 +}
  758 +
  759 +int fsp_detect(struct psmouse *psmouse, int set_properties)
  760 +{
  761 + int id;
  762 +
  763 + if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
  764 + return -EIO;
  765 +
  766 + if (id != 0x01)
  767 + return -ENODEV;
  768 +
  769 + if (set_properties) {
  770 + psmouse->vendor = "Sentelic";
  771 + psmouse->name = "FingerSensingPad";
  772 + }
  773 +
  774 + return 0;
  775 +}
  776 +
  777 +static void fsp_reset(struct psmouse *psmouse)
  778 +{
  779 + fsp_opc_tag_enable(psmouse, false);
  780 + fsp_onpad_vscr(psmouse, false);
  781 + fsp_onpad_hscr(psmouse, false);
  782 +}
  783 +
  784 +static void fsp_disconnect(struct psmouse *psmouse)
  785 +{
  786 + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
  787 + &fsp_attribute_group);
  788 +
  789 + fsp_reset(psmouse);
  790 + kfree(psmouse->private);
  791 +}
  792 +
  793 +static int fsp_reconnect(struct psmouse *psmouse)
  794 +{
  795 + int version;
  796 +
  797 + if (fsp_detect(psmouse, 0))
  798 + return -ENODEV;
  799 +
  800 + if (fsp_get_version(psmouse, &version))
  801 + return -ENODEV;
  802 +
  803 + if (fsp_activate_protocol(psmouse))
  804 + return -EIO;
  805 +
  806 + return 0;
  807 +}
  808 +
  809 +int fsp_init(struct psmouse *psmouse)
  810 +{
  811 + struct fsp_data *priv;
  812 + int ver, rev, buttons;
  813 + int error;
  814 +
  815 + if (fsp_get_version(psmouse, &ver) ||
  816 + fsp_get_revision(psmouse, &rev) ||
  817 + fsp_get_buttons(psmouse, &buttons)) {
  818 + return -ENODEV;
  819 + }
  820 +
  821 + printk(KERN_INFO
  822 + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
  823 + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
  824 +
  825 + psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
  826 + if (!priv)
  827 + return -ENOMEM;
  828 +
  829 + priv->ver = ver;
  830 + priv->rev = rev;
  831 + priv->buttons = buttons;
  832 +
  833 + /* enable on-pad click by default */
  834 + priv->flags |= FSPDRV_FLAG_EN_OPC;
  835 +
  836 + /* Set up various supported input event bits */
  837 + __set_bit(BTN_BACK, psmouse->dev->keybit);
  838 + __set_bit(BTN_FORWARD, psmouse->dev->keybit);
  839 + __set_bit(REL_WHEEL, psmouse->dev->relbit);
  840 + __set_bit(REL_HWHEEL, psmouse->dev->relbit);
  841 +
  842 + psmouse->protocol_handler = fsp_process_byte;
  843 + psmouse->disconnect = fsp_disconnect;
  844 + psmouse->reconnect = fsp_reconnect;
  845 + psmouse->cleanup = fsp_reset;
  846 + psmouse->pktsize = 4;
  847 +
  848 + /* set default packet output based on number of buttons we found */
  849 + error = fsp_activate_protocol(psmouse);
  850 + if (error)
  851 + goto err_out;
  852 +
  853 + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
  854 + &fsp_attribute_group);
  855 + if (error) {
  856 + dev_err(&psmouse->ps2dev.serio->dev,
  857 + "Failed to create sysfs attributes (%d)", error);
  858 + goto err_out;
  859 + }
  860 +
  861 + return 0;
  862 +
  863 + err_out:
  864 + kfree(psmouse->private);
  865 + psmouse->private = NULL;
  866 + return error;
  867 +}
drivers/input/mouse/sentelic.h
  1 +/*-
  2 + * Finger Sensing Pad PS/2 mouse driver.
  3 + *
  4 + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
  5 + * Copyright (C) 2005-2009 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 +#ifndef __SENTELIC_H
  23 +#define __SENTELIC_H
  24 +
  25 +/* Finger-sensing Pad information registers */
  26 +#define FSP_REG_DEVICE_ID 0x00
  27 +#define FSP_REG_VERSION 0x01
  28 +#define FSP_REG_REVISION 0x04
  29 +#define FSP_REG_TMOD_STATUS1 0x0B
  30 +#define FSP_BIT_NO_ROTATION BIT(3)
  31 +#define FSP_REG_PAGE_CTRL 0x0F
  32 +
  33 +/* Finger-sensing Pad control registers */
  34 +#define FSP_REG_SYSCTL1 0x10
  35 +#define FSP_BIT_EN_REG_CLK BIT(5)
  36 +#define FSP_REG_OPC_QDOWN 0x31
  37 +#define FSP_BIT_EN_OPC_TAG BIT(7)
  38 +#define FSP_REG_OPTZ_XLO 0x34
  39 +#define FSP_REG_OPTZ_XHI 0x35
  40 +#define FSP_REG_OPTZ_YLO 0x36
  41 +#define FSP_REG_OPTZ_YHI 0x37
  42 +#define FSP_REG_SYSCTL5 0x40
  43 +#define FSP_BIT_90_DEGREE BIT(0)
  44 +#define FSP_BIT_EN_MSID6 BIT(1)
  45 +#define FSP_BIT_EN_MSID7 BIT(2)
  46 +#define FSP_BIT_EN_MSID8 BIT(3)
  47 +#define FSP_BIT_EN_AUTO_MSID8 BIT(5)
  48 +#define FSP_BIT_EN_PKT_G0 BIT(6)
  49 +
  50 +#define FSP_REG_ONPAD_CTL 0x43
  51 +#define FSP_BIT_ONPAD_ENABLE BIT(0)
  52 +#define FSP_BIT_ONPAD_FBBB BIT(1)
  53 +#define FSP_BIT_FIX_VSCR BIT(3)
  54 +#define FSP_BIT_FIX_HSCR BIT(5)
  55 +#define FSP_BIT_DRAG_LOCK BIT(6)
  56 +
  57 +/* Finger-sensing Pad packet formating related definitions */
  58 +
  59 +/* absolute packet type */
  60 +#define FSP_PKT_TYPE_NORMAL (0x00)
  61 +#define FSP_PKT_TYPE_ABS (0x01)
  62 +#define FSP_PKT_TYPE_NOTIFY (0x02)
  63 +#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
  64 +#define FSP_PKT_TYPE_SHIFT (6)
  65 +
  66 +#ifdef __KERNEL__
  67 +
  68 +struct fsp_data {
  69 + unsigned char ver; /* hardware version */
  70 + unsigned char rev; /* hardware revison */
  71 + unsigned char buttons; /* Number of buttons */
  72 + unsigned int flags;
  73 +#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */
  74 +
  75 + bool vscroll; /* Vertical scroll zone enabled */
  76 + bool hscroll; /* Horizontal scroll zone enabled */
  77 +
  78 + unsigned char last_reg; /* Last register we requested read from */
  79 + unsigned char last_val;
  80 +};
  81 +
  82 +#ifdef CONFIG_MOUSE_PS2_SENTELIC
  83 +extern int fsp_detect(struct psmouse *psmouse, int set_properties);
  84 +extern int fsp_init(struct psmouse *psmouse);
  85 +#else
  86 +inline int fsp_detect(struct psmouse *psmouse, int set_properties)
  87 +{
  88 + return -ENOSYS;
  89 +}
  90 +inline int fsp_init(struct psmouse *psmouse)
  91 +{
  92 + return -ENOSYS;
  93 +}
  94 +#endif
  95 +
  96 +#endif /* __KERNEL__ */
  97 +
  98 +#endif /* !__SENTELIC_H */
drivers/input/serio/libps2.c
... ... @@ -161,7 +161,7 @@
161 161 * ps2_command() can only be called from a process context
162 162 */
163 163  
164   -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
  164 +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
165 165 {
166 166 int timeout;
167 167 int send = (command >> 12) & 0xf;
... ... @@ -179,8 +179,6 @@
179 179 return -1;
180 180 }
181 181  
182   - mutex_lock(&ps2dev->cmd_mutex);
183   -
184 182 serio_pause_rx(ps2dev->serio);
185 183 ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
186 184 ps2dev->cmdcnt = receive;
187 185  
... ... @@ -231,7 +229,18 @@
231 229 ps2dev->flags = 0;
232 230 serio_continue_rx(ps2dev->serio);
233 231  
  232 + return rc;
  233 +}
  234 +EXPORT_SYMBOL(__ps2_command);
  235 +
  236 +int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
  237 +{
  238 + int rc;
  239 +
  240 + mutex_lock(&ps2dev->cmd_mutex);
  241 + rc = __ps2_command(ps2dev, param, command);
234 242 mutex_unlock(&ps2dev->cmd_mutex);
  243 +
235 244 return rc;
236 245 }
237 246 EXPORT_SYMBOL(ps2_command);
include/linux/libps2.h
... ... @@ -44,6 +44,7 @@
44 44 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
45 45 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
46 46 void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
  47 +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
47 48 int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
48 49 int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
49 50 int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);