New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-detect how keyboard is attached (USB or not) #2736

Open
jpouellet opened this Issue Apr 2, 2017 · 22 comments

Comments

Projects
None yet
6 participants
@jpouellet
Contributor

jpouellet commented Apr 2, 2017

How the keyboard attaches to the system (over some spi/i2c (via the EC), or through USB) is a very useful property to know when considering to buy a laptop for Qubes.

This is especially true if we intend to move towards sys-usb by default. (I remember some discussion somewhere stating intent to remove "experimental" label in the installer option and enable it by default, but can't seem to find it right now.)

See also #2329.

I'm opening an issue rather than just submitting a PR because I don't know how to reliably determine this information. xinput? /proc/bus/input/devices? lsusb? something else?

/cc @tasket

edit: issue was originally just because this would be nice to have in the HCL, but we would need to reliably autodetect this in the installer as well if we want to enable sys-usb by default (so we could know whether or not to enable the input proxy). Issue title updated accordingly.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

A first attempt:

[user@dom0 ~]$ cat /tmp/x
awk '
  function clr() {
    kbd=0
    usb=0
    n=""
  }
  BEGIN {
    clr()
  }
  /^$/ {
    if (kbd)
      print (usb ? "usb" : "non-usb") " keyboard found: " n
    clr()
  }
  /^H: Handlers=.*kbd/ {
    kbd=1
  }
  /^S: Sysfs=.*\/usb[0-9]+\// {
    usb=1
  }
  /N: Name=/{
    sub(/[^"]*"/, "")
    sub(/"$/, "")
    n=$0
  }
' < /proc/bus/input/devices

Does not produce reliable enough results:

[user@dom0 ~]$ sh /tmp/x
non-usb keyboard found: Sleep Button
non-usb keyboard found: Power Button
non-usb keyboard found: AT Translated Set 2 keyboard
non-usb keyboard found: Video Bus
non-usb keyboard found: PC Speaker
non-usb keyboard found: ThinkPad Extra Buttons
[user@dom0 ~]$ qvm-run -p sys-usb sh < /tmp/x
non-usb keyboard found: PC Speaker
usb keyboard found: Apple, Inc Apple Keyboard
usb keyboard found: Apple, Inc Apple Keyboard

There are non-usb "keyboards" present, and one could similarly imagine a laptop having yes-usb "keyboards" as well.

Contributor

jpouellet commented Apr 2, 2017

A first attempt:

[user@dom0 ~]$ cat /tmp/x
awk '
  function clr() {
    kbd=0
    usb=0
    n=""
  }
  BEGIN {
    clr()
  }
  /^$/ {
    if (kbd)
      print (usb ? "usb" : "non-usb") " keyboard found: " n
    clr()
  }
  /^H: Handlers=.*kbd/ {
    kbd=1
  }
  /^S: Sysfs=.*\/usb[0-9]+\// {
    usb=1
  }
  /N: Name=/{
    sub(/[^"]*"/, "")
    sub(/"$/, "")
    n=$0
  }
' < /proc/bus/input/devices

Does not produce reliable enough results:

[user@dom0 ~]$ sh /tmp/x
non-usb keyboard found: Sleep Button
non-usb keyboard found: Power Button
non-usb keyboard found: AT Translated Set 2 keyboard
non-usb keyboard found: Video Bus
non-usb keyboard found: PC Speaker
non-usb keyboard found: ThinkPad Extra Buttons
[user@dom0 ~]$ qvm-run -p sys-usb sh < /tmp/x
non-usb keyboard found: PC Speaker
usb keyboard found: Apple, Inc Apple Keyboard
usb keyboard found: Apple, Inc Apple Keyboard

There are non-usb "keyboards" present, and one could similarly imagine a laptop having yes-usb "keyboards" as well.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Presence of non-keyboard buttons (extra media keys, random switches, etc.) make just checking for existence of usb or non-usb "keyboard" give false positives/negatives.

At least for autodetection in the installer we might monitor all /dev/input/eventX while the user types something, then find the corresponding device that's actually being used to type on and see what driver it's using? Not sure if this is suitable for qubes-hcl-report as we may not want to require any input for it to complete (for example, I've run it on a remote server once). It would be nice if there were a way to determine the last time a device gave input, but looking through the linux docs the closest thing seems to be MSC_TIMESTAMP which talks about "reset" (apparently not related to EV_KEY). Maybe some higher layer tracks this?

There must be a better way. My knowledge of the linux input stack is not as strong as it could be.

Contributor

jpouellet commented Apr 2, 2017

Presence of non-keyboard buttons (extra media keys, random switches, etc.) make just checking for existence of usb or non-usb "keyboard" give false positives/negatives.

At least for autodetection in the installer we might monitor all /dev/input/eventX while the user types something, then find the corresponding device that's actually being used to type on and see what driver it's using? Not sure if this is suitable for qubes-hcl-report as we may not want to require any input for it to complete (for example, I've run it on a remote server once). It would be nice if there were a way to determine the last time a device gave input, but looking through the linux docs the closest thing seems to be MSC_TIMESTAMP which talks about "reset" (apparently not related to EV_KEY). Maybe some higher layer tracks this?

There must be a better way. My knowledge of the linux input stack is not as strong as it could be.

@jpouellet jpouellet changed the title from HCL: report how keyboard is attached to Auto-detect how keyboard is attached (USB or not) Apr 2, 2017

@jpouellet jpouellet referenced this issue in QubesOS/qubes-app-linux-input-proxy Apr 2, 2017

Merged

Move security warning to qubes-doc #4

@unman

This comment has been minimized.

Show comment
Hide comment
@unman

unman Apr 2, 2017

Member
Member

unman commented Apr 2, 2017

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Tried that, doesn't work as hoped. See above.

I see you're replying from email, and I've edited the comments a bit so you may be missing context I've added later. I have a bad habit of editing perhaps a bit too often... sorry about that.

Contributor

jpouellet commented Apr 2, 2017

Tried that, doesn't work as hoped. See above.

I see you're replying from email, and I've edited the comments a bit so you may be missing context I've added later. I have a bad habit of editing perhaps a bit too often... sorry about that.

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

I believe having both Phys= contain /serio and Handlers= contain kdb could reliably detect a PS/2 keyboard. But that's only a 5min assessment. Actually, you could probably do this just by looking at the names in /dev/input/by-path, where -serio- and -kbd are both present.

Also, search seems to indicate i8042 is some near-universal controller for PS/2 ports? But I don't know if we'd want to specify that.

I'd also want to know if functioning-but-empty PS/2 ports were available.

tasket commented Apr 2, 2017

I believe having both Phys= contain /serio and Handlers= contain kdb could reliably detect a PS/2 keyboard. But that's only a 5min assessment. Actually, you could probably do this just by looking at the names in /dev/input/by-path, where -serio- and -kbd are both present.

Also, search seems to indicate i8042 is some near-universal controller for PS/2 ports? But I don't know if we'd want to specify that.

I'd also want to know if functioning-but-empty PS/2 ports were available.

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

In bash...

for file in /dev/input/by-path/*-serio-*-kbd ; do
    if [[ -c $file ]]; then
        ps2present=true
    fi
done

tasket commented Apr 2, 2017

In bash...

for file in /dev/input/by-path/*-serio-*-kbd ; do
    if [[ -c $file ]]; then
        ps2present=true
    fi
done
@Yethal

This comment has been minimized.

Show comment
Hide comment
@Yethal

Yethal Apr 2, 2017

@tasket I have a PS/2 keyboard if you want test results from real hardware

Yethal commented Apr 2, 2017

@tasket I have a PS/2 keyboard if you want test results from real hardware

@unman

This comment has been minimized.

Show comment
Hide comment
@unman

unman Apr 2, 2017

Member

@jpouellet Keyboards will always have EV=120013 in /proc/bus/input/devices, so you can combine that with the usb test for clear result. This is much cleaner than Phys or Handlers tests.

Member

unman commented Apr 2, 2017

@jpouellet Keyboards will always have EV=120013 in /proc/bus/input/devices, so you can combine that with the usb test for clear result. This is much cleaner than Phys or Handlers tests.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

@unman Interesting. That does work reliably on my machines, but it seems it would be valid for keyboards to also appear with some superset of that bitmask as well?

Contributor

jpouellet commented Apr 2, 2017

@unman Interesting. That does work reliably on my machines, but it seems it would be valid for keyboards to also appear with some superset of that bitmask as well?

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Maybe possible to have valid keyboards without EV_LED bit set as well?

Contributor

jpouellet commented Apr 2, 2017

Maybe possible to have valid keyboards without EV_LED bit set as well?

@marmarek

This comment has been minimized.

Show comment
Hide comment
@marmarek

marmarek Apr 2, 2017

Member

AFAIR this is very similar to what udev check when decide on adding ID_INPUT_KEYBOARD=1 additionally it check for actual keys presence.

Member

marmarek commented Apr 2, 2017

AFAIR this is very similar to what udev check when decide on adding ID_INPUT_KEYBOARD=1 additionally it check for actual keys presence.

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

@Yethal You could try the above code, with and without the keyboard attached. Actually, here is a shorter version that does the job:

if [ -n "$( find /dev/input/by-path -name '*-serio-*-kbd' )" ]; then echo "PS/2 Detected"; fi

There's a developer wiki with PS/2 information. It indicates that i8042 is the controller used on PC compatibles (and they list a different controller for ARM):
http://wiki.osdev.org/PS/2

tasket commented Apr 2, 2017

@Yethal You could try the above code, with and without the keyboard attached. Actually, here is a shorter version that does the job:

if [ -n "$( find /dev/input/by-path -name '*-serio-*-kbd' )" ]; then echo "PS/2 Detected"; fi

There's a developer wiki with PS/2 information. It indicates that i8042 is the controller used on PC compatibles (and they list a different controller for ARM):
http://wiki.osdev.org/PS/2

@Yethal

This comment has been minimized.

Show comment
Hide comment
@Yethal

Yethal Apr 2, 2017

@tasket above code echoes "PS/2 detected" regardless of whether the keyboard is actually connected to the PC or not.

Yethal commented Apr 2, 2017

@tasket above code echoes "PS/2 detected" regardless of whether the keyboard is actually connected to the PC or not.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Here's a shot using udev:

#!/bin/sh
udevadm info -e | awk '
  BEGIN {
    found_usb=0
    found_nonusb=0
    kbd=0
    usb=0
  }
  /^$/ {
    if (kbd) {
      if (usb)
        found_usb++
      else
        found_nonusb++
    }
    kbd=0
    usb=0
  }
  /^E: ID_INPUT_KEYBOARD=1$/ { kbd=1 }
  /^E: ID_USB/ { usb=1 }
  END {
    if (found_usb && !found_nonusb)
      print "USB"
    else if (!found_usb && found_nonusb)
      print "non-USB"
    else if (found_usb && found_nonusb)
      print "both"
    else
      print "none"
  }
'

I'm admittedly not very familiar with udev, and there didn't seem to be a way to query for a device matching particular attributes (like you'd do when matching rules), rather udevadm info seems to expect you to query a specific device, or dump everything? I'd like to be wrong about this.

Contributor

jpouellet commented Apr 2, 2017

Here's a shot using udev:

#!/bin/sh
udevadm info -e | awk '
  BEGIN {
    found_usb=0
    found_nonusb=0
    kbd=0
    usb=0
  }
  /^$/ {
    if (kbd) {
      if (usb)
        found_usb++
      else
        found_nonusb++
    }
    kbd=0
    usb=0
  }
  /^E: ID_INPUT_KEYBOARD=1$/ { kbd=1 }
  /^E: ID_USB/ { usb=1 }
  END {
    if (found_usb && !found_nonusb)
      print "USB"
    else if (!found_usb && found_nonusb)
      print "non-USB"
    else if (found_usb && found_nonusb)
      print "both"
    else
      print "none"
  }
'

I'm admittedly not very familiar with udev, and there didn't seem to be a way to query for a device matching particular attributes (like you'd do when matching rules), rather udevadm info seems to expect you to query a specific device, or dump everything? I'd like to be wrong about this.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Enumerating with pyudev like in the installer would be cleaner, but we don't have pyudev in dom0 by default and idk if we'd like to bring it in just for qubes-hcl-report (which is currently all shell anyway).

Contributor

jpouellet commented Apr 2, 2017

Enumerating with pyudev like in the installer would be cleaner, but we don't have pyudev in dom0 by default and idk if we'd like to bring it in just for qubes-hcl-report (which is currently all shell anyway).

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

@Yethal Can you post a list of your dir /dev/input/by-path with the keyboard unplugged? Its possibly detecting the empty port (which is good).

tasket commented Apr 2, 2017

@Yethal Can you post a list of your dir /dev/input/by-path with the keyboard unplugged? Its possibly detecting the empty port (which is good).

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Apr 2, 2017

Contributor

Its possibly detecting the empty port (which is good).

Good... unless the laptop simply has a PS/2 controller somewhere with no actual PS/2 port exposed, and the built-in keyboard is attached via internal USB. If udev has logic to attempt to differentiate this case, then I think it makes sense to take advantage of it.

Contributor

jpouellet commented Apr 2, 2017

Its possibly detecting the empty port (which is good).

Good... unless the laptop simply has a PS/2 controller somewhere with no actual PS/2 port exposed, and the built-in keyboard is attached via internal USB. If udev has logic to attempt to differentiate this case, then I think it makes sense to take advantage of it.

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

I don't know what use case would justify a PS/2 controller + internal USB keyboard. Assuming there is, (though I doubt udev can tell between an internal and external PS/2 port) then I'd guess we're looking at involving the user in a hardware test of some kind... "Press the Z and SHIFT keys on your keyboard" for each detected keyboard. But since we're also looking for the ability to plug in a PS/2 keyboard (not so much whether such a keyboard is presently attached) then we may have to ask the user to plug in a PS/2 keyboard if one is available.

More realistic would be detecting PS/2 keyboard devices as above, instruct user to press keys on the "internal laptop keyboard (if any)" ... and ask a separate question "Does your computer have external PS/2 ports"?

This would return multiple pieces of information, and it could be represented on the HCL under a PS/2 Keyboard column with indications 'Controller present', 'Detected' or 'Answered yes'.

Another possibility is 'KISS'... simply show whether a PS/2 keyboard controller was detected and add a footnote explaining what that means. But I like the above idea of having the user answer a question and tap keys.

tasket commented Apr 2, 2017

I don't know what use case would justify a PS/2 controller + internal USB keyboard. Assuming there is, (though I doubt udev can tell between an internal and external PS/2 port) then I'd guess we're looking at involving the user in a hardware test of some kind... "Press the Z and SHIFT keys on your keyboard" for each detected keyboard. But since we're also looking for the ability to plug in a PS/2 keyboard (not so much whether such a keyboard is presently attached) then we may have to ask the user to plug in a PS/2 keyboard if one is available.

More realistic would be detecting PS/2 keyboard devices as above, instruct user to press keys on the "internal laptop keyboard (if any)" ... and ask a separate question "Does your computer have external PS/2 ports"?

This would return multiple pieces of information, and it could be represented on the HCL under a PS/2 Keyboard column with indications 'Controller present', 'Detected' or 'Answered yes'.

Another possibility is 'KISS'... simply show whether a PS/2 keyboard controller was detected and add a footnote explaining what that means. But I like the above idea of having the user answer a question and tap keys.

@tasket

This comment has been minimized.

Show comment
Hide comment
@tasket

tasket Apr 2, 2017

To clarify:

Ideally we should look for a PS/2 "internal" laptop keyboard and/or external PS/2 ports.

If we're going to encounter systems with odd combinations like USB internal keyboard + PS/2 touchpad + unused PS/2 keyboard port (or a PS/2 special-key device) then we'll probably need user input to discern what is a real keyboard or accessible port. The alternative is to report simply that PS/2 was detected along with a footnote/disclaimer.

I don't know if Linux distros (or any equipment vendor) ever had reason to care whether a PS/2 device was internal or external...

tasket commented Apr 2, 2017

To clarify:

Ideally we should look for a PS/2 "internal" laptop keyboard and/or external PS/2 ports.

If we're going to encounter systems with odd combinations like USB internal keyboard + PS/2 touchpad + unused PS/2 keyboard port (or a PS/2 special-key device) then we'll probably need user input to discern what is a real keyboard or accessible port. The alternative is to report simply that PS/2 was detected along with a footnote/disclaimer.

I don't know if Linux distros (or any equipment vendor) ever had reason to care whether a PS/2 device was internal or external...

@Yethal

This comment has been minimized.

Show comment
Hide comment
@Yethal

Yethal Apr 3, 2017

@tasket here are by-path contents:
platform-i8042-serio-0-event-kbd platform-pcspkr-event-spkr

There is also a possibility that an external PS/2 port is internally connected to a PS/2 to USB converter which is then connected to a USB controller.

Yethal commented Apr 3, 2017

@tasket here are by-path contents:
platform-i8042-serio-0-event-kbd platform-pcspkr-event-spkr

There is also a possibility that an external PS/2 port is internally connected to a PS/2 to USB converter which is then connected to a USB controller.

@jpouellet

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet May 26, 2017

Contributor

relevant: #2781 (comment)

Keyboards can be weird...

Contributor

jpouellet commented May 26, 2017

relevant: #2781 (comment)

Keyboards can be weird...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment