You are not logged in.
I would like to develop a specific driver for a given bluetooth mouse, which ID is known, and could be specified in udev for instance.
Can you please give some pointers as
- what C library to use (the lower level the better)
- how to make sure the mouse will not be taken over by the GUI (Gnome)
Thanks!
Last edited by r-**-t (2015-03-13 14:08:40)
Offline
Are you looking to write a kernel mode driver, or a user space 'driver'?
What Bluetooth modes does the mouse use? Is it one of those that do HID over GATT?
To keep it out the grasps of Gnome, all you really should need to do is write some Xorg rules so that that the driver for that input class no be instantiated. You probably will need to create or edit 10-evdev-conf. https://wiki.archlinux.org/index.php/xo … _xorg.conf
Which libraries are used depends on the architecture, but I suggest the search terms 'linux gatt hid stack'
Edit: By the way -- Welcome to the Arch Linux forums
Last edited by ewaller (2015-03-13 16:13:47)
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
Hi ewaller, and thanks for the first pointers.
While considering myself fluent in C prog on Linux, I'm a total newbie in all of BT dev.
Currently is a project which human interface is from the keyboard. Target is to add BT support to that application.
And since a mouse has most of the necessary controls, the simplest would be probably to adapt/develop a BT mouse controller (and not a driver, indeed).
So to answer your questions,
- User space, I guess
- HID over GATT, according to the google search you suggested, seems to be the way to go
- had a look at Bluez, maybe bluez is fine - need to look more closely
But the library should have no huge dependency (besides the kernel of course). I.e. if not mistaken, V4L to capture video from a USB webcam does need a GUI like Gnome - why's that, it's USB... Probably the GUI libs convenience, but what when you're on small Linux device...
Offline
Okay, I think I have a better picture of what you are up too. You might want to look at the documentation on evdev. The evdev system maps many input devices into dev nodes in /dev/input/.
Xorg picks those up and maps them to xorg devices. Here are some evdev lines from my Xorg config file:
ewaller@odin /sys 1086 %grep evdev ~/.local/share/xorg/Xorg.0.log
[138175.033] (**) Power Button: Applying InputClass "evdev keyboard catchall"
[138175.033] (II) LoadModule: "evdev"
[138175.033] (II) Loading /usr/lib/xorg/modules/input/evdev_drv.so
[138175.034] (II) Module evdev: vendor="X.Org Foundation"
[138175.034] (II) Using input driver 'evdev' for 'Power Button'
[138175.034] (**) evdev: Power Button: Device: "/dev/input/event4"
[138175.035] (--) evdev: Power Button: Vendor 0 Product 0x1
[138175.035] (--) evdev: Power Button: Found keys
[138175.035] (II) evdev: Power Button: Configuring as keyboard
[138175.035] (**) Option "xkb_rules" "evdev"
[138175.068] (**) Video Bus: Applying InputClass "evdev keyboard catchall"
[138175.068] (II) Using input driver 'evdev' for 'Video Bus'
[138175.068] (**) evdev: Video Bus: Device: "/dev/input/event13"
[138175.068] (--) evdev: Video Bus: Vendor 0 Product 0x6
[138175.068] (--) evdev: Video Bus: Found keys
[138175.068] (II) evdev: Video Bus: Configuring as keyboard
[138175.068] (**) Option "xkb_rules" "evdev"
[138175.069] (**) Power Button: Applying InputClass "evdev keyboard catchall"
[138175.069] (II) Using input driver 'evdev' for 'Power Button'
[138175.069] (**) evdev: Power Button: Device: "/dev/input/event1"
[138175.069] (--) evdev: Power Button: Vendor 0 Product 0x1
[138175.069] (--) evdev: Power Button: Found keys
[138175.069] (II) evdev: Power Button: Configuring as keyboard
[138175.070] (**) Option "xkb_rules" "evdev"
[138175.070] (**) Sleep Button: Applying InputClass "evdev keyboard catchall"
[138175.071] (II) Using input driver 'evdev' for 'Sleep Button'
[138175.071] (**) evdev: Sleep Button: Device: "/dev/input/event3"
[138175.071] (--) evdev: Sleep Button: Vendor 0 Product 0x3
[138175.071] (--) evdev: Sleep Button: Found keys
[138175.071] (II) evdev: Sleep Button: Configuring as keyboard
[138175.071] (**) Option "xkb_rules" "evdev"
[138175.073] (**) HP Webcam: Applying InputClass "evdev keyboard catchall"
[138175.074] (II) Using input driver 'evdev' for 'HP Webcam'
[138175.074] (**) evdev: HP Webcam: Device: "/dev/input/event18"
[138175.074] (--) evdev: HP Webcam: Vendor 0x64e Product 0xc107
[138175.074] (--) evdev: HP Webcam: Found keys
[138175.074] (II) evdev: HP Webcam: Configuring as keyboard
[138175.074] (**) Option "xkb_rules" "evdev"
[138175.075] (**) AT Translated Set 2 keyboard: Applying InputClass "evdev keyboard catchall"
[138175.075] (II) Using input driver 'evdev' for 'AT Translated Set 2 keyboard'
[138175.075] (**) evdev: AT Translated Set 2 keyboard: Device: "/dev/input/event0"
[138175.075] (--) evdev: AT Translated Set 2 keyboard: Vendor 0x1 Product 0x1
[138175.075] (--) evdev: AT Translated Set 2 keyboard: Found keys
[138175.075] (II) evdev: AT Translated Set 2 keyboard: Configuring as keyboard
[138175.075] (**) Option "xkb_rules" "evdev"
[138175.076] (**) AlpsPS/2 ALPS GlidePoint: Applying InputClass "evdev touchpad catchall"
[138175.108] (**) ALPS PS/2 Device: Applying InputClass "evdev pointer catchall"
[138175.109] (II) Using input driver 'evdev' for 'ALPS PS/2 Device'
[138175.109] (**) evdev: ALPS PS/2 Device: Device: "/dev/input/event15"
[138175.109] (--) evdev: ALPS PS/2 Device: Vendor 0x2 Product 0x8
[138175.109] (--) evdev: ALPS PS/2 Device: Found 3 mouse buttons
[138175.109] (--) evdev: ALPS PS/2 Device: Found relative axes
[138175.109] (--) evdev: ALPS PS/2 Device: Found x and y relative axes
[138175.109] (II) evdev: ALPS PS/2 Device: Configuring as mouse
[138175.109] (**) evdev: ALPS PS/2 Device: YAxisMapping: buttons 4 and 5
[138175.109] (**) evdev: ALPS PS/2 Device: EmulateWheelButton: 4, EmulateWheelInertia: 10, EmulateWheelTimeout: 200
[138175.110] (II) evdev: ALPS PS/2 Device: initialized for relative axes.
[138175.112] (**) HP WMI hotkeys: Applying InputClass "evdev keyboard catchall"
[138175.112] (II) Using input driver 'evdev' for 'HP WMI hotkeys'
[138175.113] (**) evdev: HP WMI hotkeys: Device: "/dev/input/event17"
[138175.113] (--) evdev: HP WMI hotkeys: Vendor 0 Product 0
[138175.113] (--) evdev: HP WMI hotkeys: Found keys
[138175.113] (II) evdev: HP WMI hotkeys: Configuring as keyboard
[138175.113] (**) Option "xkb_rules" "evdev"
[138175.113] (**) MCE IR Keyboard/Mouse (ene_ir): Applying InputClass "evdev pointer catchall"
[138175.113] (**) MCE IR Keyboard/Mouse (ene_ir): Applying InputClass "evdev keyboard catchall"
[138175.114] (II) Using input driver 'evdev' for 'MCE IR Keyboard/Mouse (ene_ir)'
[138175.114] (**) evdev: MCE IR Keyboard/Mouse (ene_ir): Device: "/dev/input/event6"
[138175.114] (--) evdev: MCE IR Keyboard/Mouse (ene_ir): Vendor 0 Product 0
[138175.114] (--) evdev: MCE IR Keyboard/Mouse (ene_ir): Found 3 mouse buttons
[138175.114] (--) evdev: MCE IR Keyboard/Mouse (ene_ir): Found relative axes
[138175.114] (--) evdev: MCE IR Keyboard/Mouse (ene_ir): Found x and y relative axes
[138175.114] (--) evdev: MCE IR Keyboard/Mouse (ene_ir): Found keys
[138175.114] (II) evdev: MCE IR Keyboard/Mouse (ene_ir): Configuring as mouse
[138175.114] (II) evdev: MCE IR Keyboard/Mouse (ene_ir): Configuring as keyboard
[138175.114] (**) evdev: MCE IR Keyboard/Mouse (ene_ir): YAxisMapping: buttons 4 and 5
[138175.114] (**) evdev: MCE IR Keyboard/Mouse (ene_ir): EmulateWheelButton: 4, EmulateWheelInertia: 10, EmulateWheelTimeout: 200
[138175.114] (**) Option "xkb_rules" "evdev"
[138175.115] (II) evdev: MCE IR Keyboard/Mouse (ene_ir): initialized for relative axes.
[138175.116] (**) ENE eHome Infrared Remote Receiver: Applying InputClass "evdev keyboard catchall"
[138175.116] (II) Using input driver 'evdev' for 'ENE eHome Infrared Remote Receiver'
[138175.116] (**) evdev: ENE eHome Infrared Remote Receiver: Device: "/dev/input/event5"
[138175.116] (--) evdev: ENE eHome Infrared Remote Receiver: Vendor 0 Product 0
[138175.116] (--) evdev: ENE eHome Infrared Remote Receiver: Found keys
[138175.116] (II) evdev: ENE eHome Infrared Remote Receiver: Configuring as keyboard
[138175.116] (**) Option "xkb_rules" "evdev"
[243415.218] (II) evdev: ENE eHome Infrared Remote Receiver: Close
[243417.391] (II) UnloadModule: "evdev"
[243417.575] (II) evdev: MCE IR Keyboard/Mouse (ene_ir): Close
[243417.888] (II) UnloadModule: "evdev"
[243417.939] (II) evdev: HP WMI hotkeys: Close
[243417.988] (II) UnloadModule: "evdev"
[243418.029] (II) evdev: ALPS PS/2 Device: Close
[243418.110] (II) UnloadModule: "evdev"
[243418.207] (II) evdev: AT Translated Set 2 keyboard: Close
[243418.207] (II) UnloadModule: "evdev"
[243418.259] (II) evdev: HP Webcam: Close
[243418.278] (II) UnloadModule: "evdev"
[243418.320] (II) evdev: Sleep Button: Close
[243418.433] (II) UnloadModule: "evdev"
[243418.448] (II) evdev: Power Button: Close
[243418.543] (II) UnloadModule: "evdev"
[243418.562] (II) evdev: Video Bus: Close
[243418.562] (II) UnloadModule: "evdev"
[243418.573] (II) evdev: Power Button: Close
[243418.573] (II) UnloadModule: "evdev"
ewaller@odin /sys 1087 %
You can create an Xorg config file to block Xorg from loading a module for a device based upon event number, manufacturer, serial number, whatever. Then you are free to use the /dev/input/theNameOfTheDevice to for your custom I/O.
Here is the output of my "joystick" which are actually the output of the three axis accelerometers mapped to a joystick.
ewaller@odin /sys [130]1103 %sudo bash -c "cat /dev/input/js0 | od -x"
0000000 8403 a4bf 0000 0082 8403 a4bf 056b 0182
0000020 8403 a4bf 3257 0282 8435 a4bf 0048 0002
0000040 8435 a4bf 0596 0102 8467 a4bf 056b 0102
0000060 8499 a4bf 322c 0202 84ce a4bf 0596 0102
0000100 8500 a4bf 0000 0002 8500 a4bf 056b 0102
0000120 8500 a4bf 3249 0202 8532 a4bf 3266 0202
0000140 8596 a4bf 04bd 0102 8596 a4bf 323a 0202
0000160 85c8 a4bf 056b 0102 85fa a4bf 3257 0202
0000200 865e a4bf 3313 0202 8690 a4bf 3266 0202
0000220 86c2 a4bf 0596 0102 86f4 a4bf 056b 0102
0000240 878a a4bf 323a 0202 87bc a4bf 3257 0202
0000260 8884 a4bf 322c 0202 88b6 a4bf 3249 0202
0000300 88e8 a4bf 04bd 0102 88e8 a4bf 3266 0202
0000320 891a a4bf 36db 0202 894c a4bf 0104 0002
0000340 894c a4bf 0820 0102 894c a4bf 2bae 0202
0000360 897e a4bf 030c 0102 897e a4bf 31c7 0202
0000400 89b0 a4bf 0000 0002 89b0 a4bf 0104 0102
0000420 89b0 a4bf 35d7 0202 89e2 a4bf 0104 0002
0000440 89e2 a4bf fefb 0102 89e2 a4bf 3bef 0202
0000460 8a14 a4bf fdf7 0002 8a14 a4bf 0a28 0102
0000500 8a14 a4bf 33cf 0202 8a46 a4bf 0c30 0102
0000520 8a46 a4bf 279e 0202 8a8c a4bf 0000 0002
0000540 8a8c a4bf 0208 0102 8a8c a4bf 2db6 0202
0000560 8abe a4bf 0208 0002 8abe a4bf fefb 0102
0000600 8abe a4bf 35d7 0202 8af0 a4bf 0000 0002
0000620 8af0 a4bf 030c 0102 8af0 a4bf 39e7 0202
0000640 8b22 a4bf 0514 0102 8b22 a4bf 34d3 0202
0000660 8b54 a4bf 0104 0002 8b54 a4bf 0820 0102
0000700 8b54 a4bf 2cb2 0202 8b86 a4bf 0082 0002
0000720 8b86 a4bf 0514 0102 8b86 a4bf 30c3 0202
0000740 8bb8 a4bf 0000 0002 8bb8 a4bf 0208 0102
^C%
ewaller@odin /sys [130]1104 %
Poke around and see if an event node is generated for your BT mouse. If so, playing with that event node is orders of magnitude easier than horsing around at the HID layer.
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
Thanks for the advice! That was indeed helpful. Everything works as intended with, as you promised, little effort. Thanks a lot!
For those who are in the same situation (based on your comments)...
First of all, have to identify your input device.
xinput --list --long
or, Debian
apt-get install input-utils
lsinput
You may have to be root or sudo depending on /dev/input/* ACL.
Then you don't want the GUI to use the device.
On a recent Ubuntu at least, the Xorg configuration files are in
/usr/share/X11/xorg.conf.d
Create a new one with something like
Section "InputClass"
Identifier "my ignore bt elecom mouse"
MatchProduct "Bluetooth Super Mouse"
MatchDevicePath "/dev/input/*"
MatchIsPointer "on"
Option "Ignore" "on"
EndSection
So here, tried a few values as it doesn't seem easy to find exactly what Xorg considers the Vendor to be for instance.
Since got no luck with the Vendor, just used the Product instead.
There are certainly other ways to refine the match, if you have many input devices, with similar names etc...
Also, X created /dev/input/event12 and /dev/input/mouse1 and both had to be matched in the Section above (thus the /dev/input/*)
And log off / on to load the new parameters. As shown above by ewaller, the /var/log/Xorg.0.log file tells if your Section found a match.
Then, how to read the input data from the bluetooth mouse?
Tried first to use the /dev/input/mouse1 data, but it seems very much reduced to the minimum, and some mouse events cannot be distinguished.
So /dev/input/event12 looked more promising since, as the name invites to suggest, an event comes from the file whenever something happens on the mouse.
Had a look at /usr/include/linux/input.h to get an idea of what the event structure looks like, and used some of the C prog from this page
http://www.thelinuxdaily.com/2010/05/gr … nputevent/
Did a small loop to try to find my device ID (eventXX)
const char *look = "Elecom Bluetooth Super Mouse";
char dev[128],name[128];
int i,fd;
for (i=0 ; i<32 ; i++) {
sprintf(dev, "/dev/input/event%d", i);
if ((fd = open (dev, O_RDONLY)) > 0) {
ioctl (fd, EVIOCGNAME (sizeof (name)), name);
name[sizeof(name)-1] = 0;
if (strstr(name, look)) break;
close (fd);
}
}
if (i >= 32) {
printf("BT: could not find '%s'. No BT.\n", look);
return NULL;
}
printf("BT: found device %s\n", dev);
And then I loop on reading the device file
struct input_event ev;
int size = sizeof(struct input_event);
int rd;
while (1){
if ((rd = read (fd, &ev, size)) < size) {
perror ("BT read");
close (fd);
return NULL;
}
s_robex rob;
memset(&rob, 0, sizeof(s_robex));
//printf(" <BT event> %u %u %d\n", (unsigned)ev.type, (unsigned)ev.code, ev.value);
// button click
if (ev.type == 1 && ev.code >= 272 && ev.code <= 274 && ev.value) {
ev.code -= 272;
rob.but = ev.code ? (1<<ev.code) : 1;
}
// wheel
else if (ev.type == 2 && ev.code == 8) {
rob.wheel = ev.value;
}
else continue;
robwrite(&rob);
}
I'm only interested in buttons + wheel (not the mouse moves).
Don't worry about the codes ... 1 is for Left, 2 Right, 4 wheel buttons.
and the rob... stuff (personal). robwrite() does add that to another s_robex struct.
All of that is in a thread as read() is blocking here.
And the main prog calls asynchronously to get the latest mouse data.
Finally in order to use the prog as a simple user, added a udev rule in /etc/udev/rules.d
SUBSYSTEMS=="input", GROUP=="hehe", MODE="640"
Thanks again ewaller, that was the right direction.
Offline