13 Dec 2018

feedPlanet KDE

Achievement of the Week

This week I gave KDE Frameworks a web page after only 4 years of us trying to promote it as the best thing ever since cabogganing without one. I also updated the theme on the KDE Applications 18.12 announcement to this millennium and even made the images in it have a fancy popup effect using the latest in JQuery Bootstrap CSS. But my proudest contribution is making the screenshot for the new release of Konsole showing how it can now display all the cat emojis plus one for a poodle.

So far no comments asking why I named my computer thus.

Facebooktwittergoogle_pluslinkedinby feather

13 Dec 2018 6:41pm GMT

feedPlanet GNOME

Ludovico de Nittis: GNOME Security Internship - Update 1

If you missed it, the introduction to this project can be found here.

Check if we are in a working state

Before letting the user select the desired level of USB protection, we check if we are in a working state. Meaning for example that USBGuard needs to be installed and the corresponding DBus service needs to be active.

If these conditions are not met, we grey out the dropdown menu in GNOME-Control-Center.

first step

This method probably can be improved showing also the reason of the non working state to the users.

"allow" wildcard rule

As I mentioned in my previous blog post, we can't get or set ImplicitPolicyTarget from the USBGuard configuration. While the PR is still open, we worked around this issue using the rule file.

Prepending a wildcard allow rule allow *:* we are now able to reach a state where every new inserted devices are automatically allowed.

It works like this:

Allow wildcard

Fail-safe mode

Using the allow wildcard is also useful for reaching a fail-safe mode when we want USB protection when the lock screen is active. What does fail-safe mean? Let me give you a real world example:

The user sets the USB protection level to "when lock screen is active", so when the session is unlocked he can freely plug in USB devices. But when the session gets locked all new USB devices needs to be blocked.

The logic here is bounded in GNOME-Shell's lock and unlock functions. When a lock happens we set InsertedDevicePolicy to block. When the session is unlocked we set InsertedDevicePolicy to apply-policy.

But what happen if the user activates the lock screen and then GNOME-Shell crashes? After a reboot InsertedDevicePolicy will continue to be at block, so is the user locked out? No because there is a trick.

When USBGuard service starts there is another config variable that gets checked: PresentDevicePolicy. This rule regulates how to handle already connected USB devices. By default it is set to apply-policy, meaning that it will check the rule files and, if there isn't a match, the ImplicitPolicyTarget value. And because we have an allow *:* in our rule file, already present devices will get authorized.

Oof, there is a lot in this section. But there is one last thing. Ok, we are not locked out because we can still use our plugged in, at boot time, USB devices, great. But what about InsertedDevicePolicy? It is stuck to block while it should be at apply-policy, how we reset it now? If you end up in this situation, you can invoke the lock screen one single time and everything will return as it should.

Reflect manual user changes

USBGuard can now be configured from GNOME-Control-Center, awesome. But what happens if I set something from g-c-c and later I manually edit the USBGuard configuration within the CLI or DBus? In order to reflect the current USBGuard status we subscribe to the new PropertyParameterChanged signal. If the protection level was "Always" but InsertedDevicePolicy gets changed to apply-policy, or also the other way around, if the protection level was "Never" but InsertedDevicePolicy gets changed to block, it's save to assume that the user manually changed the USBGuard configuration. So we change the displayed value accordingly (without further changing the current USBGuard config values).

Notification for blocked USB devices

If a new USB device has been blocked because plugged in when the session was locked, we display a notification to inform the user that he needs to replug his device.

USB Notification

Step 3 - From static to dynamic

Until now everything has been achieved with a "static" configuration of USBGuard. That means that we edited USBGuard in order to let it do what we wanted, but we were not actively listening to USBGuard events, like to the signal DevicePrecenceChanged.

With this static configuration we probably can't do much else, we reached the capability limit. This is the reason why now everything has been switched to be more dynamic.

Now the new GNOME-Shell's USB component, similarly to the Thunderbolt one, actively listens to USBGuard signals and act accordingly.

What to expect next and comments

The two major things to expect are: smarter way to handle keyboards even if the protection is active (what happens if my keyboard breaks?) and also trying to add some sort of protection even when the session is unlocked (improving in this way the "block all" that we have right now).

Feedback is welcome!

13 Dec 2018 10:08am GMT

Ludovico de Nittis: GNOME Security Internship - The Beginning

Introduction

For this very first round of GNOME Internships I'll work in the USB Protection project.

The attack surface of USB is quite large and while disabling USB altogether solves the problem, it creates other. As do existing protection mechanisms. They suffer from poor usability and missing integration into the operating system.

This is why here we are trying a different approach to defend against rogue USB devices for a GNOME-based operating system.

USB is arguably to most exposed interface of a user's machine. It allows an attacker to interact with pretty much any driver, many of which are of questionable quality.

In order to protect the users, while keeping the entire system easy to use, we try to be smart about when to allow new USB devices. First, we try to detect when the user is present, arguing that if the user is not then new USB devices should not work. But even this apparently simple case can hide some complications, because for example you might very well want to attach a new keyboard in case yours breaks. Keyboards, however, pose another risk as several attacks have shown.

This project will be handled with an incremental build model, decomposing the whole problem in parts. In this way we'll be able to start tackling the problem from the easier cases and gradually increase the proposed solution complexity.

USBGuard

In this "preparation" month I started to look into USBGuard, because it is very likely that this will be the component we will use within GNOME in order to protect the USB ports.

The configuration of USBGuard consists of two files: usbguard-daemon.conf and rules.conf. The former holds a few variables like InsertedDevicePolicy and ImplicitPolicyTarget, while the latter is a file where it's possible to whitelist/blacklist single, or groups of, USB devices.

When you plug in a new USB device in your system, USBGuard performs a few sequential checks in order to decide if a device should be enabled:

  1. From the usbguard-daemon.conf the value of InsertedDevicePolicy will be checked:

    • If it is apply-policy it will go to the step 2.

    • If it is block or reject the device will be, respectively, deauthorized or removed. No further checks will be performed.

  2. The rules.conf file will be parsed:

    • If there is a rule that matches the inserted USB device it will be applied. No further checks will be performed.

    • Otherwise it will go to the step 3.

  3. From the usbguard-daemon.conf the value of ImplicitPolicyTarget will be checked:

    • If it is allow the device will be authorized

    • If it is block or reject the device will be, respectively, deauthorized or removed.

On top of that, from the CLI/DBus there is a function called applyDevicePolicy that can be used to override the decision that USBGuard took after the three steps listed above. In applyDevicePolicy there is a parameter called permanent. If it is set to False the policy override will just work as long as the device stays plugged in. Otherwise if set to True, the policy will be stored in the rules.conf file.

USBGuard limitations

USBGuard configuration can be accessed and manipulated with DBus. Unfortunately there were two major deal breaker for us:

The first issue was solved with this PR, now already merged in master.

The second is an issue for us because without being able to manipulate ImplicitPolicyTarget we can't, for example, easily reach a state where we allow every new USB devices. Regarding this limitation I proposed a fix with this PR, and it is currently waiting for approval.

Work done so far

My starting point was regarding the first step where we display an entry in GNOME Control Center under the Privacy tab that let the user permanently allow or disallow new USB devices. So far I created two proof of concepts of this functionality:

  1. The first uses a GSettings entry to store the chosen value.

  2. The second where the displayed value always reflects the InsertedDevicePolicy from the USBGuard configuration.

first step

For the second step the plan was to give an option to forbid new USB devices only when the lock screen was active. This can be considered a sort of a middle ground between the permanently allow and disallow. So far I did a first proof of concept where I displayed a drop down menu letting the users choose between "always", "never" and "when lock screen is active".

The chosen property is then propagated to the USBGuard configuration and also stored with GSettings.

What to expect in the following 1-2 weeks

Currently in the PoC that I realized I'm working exclusively with the InsertedDevicePolicy property. While this is good enough when we want to block USB devices, it is subpar when we want to deactivate the protection. The only way to be 100% sure that every new devices will be allowed is with ImplicitPolicyTarget. As soon as we will be able to control it too, I'll adjust my implementation accordingly. In the meantime I can prepend a wildcard "allow" to the rule file to achieve the same result.

I also need to improve the USBGuard check, in order to better inform the users if something is not working as expected (e.g. too old version of USBGuard or wrong initial USBGuard configuration).

Regarding the second step I'll create a patch for GNOME Shell that binds the USB locking logic to the lock screen process and, before acting, it checks the stored property from GNOME Control Center to decide how to behave based on the users choice. In this step also an interesting question raises: What to do with devices which have been inserted while the lock screen was on? Initially we probably keep them blocked and maybe we should show a notification about them to inform the users that they need to be re-plugged to make them work.

Thanks

I'd like to thanks Tobias Muller for guiding me in this project and the whole GNOME foundation for this awesome opportunity.

13 Dec 2018 10:08am GMT

feedPlanet KDE

Krita 4.1.7 Released

Today we're releasing Krita 4.1.7, another bug fix release in the Krita 4.1 series.

The most important fix is a weird one: it might help your wifi connection. The problem is that we started building a widget that would show you the news feed from krita.org. The widget isn't active, and doesn't make any kind of network connection… But Qt's network manager class still checks your wifi settings all the time. See these bugs: https://bugreports.qt.io/browse/QTBUG-46015 and https://bugreports.qt.io/browse/QTBUG-40332.

Apart from that, we've worked around a bug in Qt 5.12 that would cause an instant crash when using a tablet. Our own builds do not use that version of Qt, so the Windows builds, macOS build and the Linux appimage are fine, but users of rolling Linux releases like Arch would suffer from this issue.

And there are more bug fixes, of course:

Download

Windows

Note for Windows users: if you encounter crashes, please follow these instructions to use the debug symbols so we can figure out where Krita crashes.

Linux

(If, for some reason, Firefox thinks it needs to load this as text: to download, right-click on the link.)

When it is updated, you can also use the Krita Lime PPA to install Krita 4.1.7 on Ubuntu and derivatives. We are working on an updated snap.

OSX

Note: the touch docker, gmic-qt and python plugins are not available on OSX.

Source code

md5sum

For all downloads:

Key

The Linux appimage and the source tarball are signed. You can retrieve the public key over https here:
0x58b9596c722ea3bd.asc
. The signatures are here (filenames ending in .sig).

Support Krita

Krita is a free and open source project. Please consider supporting the project with donations or by buying training videos or the artbook! With your support, we can keep the core team working on Krita full-time.

13 Dec 2018 9:03am GMT

12 Dec 2018

feedPlanet GNOME

Daniel García Moreno: Fractal December'18 Hackfest (part 1)

First two days of work

The Tuesday 11th started the second Fractal Hackfest. I've organized this hackfest in Seville, the city where I studied computer science and here I've a lot of friends in the University so is a good place to do it here.

The weather was important too for the hackfest selection, in December Seville is a good choice because the weather is not too cold, we're having sunny days.

The first day was a good day, thinking about some relevant issues and planning what we want to do. We talked about the work needed for the interface split, about the E2EE support, new features and the need for a new release.

We're having some problems with the internet connection, because the University has a restricted network policy and we ask for the guess internet connection the Monday, but we're still waiting.

Meantime we have to thanks to Julian Sparber the hackfest wifi, because he's using his laptop to stream the eduroam connection.

Newcomers

The first day we try to promote as a newcomers day, and some people comes. We've some contributions and I spend some time trying to help people to introduce to the GNOME community.

GNOME Foundation sponsored dinner

The GNOME Foundation payed for a Fractal dev day dinner, so we should thanks this great dinner to GNOME:


We've a good time eating and drinking in the Coco Verde. We talk about GNOME, the desktop, matrix.org and other communication tools.

Hacking day

Today was a hacking day, so we started to work in the stuff that we talk about yesterday. We've resolved some minor issues and I started with the fractal-backend crate.


We talked about move all the app data model and logic to the fractal-backend and leave fractal-gtk only as UI management.

We talked about the LMDB use to store rooms and messages and we decided that the best solution should be to use a relational database, because we've relations and with the key-value thing we'll end creating those relations and maintaining by hand. In any case, I've this decision in mind and I'm implementing all this with a trait to hide the storage detail so we can change easily in the future.

So today I've spend a lot of time implementing this trait and a first implementation for the Room struct. I've decided to use rusqlite instead the diesel orm because I want to keep it simple.

I want to finish all the database storage and move the AppOp main loop to the fractal-backend and try to update the fractal-gtk to use the backend instead the AppOp struct to get the rooms and messages. But maybe is a lot of work, I don't know if I'll be able to finish this before the end of the hackfest.


Thanks

This hackfest is possible because there's a lot of volunteer work and people helping us. First of all, the Fractal core team that comes Tobias Bernard, Julian Sparber and Alexandre Franke and of course the GNOME Foundation. And also we've to thank Alejandro Domínguez, a newcomer that is doing a really good job fixing bugs and cleaning some old code.

Then I want to thank the Linux local group, SUGUS for the help and also I want to thank to other free software related group Plan4D.


Plan4D is giving us some help with the place and cookies, fruits, juices and some tea.

And finally I want to thank again to my coworkers in wadobo because they support me to spend a full work week working in gnome and they also spend some time helping us to organize all the hackfest stuff.

12 Dec 2018 9:09pm GMT

feedPlanet KDE

A simple blank makes the difference

OFX is the Open Financial eXchange protocol used by various financial institutions in a few countries. KMyMoney provides an OFX client implementation using the open source LibOFX library allowing users to import transactions directly from the bank's server without using the detour through a web-browser and a downloaded file into the ledger of the application.

A while ago, a KMyMoney user reported a problem with a single institution using OFX transaction download. Out of a sudden, this feature did not work anymore and the bank did not allow to login anymore and provided the following error message:

We're very sorry, but that content you are looking for can't be found. Please try the homepage again. If you continue to receive this message, please call the Customer Service number on the back of your card. We apologize for any inconvenience and appreciate your patience.

Since there was no change on the KMyMoney side nor on LibOFX, the problem must have been with the institution. So he contacted their customer support but the answers did not help to solve the problem.

Not surprisingly I got nowhere talking to tech support at the bank. I don't think anyone answering the phones knows anything about direct connect ."Can you logon to our website" and "reinstall your personal finance software" is about all they could suggest.

A frustrated KMyMoney user about his banks customer support

We know these answers just to well and one can find them on mailing lists and forums of almost any open source finance applications in or another form.

Living in a country where banks don't use OFX at all, it is kind of hard to support these stranded users. We tried to log the requests and analyze them, but all just looked well according to the OFX specs.

Searching the web, I came across a posting where a GnuCash user reported, that adding a trailing blank to the username and changing the application version in the request solved the problem. This just sounded too strange, so I forwarded this information to the user and he answered:

Not surprisingly… ipwizard does it again!

I changed the APP_VER to 2400 using the KMM online settings as suggested. Then I saved my KMM file in XML, opened the XML and added a space to me user name.

Worked like a charm.

A happy KMyMoney user

I was also able to get it working with KMM 4.8.0. I just unmapped and remapped the account adding a space to the end of the user ID and using 2700 as the version. No XML hacking required.

Another KMyMoney user also being happy

As a side effect of my search, I stumbled across a posting about OFX security issues. Very interesting article which does not surprise me and shows the partial ignorance of banks regarding security on top of their sometimes non-existant customer support if it comes to home banking.

12 Dec 2018 7:54pm GMT

feedplanet.freedesktop.org

Peter Hutterer: Understanding HID report descriptors

This time we're digging into HID - Human Interface Devices and more specifically the protocol your mouse, touchpad, joystick, keyboard, etc. use to talk to your computer.

Remember the good old days where you had to install a custom driver for every input device? Remember when PS/2 (the protocol) had to be extended to accommodate for mouse wheels, and then again for five button mice. And you had to select the right protocol to make it work. Yeah, me neither, I tend to suppress those memories because the world is awful enough as it is.

As users we generally like devices to work out of the box. Hardware manufacturers generally like to add bits and bobs because otherwise who would buy that new device when last year's device looks identical. This difference in needs can only be solved by one superhero: Committee-man, with the superpower to survive endless meetings and get RFCs approved.

Many many moons ago, when USB itself was in its infancy, Committee man and his sidekick Caffeine boy got the USB consortium agree on a standard for input devices that is so self-descriptive that operating systems (Win95!) can write one driver that can handle this year's device, and next year's, and so on. No need to install extra drivers, your device will just work out of the box. And so HID was born. This may only an approximate summary of history.

Originally HID was designed to work over USB. But just like Shrek the technology world is obsessed with layers so these days HID works over different transport layers. HID over USB is what your mouse uses, HID over i2c may be what your touchpad uses. HID works over Bluetooth and it's celebrity-diet version BLE. Somewhere, someone out there is very slowly moving a mouse pointer by sending HID over carrier pigeons just to prove a point. Because there's always that one guy.

HID is incredibly simple in that the static description of the device can just be bytes burnt into the ROM like the Australian sun into unprepared English backpackers. And the event frames are often an identical series of bytes where every bit is filled in by the firmware according to the axis/buttons/etc.

HID is incredibly complicated because parsing it is a stack-based mental overload. Each individual protocol item is simple but getting it right and all into your head is tricky. Luckily, I'm here for you to make this simpler to understand or, failing that, at least more entertaining.

As said above, the purpose of HID is to make devices describe themselves in a generic manner so that you can have a single driver handle any input device. The idea is that the host parses that standard protocol and knows exactly how the device will behave. This has worked out great, we only have around 200 files dealing with vendor- and hardware-specific HID quirks as of v4.20.

HID messages are Reports. And to know what a Report means and how to interpret it, you need a Report Descriptor. That Report Descriptor is static and contains a series of bytes detailing "what" and "where", i.e. what a sequence of bits represents and where to find those bits in the Report. So let's try and parse one of Report Descriptors, let's say for a fictional mouse with a few buttons. How exciting, we're at the forefront of innovation here.

The Report Descriptor consists of a bunch of Items. A parser reads the next Item, processes the information within and moves on. Items are small (1 byte header, 0-4 bytes payload) and generally only apply exactly one tiny little bit of information. You need to accumulate several items to build up enough information to actually know what's happening.

The "what" question of the Report Descriptor is answered with the so-called Usage. This could be something simple like X or Y (0x30 and 0x31) or something more esoteric like System Menu Exit (0x88). A Usage is 16 bits but all Usages are grouped into so-called Usage Pages. A Usage Page too is a 16 bit value and together they form the 32-bit value that tells us what the device can do. Examples:


0001 0031 # Generic Desktop, Y
0001 0088 # Generic Desktop, System Menu Exit
0003 0005 # VR Controls, Head Tracker
0003 0006 # VR Controls, Head Mounted Display
0004 0031 # Keyboard, Keyboard \ and |

Note how the Usage in the last item is the same as the first one, without the Usage Page you will mix things up. It helps if you always think of as the Usage as a 32-bit number. For your kids' bed-time story time, here are the HID Usage Tables from 2004 and the approved HID Usage Table Review Requests of the last decade. Because nothing puts them to sleep quicker than droning on about hex numbers associated with remote control buttons.

To successfully interpret a Report from the device, you need to know which bits have which Usage associated with them. So let's go back to our innovative mouse. We would want a report descriptor with 6 items like this:


Usage Page (Generic Desktop)
Usage (X)
Report Size (16)
Usage Page (Generic Desktop)
Usage (Y)
Report Size (16)

This basically tells the host: X and Y both have 16 bits. So if we get a 4-byte Report from the device, we know two bytes are for X, two for Y.

HID was invented when a time when bits were more expensive than printer ink, so we can't afford to waste any bits (still the case because who would want to spend an extra penny on more ROM). HID makes use of so-called Global items, once those are set their value applies to all following items until changed. Usage Page and Report Size are such Global items, so the above report descriptor is really implemented like this:


Usage Page (Generic Desktop)
Usage (X)
Usage (Y)
Report Count (2)
Report Size (16)
Input (Data,Var,Rel)

The Report Count just tells us that 2 fields of the current Report Size are coming up. We have two usages, two fields, and 16 bits each so we know what to do. The Input item is sort-of the marker for the end of the stack, it basically tells us "process what you've seen so far", together with a few flags. Rel in this case means that the Usages are relative. Oh, and Input means that this is data from device to host. Output would be data from host to device, e.g. to set LEDs on a keyboard. There's also Feature which indicates configurable items.

Buttons on a device are generally just numbered so it'd be monumental 16-bits-at-a-time waste to have HID send Usage (Button1), Usage (Button2), etc. for every button on the device. HID instead provides a Usage Minimum and Usage Maximumto sequentially order them. This looks like this:


Usage Page (Button)
Usage Minimum (1)
Usage Maximum (5)
Report Count (5)
Report Size (1)
Input (Data,Var,Abs)

So we have 5 buttons here and each button has one bit. Note how the buttons are Abs because a button state is not a relative value, it's either down or up. HID is quite intolerant to Schrödinger's thought experiments.

Let's put the two things together and we have an almost-correct Report descriptor:


Usage Page (Button)
Usage Minimum (1)
Usage Maximum (5)
Report Count (5)
Report Size (1)
Input (Data,Var,Abs)

Report Size (3)
Report Count (1)
Input (Cnst,Arr,Abs)

Usage Page (Generic Desktop)
Usage (X)
Usage (Y)
Report Count (2)
Report Size (16)
Input (Data,Var,Rel)

New here is Cnst. This signals that the bits have a constant value, thus don't need a Usage and basically don't matter (haha. yeah, right. in theory). Linux does indeed ignore those. Cnst is used for padding to align on byte boundaries - 5 bits for buttons plus 3 bits padding make 8 bits. Which makes one byte as everyone agrees except for granddad over there in the corner. I don't know how he got in.

Were we to get a 5-byte Report from the device, we'd parse it approximately like this:


button_state = byte[0] & 0x1f
x = bytes[1] | (byte[2] << 8)
y = bytes[3] | (byte[4] << 8)

Hooray, we're almost ready. Except not. We may need more info to correctly interpret the data within those reports.

The Logical Minimum and Logical Maximum specify the value range of the actual data. We need this to tell us whether the data is signed and what the allowable range is. Together with the Physical Minimumand the Physical Maximum they specify what the values really mean. In the simple case:


Usage Page (Generic Desktop)
Usage (X)
Usage (Y)
Report Count (2)
Report Size (16)
Logical Minimum (-32767)
Logical Maximum (32767)
Input (Data,Var,Rel)

This just means our x/y data is signed. Easy. But consider this combination:


...
Logical Minimum (0)
Logical Maximum (1)
Physical Minimum (1)
Physical Maximum (12)

This means that if the bit is 0, the effective value is 1. If the bit is 1, the effective value is 12.

Note that the above is one report only. Devices may have multiple Reports, indicated by the Report ID. So our Report Descriptor may look like this:


Report ID (01)
Usage Page (Button)
Usage Minimum (1)
Usage Maximum (5)
Report Count (5)
Report Size (1)
Input (Data,Var,Abs)
Report Size (3)
Report Count (1)
Input (Cnst,Arr,Abs)

Report ID (02)
Usage Page (Generic Desktop)
Usage (X)
Usage (Y)
Report Count (2)
Report Size (16)
Input (Data,Var,Rel)

If we were to get a Report now, we need to check byte 0 for the Report ID so we know what this is. i.e. our single-use hard-coded parser would look like this:


if byte[0] == 0x01:
button_state = byte[1] & 0x1f
else if byte[0] == 0x02:
x = bytes[2] | (byte[3] << 8)
y = bytes[4] | (byte[5] << 8)

A device may use multiple Reports if the hardware doesn't gather all data within the same hardware bits. Now, you may ask: if I get fifteen reports, how should I know what belongs together? Good question, and lucky for you the HID designers are miles ahead of you. Report IDs are grouped into Collections.

Collections can have multiple types. An Application Collectiondescribes a set of inputs that make sense as a whole. Usually, every Report Descriptor must define at least one Application Collection but you may have two or more. For example, a a keyboard with integrated trackpoint should and/or would use two. This is how the kernel knows it needs to create two separate event nodes for the device. Application Collections have a few reserved Usages that indicate to the host what type of device this is. These are e.g. Mouse, Joystick, Consumer Control. If you ever wondered why you have a device named like "Logitech G500s Laser Gaming Mouse Consumer Control" this is the kernel simply appending the Application Collection's Usage to the device name.

A Physical Collection indicates that the data is collected at one physical point though what a point is is a bit blurry. Theoretical physicists will disagree but a point can be "a mouse". So it's quite common for all reports on a mouse to be wrapped in one Physical Collections. If you have a device with two sets of sensors, you'd have two collections to illustrate which ones go together. Physical Collections also have reserved Usages like Pointer or Head Tracker.

Finally, a Logical Collection just indicates that some bits of data belong together, whatever that means. The HID spec uses the example of buffer length field and buffer data but it's also common for all inputs from a mouse to be grouped together. A quick check of my mice here shows that Logitech doesn't wrap the data into a Logical Collection but Microsoft's firmware does. Because where would we be if we all did the same thing...

Anyway. Now that we know about collections, let's look at a whole report descriptor as seen in the wild:


Usage Page (Generic Desktop)
Usage (Mouse)
Collection (Application)
Usage Page (Generic Desktop)
Usage (Mouse)
Collection (Logical)
Report ID (26)
Usage (Pointer)
Collection (Physical)
Usage Page (Button)
Usage Minimum (1)
Usage Maximum (5)
Report Count (5)
Report Size (1)
Logical Minimum (0)
Logical Maximum (1)
Input (Data,Var,Abs)
Report Size (3)
Report Count (1)
Input (Cnst,Arr,Abs)
Usage Page (Generic Desktop)
Usage (X)
Usage (Y)
Report Count (2)
Report Size (16)
Logical Minimum (-32767)
Logical Maximum (32767)
Input (Data,Var,Rel)
Usage (Wheel)
Physical Minimum (0)
Physical Maximum (0)
Report Count (1)
Report Size (16)
Logical Minimum (-32767)
Logical Maximum (32767)
Input (Data,Var,Rel)
End Collection
End Collection
End Collection

We have one Application Collection (Generic Desktop, Mouse) that contains one Logical Collection (Generic Desktop, Mouse). That contains one Physical Collection (Generic Desktop, Pointer). Our actual Report (and we have only one but it has the decimal ID 26) has 5 buttons, two 16-bit axes (x and y) and finally another 16 bit axis for the Wheel. This device will thus send 8-byte reports and our parser will do:


if byte[0] != 0x1a: # it's decimal in the above descriptor
error, should be 26
button_state = byte[1] & 0x1f
x = byte[2] | (byte[3] << 8)
y = byte[4] | (byte[5] << 8)
wheel = byte[6] | (byte[7] << 8)

That's it. Now, obviously, you can't write a parser for every HID descriptor out there so your actual parsing code needs to be generic. The Linux kernel does exactly that and so does everything else that needs to parse HID. There's a huge variety in devices out there, all with HID descriptors that may or may not be correct. As with so much in life, correct HID implementations are often defined by "whatever Windows accepts" so if you like playing catch, Linux development is for you.

Oh, in case you just got a bit too optimistic about the state of the world: HID allows for vendor-defined usages. Which does exactly what you'd think it does, it hides vendor-specific protocol inside what should be a generic protocol. There are devices with hidden report IDs that you can only unlock by sending the right magic sequence to the report and/or by defeating the boss on Level 4. Usually those devices present themselves as basic/normal devices over HID but if you know the magic sequence you get to use *gasp* all buttons. Or access the device-specific configuration features. Logitech's HID++ is just one example here but at least that's one where we have most of the specs available.

The above describes how to parse the HID report descriptor and interpret the reports. But what happens once you have a HID report correctly parsed? In the case of the Linux kernel, once the report descriptor is parsed evdev nodes are created (one per Application Collection, more or less). As the Reports come in, they are mapped to evdev codes and the data appears on the evdev node. That's where userspace like libinput can pick it up. That bit is actually quite simple (mostly anyway).

The above output was generated with the tools from the hid-tools repository. Go forth and hid-record.

12 Dec 2018 10:21am GMT

Peter Hutterer: High resolution wheel scrolling on Linux v4.21

Disclaimer: this is pending for v4.21 and thus not yet in any kernel release.

Most wheel mice have a physical feature to stop the wheel from spinning freely. That feature is called detents, notches, wheel clicks, stops, or something like that. On your average mouse that is 24 wheel clicks per full rotation, resulting in the wheel rotating by 15 degrees before its motion is arrested. On some other mice that angle is 18 degrees, so you get 20 clicks per full rotation.

Of course, the world wouldn't be complete without fancy hardware features. Over the last 10 or so years devices have added free-wheeling scroll wheels or scroll wheels without distinct stops. In many cases wheel behaviour can be configured on the device, e.g. with Logitech's HID++ protocol. A few weeks back, Harry Cutts from the chromium team sent patches to enable Logitech high-resolution wheel scrolling in the kernel. Succinctly, these patches added another axis next to the existing REL_WHEEL named REL_WHEEL_HI_RES. Where available, the latter axis would provide finer-grained scroll information than the click-by-click REL_WHEEL. At the same time I accidentally stumbled across the documentation for the HID Resolution Multiplier Feature. A few patch revisions later and we now have everything queued up for v4.21. Below is a summary of the new behaviour.

The kernel will continue to provide REL_WHEEL as axis for "wheel clicks", just as before. This axis provides the logical wheel clicks, (almost) nothing changes here. In addition, a REL_WHEEL_HI_RES axis is available which allows for finer-grained resolution. On this axis, the magic value 120 represents one logical traditional wheel click but a device may send a fraction of 120 for a smaller motion. Userspace can either accumulate the values until it hits a full 120 for one wheel click or it can scroll by a few pixels on each event for a smoother experience. The same principle is applied to REL_HWHEEL and REL_HWHEEL_HI_RES for horizontal scroll wheels (which these days is just tilting the wheel). The REL_WHEEL axis is now emulated by the kernel and simply sent out whenever we have accumulated 120.

Important to note: REL_WHEEL and REL_HWHEEL are now legacy axes and should be ignored by code handling the respective high-resolution version.

The magic value of 120 is taken directly from Windows. That value was chosen because it has a good number of integer factors, so dividing 120 by whatever multiplier the mouse uses gives you a integer fraction of 120. And because HW manufacturers want it to work on Windows, we can rely on them doing it right, provided we use the same approach.

There are two implementations that matter. Harry's patches enable the high-resolution scrolling on Logitech mice which seem to mostly have a multiplier of 8 (i.e. REL_WHEEL_HI_RES will send eight events with a value of 15 before REL_WHEEL sends 1 click). There are some interesting side-effects with e.g. the MX Anywhere 2S. In high-resolution mode with a multiplier of 8, a single wheel movement does not always give us 8 events, the firmware does its own magic here. So we have some emulation code in place with the goal of making the REL_WHEEL event happen on the mid-point of a wheel click motion. The exact point can shift a bit when the device sends 7 events instead of 8 so we have a few extra bits in place to reset after timeouts and direction changes to make sure the wheel behaviour is as consistent as possible.

The second implementation is for the generic HID protocol. This was all added for Windows Vista, so we're only about a decade behind here. Microsoft got the Resolution Multiplier feature into the official HID documentation (possibly in the hope that other HW manufacturers implement it which afaict didn't happen). This feature effectively provides a fixed value multiplier that the device applies in hardware when enabled. It's basically the same as the Logitech one except it's set through a HID feature instead of a vendor-specific protocol. On the devices tested so far (all Microsoft mice because no-one else seems to implement this) the multipliers vary a bit, ranging from 4 to 12. And the exact behaviour varies too. One mouse behaves correctly (Microsoft Comfort Optical Mouse 3000) and sends more events than before. Other mice just send the multiplied value instead of the normal value, so nothing really changes. And at least one mouse (Microsoft Sculpt Ergonomic) sends the tilt-wheel values more frequently and with a higher value. So instead of one event with value 1 every X ms, we now get an event with value 3 every X/4 ms. The mice tested do not drop events like the Logitech mice do, so we don't need fancy emulation code here. Either way, we map this into the 120 range correctly now, so userspace gets to benefit.

As mentioned above, the Resolution Multiplier HID feature was introduced for Windows Vista which is... not the most recent release. I have a strong suspicion that Microsoft dumped this feature as well, the most recent set of mice I have access to don't provide the feature anymore (they have vendor-private protocols that we don't know about instead). So the takeaway for all this is: if you have a Logitech mouse, you'll get higher-resolution scrolling on v4.21. If you have a Microsoft mouse a few years old, you may get high-resolution wheel scrolling if the device supports it. Any other vendor or a new Microsoft mouse, you don't get it.

Coincidentally, if you know anyone at Microsoft who can provide me with the specs for their custom protocol, I'd appreciate it. We'd love to have support for it both in libratbag and in the kernel. Or any other vendor, come to think of it.

12 Dec 2018 4:27am GMT

10 Dec 2018

feedplanet.freedesktop.org

Eric Anholt: 2018-12-10

For V3D last week, I resurrected my old GLES 3.1 series with SSBO and shader imgae support, rebuilt it for V3D 4.1 (shader images no longer need manual tiling), and wrote indirect draw support and started on compute shaders. As of this weekend, dEQP-GLES31 is passing 1387/1567 of tests with "compute" in the name on the simulator. I have a fix needed for barrier(), then it's time to build the kernel interface. In the process, I ended up fixing several job flushing bugs, plugging memory leaks, improving our shader disassembly debug dumps, and reducing memory consumption and CPU overhead.

The TFU series is now completely merged, and the kernel cache management series from last week is now also merged. I also fixed a bug in the core GPU scheduler that would cause use-after-frees when tracing.

For vc4, Boris completed and merged the H/V flipping work after fixing display of flipped/offset SAND images. More progress has been made on chamelium testing, so we're nearing having automated regression tests for parts of our display stack. My PM driver has the acks we needed, but my co-maintainer has tacked a new request on in v3 so it'll be delayed.

10 Dec 2018 12:30am GMT