From: Ben Gamari <bgamari.foss@gmail.com>
To: James <james@madingley.org>,
Ignacio Casal Quinteiro <nacho.resa@gmail.com>
Cc: linux-input@vger.kernel.org
Subject: Re: New Alps protocol in the wild?
Date: Wed, 15 Aug 2012 01:49:59 -0400 [thread overview]
Message-ID: <87ipckwvp4.fsf@gmail.com> (raw)
In-Reply-To: <20120814103553.GF23370@arianrhod.panaceas.james.local>
[-- Attachment #1: Type: text/plain, Size: 2312 bytes --]
After doing some fiddling around myself, I've put together a few tools
and I think I now have the beginnings of an understanding of the report
frame structure. I've attached some notes below. The data packets
appear to be 6 bytes long, consistent with earlier versions of the
protocol. The first and fifth bytes of the touchpad packet are still
quite mysterious. While they likely have something to do with
multitouch, they both fluctuate even with single touch events. Touchpad
packets can be distinguished from stick packets by examining the byte 5,
which is 0x3f (out of the range of the pressure field) in touchstick
packets.
I've also attached two tools I've developed. ps2-parse.py annotates PS/2
traces produced by the VM with common command names (simply pipe a trace
in to stdin, out comes the annotate trace on stdout). Alps.py is a first
attempt at communicating with the hardware. It currently has the ability
to put playback a trace (say, the attached serio-init.log) and start
dumping frames to stdout. It also has an incomplete version of the
initialization sequence (enter_absolute_mode).
Hopefully I'll find some more time in the next few days to figure out
the last few bits (primarily how multitouch events work). I wouldn't be
sad if someone finished the task for me, however.
Cheers,
- Ben
Touchpad Packet format:
byte 0: ??? starts with 0x9f, 0x8f, changes
0x10: ??
0x20: ??
0x8f: Always set
Only 0x10 and 0x20 are set with single-touch events. 0x40 seems to be set with multitouch events
byte 1: X position? (- is left, + is right)
byte 2: Y position? (- is up, + is down)
byte 3: button state:
0x1: left touchpad
0x2: right touchpad
0x4: middle touchpad?
0x8: Always set?
0x10: left touchstick
0x20: right touchstick
0x40: middle touchstick
0x80: ???
byte 4: ???
byte 5: Pressure (0x00 - 0x3e)
0x3f: Reporting stick?
Touchstick Packet format:
byte 0: 0x10: Y Sign
0x20: X Sign
0x4f: Always set
byte 1: X pressure (0 - 0x7f)
byte 2: Y pressure (0 - 0x7f)
byte 3: always 0x48
byte 4: Z pressure (0 - 0x7c)
byte 5: always 0x3f
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: alps.py --]
[-- Type: text/x-python, Size: 3064 bytes --]
#!/usr/bin/python3.2
import sys
from glob import glob
from time import sleep
import logging
logging.basicConfig(level=logging.DEBUG)
def find_serio_device():
for f in glob('/sys/bus/serio/devices/serio*'):
a = open('%s/description'%f).read()
if 'i8042 AUX' in a:
return f
#dev = find_serio_device()
#logging.info("Found device %s" % dev)
#open('%s/drvctl'%dev, 'w').write('serio_raw')
#sleep(1)
serio_dev = sys.argv[1]
#serio_dev = glob('/dev/serio*')[0]
f = open(serio_dev, 'wb+')
def playback(cmds):
for dir,data in cmds:
if dir == 'S':
logging.debug('Sent %02x' % data)
f.write(bytes([data]))
elif dir == 'R':
a = f.read(1)
logging.debug('Recieved %02x' % a[0])
if data != a[0]:
logging.warn('reply mismatch: expected %02x, saw %02x' % (data, a[0]))
else:
raise RuntimeError("uh oh")
def recv_ack():
a = b''
logging.debug('Waiting for ACK')
while len(a) == 0:
a = f.read(1)
print(len(a))
if a != b'\xfa':
raise RuntimeError("oops: %s" % str(a))
def reset():
f.write(b'\xff')
recv_ack()
a = f.read(2)
return a
def get_device_id():
f.write(b'\xf2')
recv_ack()
a = f.read(1)
return a
def set_resolution(arg):
f.write(b'\xe8')
recv_ack()
f.write(arg)
recv_ack()
def set_sample_rate(arg):
f.write(b'\xf3')
recv_ack()
f.write(arg)
recv_ack()
def set_1_1_scaling():
f.write(b'\xe6')
recv_ack()
def status_rq():
f.write(b'\xe9')
recv_ack()
a = f.read(3)
return a
def enable_data_reporting():
f.write(b'\xf4')
recv_ack()
def disable_data_reporting():
f.write(b'\xf5')
recv_ack()
def enter_absolute_mode():
reset()
reset()
get_device_id()
set_resolution(b'\x00')
set_1_1_scaling()
set_1_1_scaling()
set_1_1_scaling()
status_rq()
set_resolution(b'\x03')
set_sample_rate(b'\xc8')
set_sample_rate(b'\x64')
set_sample_rate(b'\x50')
get_device_id()
set_sample_rate(b'\xc8')
set_sample_rate(b'\xc8')
set_sample_rate(b'\x50')
set_resolution(b'\x03')
enable_data_reporting()
def format_bytes(bytes):
return map(lambda b: '%02x' % b, bytes)
cmds = []
for l in open('serio-init.log'):
(dir,data) = (l[0], int(l[1:4], 16))
cmds.append((dir,data))
disable_data_reporting()
reset()
reset()
playback(cmds)
#enter_absolute_mode()
try:
while True:
a = f.read(6)
print(' '.join(format_bytes(a)))
except KeyboardInterrupt:
pass
#open('%s/drvctl'%dev, 'w').write('psmouse')
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: ps2-parse.py --]
[-- Type: text/x-python, Size: 2226 bytes --]
#!/usr/bin/python
import sys
def get_line():
l = sys.stdin.readline()
return (l[0], int(l[1:], 16))
def get_ack():
(dir,data) = get_line()
if dir!='R' and data!=0xfa:
print('! Unknown reply: %02x'%data)
while True:
notes = ''
(dir,data) = get_line()
if dir == 'S':
get_ack()
if data == 0xff:
notes = 'reset'
elif data == 0xfe:
notes = 'resend'
elif data == 0xf6:
notes = 'set defaults'
elif data == 0xf5:
notes = 'disable reporting'
elif data == 0xf4:
notes = 'enable reporting'
elif data == 0xf3:
dir,data = get_line()
notes = 'set_sample_rate: %02x' % data
get_ack()
elif data == 0xf2:
_,d = get_line()
notes = 'get device id: %02x' % d
elif data == 0xf0:
notes = 'set remote mode'
elif data == 0xee:
notes = 'set wrap mode'
elif data == 0xec:
notes = 'reset wrap mode'
elif data == 0xeb:
notes = 'read data'
elif data == 0xea:
notes = 'set stream mode'
elif data == 0xe9:
_,d1 = get_line()
_,d2 = get_line()
_,d3 = get_line()
notes = 'status request: %02x resolution=%02x rate=%02x' % (d1, d2, d3)
elif data == 0xe8:
_,d = get_line()
notes = 'set resolution: %02x' % d
get_ack()
elif data == 0xe7:
notes = 'set scaling 2:1'
elif data == 0xe6:
notes = 'set scaling 1:1'
else:
notes = 'unknown command'
print('%s %02x %s' % (dir, data, notes))
[-- Attachment #4: serio-init.log --]
[-- Type: application/octet-stream, Size: 2830 bytes --]
S ff
R fa
R aa
R 00
S ff
R fa
R aa
R 00
S f2
R fa
R 00
S e8
R fa
S 00
R fa
S e6
R fa
S e6
R fa
S e6
R fa
S e9
R fa
R 00
R 00
R 64
S e8
R fa
S 03
R fa
S f3
R fa
S c8
R fa
S f3
R fa
S 64
R fa
S f3
R fa
S 50
R fa
S f2
R fa
R 00
S f3
R fa
S c8
R fa
S f3
R fa
S c8
R fa
S f3
R fa
S 50
R fa
S f2
R fa
R 00
S f3
R fa
S 64
R fa
S e8
R fa
S 03
R fa
S f4
R fa
S f5
R fa
S ff
R fa
R aa
R 00
S e7
R fa
S e7
R fa
S e7
R fa
S e9
R fa
R 73
R 03
R 0a
S ea
R fa
S ec
R fa
S ec
R fa
S ec
R fa
S e9
R fa
R 88
R 08
R 1d
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S e9
R fa
R c2
R c8
R 80
S f3
R fa
S 64
R fa
S f6
R fa
S ea
R fa
S e7
R fa
S e7
R fa
S e7
R fa
S e9
R fa
R 42
R 02
R 3c
S e6
R fa
S e6
R fa
S e6
R fa
S f3
R fa
S c8
R fa
S f3
R fa
S 14
R fa
S ea
R fa
S ec
R fa
S ec
R fa
S ec
R fa
S e9
R fa
R 88
R 08
R 1d
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S f3
R fa
S 64
R fa
S e7
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 14
R fa
S e9
R fa
R c2
R c4
R 00
S f0
R fa
S e7
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 02
R fa
S f3
R fa
S c8
R fa
S e9
R fa
R c2
R d9
R 00
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S e8
R fa
S 00
R fa
S f0
R fa
S f0
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S e9
R fa
R c2
R c8
R 82
S f3
R fa
S 64
R fa
S e7
R fa
S ea
R fa
S f3
R fa
S 64
R fa
S f4
R fa
S f5
R fa
S ff
R fa
R aa
S f5
S ff
R fa
R fa
R aa
R 00
S e7
R fa
S e7
R fa
S e7
R fa
S e9
R fa
R 73
R 03
R 0a
S ea
R fa
S ec
R fa
S ec
R fa
S ec
R fa
S e9
R fa
R 88
R 08
R 1d
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S e9
R fa
R c2
R c8
R 80
S f3
R fa
S 64
R fa
S f6
R fa
S ea
R fa
S e7
R fa
S e7
R fa
S e7
R fa
S e9
R fa
R 42
R 02
R 3c
S e6
R fa
S e6
R fa
S e6
R fa
S f3
R fa
S c8
R fa
S f3
R fa
S 14
R fa
S ea
R fa
S ec
R fa
S ec
R fa
S ec
R fa
S e9
R fa
R 88
R 08
R 1d
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S f3
R fa
S 64
R fa
S e7
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 14
R fa
S e9
R fa
R c2
R c4
R 00
S f0
R fa
S e7
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 02
R fa
S f3
R fa
S c8
R fa
S e9
R fa
R c2
R d9
R 00
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S e8
R fa
S 00
R fa
S f0
R fa
S f0
R fa
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 64
R fa
S e9
R fa
R c2
R c8
R 82
S f3
R fa
S 64
R fa
S e7
R fa
S ea
R fa
S f3
R fa
S 64
R fa
S f4
R fa
S f5
R fa
S f2
R fa
R 00
S ea
R fa
S ec
R fa
S ec
R fa
S ec
R fa
S e9
R fa
R 88
R 08
R 1d
S ec
R fa
S e8
R fa
S 01
R fa
S e7
R fa
S e8
R fa
S 01
R fa
S f3
R fa
S 28
R fa
S e9
R fa
R c2
R c5
R 69
S f3
R fa
S 3c
R fa
S f3
R fa
S c8
R fa
S ea
R fa
S f4
R fa
next prev parent reply other threads:[~2012-08-15 5:50 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-27 16:18 New Alps protocol in the wild? Ben Gamari
2012-07-27 16:52 ` Seth Forshee
2012-07-27 17:17 ` Ben Gamari
2012-07-27 19:15 ` dturvene
2012-07-30 8:43 ` Jiri Kosina
2012-07-30 16:19 ` Ben Gamari
2012-07-31 5:19 ` Ben Gamari
2012-07-31 6:01 ` Dmitry Torokhov
2012-07-31 20:50 ` Ben Gamari
2012-07-31 19:17 ` Ben Gamari
2012-08-14 10:35 ` James
2012-08-14 16:01 ` Ben Gamari
2012-08-14 16:15 ` Seth Forshee
[not found] ` <20120814160519.GC12473@artemis.panaceas.org>
2012-08-15 5:49 ` Ben Gamari [this message]
2012-08-16 5:04 ` Ben Gamari
2012-08-17 16:46 ` dturvene
2012-08-17 17:04 ` Ben Gamari
2012-09-08 12:51 ` dturvene
2012-09-10 20:35 ` Ben Gamari
2012-09-15 20:49 ` dturvene
[not found] ` <CAPtp-N_PbGABwC7PtNtEe7bitc=yg1oV2M6cK6Wb1PkVq6wa9A@mail.gmail.com>
2012-09-30 17:33 ` dturvene
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ipckwvp4.fsf@gmail.com \
--to=bgamari.foss@gmail.com \
--cc=james@madingley.org \
--cc=linux-input@vger.kernel.org \
--cc=nacho.resa@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).