Contents

Plug and Play USB Devices dengan Udev Rules

Perangkat USB yang terpasang ke komputer dengan sistem operasi GNU/Linux akan dimonitor oleh daemon dari Udev. Saya baru saja membeli sebuah USB Mouse hybrid yaitu Rexus Arka RX107 yang mendukung dual-mode di mana kita dapat menggunakannya secara nirkabel maupun berkabel. Dalam kasus ini mouse dapat terdeteksi dan digunakan secara langsung, namun ada beberapa hal yang saya butuhkan, seperti mengatur beberapa properties pada mouse. Yang saya maksud misalnya akselerasi kursor, kecepatan double-click, hingga kecepatan scroll. Konfigurasi semacam itu terkadang perlu kita adjust secara mandiri dan tidak dapat serta merta dilakukan begitu saja dari System Settings (contohnya xfce4-mouse-settings) di DE (Desktop Environment) XFCE. Terlebih saya tidak menggunakan DE, hanya Window Manager saja.

Xinput

Biasanya saya menggunakan xinput untuk melakukan konfigurasi pada properties milik mouse.

Listing

Kita dapat melihat perangkat apa saja yang terhubung seperti berikut.

1
xinput list

Dan di sini saya mempunyai beberapa perangkat input, kita akan berfokus pada perangkat yang namanya mengandung kata Wireless dan pointer karena kita membahas tentang akselerasi mouse.

1
2
3
4
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ LXDDZ 2.4G Wireless Mouse               	id=19	[slave  pointer  (2)]
⎜   ↳ LXDDZ 2.4G Wireless Mouse Consumer Control	id=12	[slave  pointer  (2)]
...

Properties

Untuk melihat properties apa saja yang mungkin dapat kita set, jalankan perintah berikut.

1
xinput list-props 19

Angka 19 adalah id dari pointer LXDDZ 2.4G Wireless Mouse. Kurang lebih outputnya seperti dibawah ini, cukup cari kata yang berhubungan dengan Speed atau Accel.

1
2
3
4
5
Device 'LXDDZ 2.4G Wireless Mouse':
...
	libinput Accel Speed (321):	0.000000
	libinput Accel Speed Default (322):	0.000000
...

Dari sini kita akan mendapatkan id dari properties Accel Speed adalah 321. Kita akan membutuhkannya untuk melakukan adjustment pada mouse.

Set Mouse Properties

Untuk memberikan value baru pada properties di atas, kita dapat menggunakan perintah berikut.

1
xinput set-prop 19 321 --type=float -0.575

Saya memberikan value sebesar -0.575 bertipe float atau pecahan, untuk menurunkan kecepatan akselerasi pada mouse. Dari sini seharusnya mouse akan terasa lebih lambat untuk digerakkan, sesuaikan dengan preferensi kalian. Kita perlu mengatur properties tersebut tiap kali mouse reconnected, tentu saja sangat melelahkan. Maka dari itu, mari membuatnya menjadi otomatis.


Deteksi USB Mouse

Saya mencoba membaca perangkat USB yang terhubung menggunakan perintah lsusb, beberapa informasi yang kita butuhkan adalah Device ID dan Vendor ID.

lsusb

Informasi terkait dapat kita dapatkan dengan perintah berikut.

1
sudo lsusb -v | grep -iE 'idproduct|idvendor'

Berikut ini adalah sebelum Mouse USB terpasang.

1
2
3
4
5
6
7
8
...
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0003 3.0 root hub
  idVendor           0x138a Validity Sensors, Inc.
  idProduct          0x0017 VFS 5011 fingerprint sensor
  idVendor           0x04ca Lite-On Technology Corp.
  idProduct          0x7035 
...

Kemudian saya menghubungkan Mouse USB, dan inilah outputnya.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
...
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0003 3.0 root hub
  idVendor           0x138a Validity Sensors, Inc.
  idProduct          0x0017 VFS 5011 fingerprint sensor
  idVendor           0x1d57 Xenta
  idProduct          0xfa60 
  idVendor           0x04ca Lite-On Technology Corp.
  idProduct          0x7035 
...

Berdasarkan output diatas, dapat kita ambil value yang baru muncul (bernama Xenta).

KeyValue
idVendor0x1d57
idProduct0xfa60

udevadm

Sekarang mari kita monitor path dari pertangkat USB yang terhubung. Tapi sebelumnya saya akan mencabut mouse terlebih dahulu, barulah menjalankan perintah berikut.

1
udevadm monitor

Setelah mouse kembali dihubungkan ke komputer, saya mendapatkan output seperti berikut.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[2977.046735] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3 (usb)
KERNEL[2977.049111] change   /devices/pci0000:00/0000:00:14.0/usb3/3-3 (usb)
KERNEL[2977.049159] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0 (usb)
KERNEL[2977.050130] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/0003:1D57:FA60.0011 (hid)
KERNEL[2977.050251] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/wakeup/wakeup25 (wakeup)
KERNEL[2977.050369] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/0003:1D57:FA60.0011/input/input44 (input)

Kita hanya perlu mencari path yang berhubungan dengan idVendor dan idProduct yang telah kita dapatkan sebelumnya. Maka kita akan menggunakan baris berikut.

1
2
KERNEL[2977.049159] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0 (usb)
KERNEL[2977.050130] add      /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/0003:1D57:FA60.0011 (hid)

Lalu kita cari informasi lebih lanjut tentang path tersebut menggunakan perintah berikut.

1
udevadm info -a -p /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0

Maka kita akan mendapatkan banyak sekali output seperti berikut.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-3':
    KERNELS=="3-3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 4"
    ATTRS{bcdDevice}=="2003"
    ATTRS{bmAttributes}=="a0"
    ATTRS{busnum}=="3"
    ATTRS{configuration}==""
    ATTRS{devnum}=="9"
    ATTRS{devpath}=="3"
    ATTRS{idProduct}=="fa60"
    ATTRS{idVendor}=="1d57"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="LXDDZ"
    ATTRS{maxchild}=="0"
    ATTRS{power/active_duration}=="553324"
    ATTRS{power/autosuspend}=="2"
    ATTRS{power/autosuspend_delay_ms}=="2000"
    ATTRS{power/connected_duration}=="553324"
    ATTRS{power/control}=="on"
    ATTRS{power/level}=="on"
    ATTRS{power/persist}=="1"
    ATTRS{power/runtime_active_time}=="553060"
    ATTRS{power/runtime_status}=="active"
    ATTRS{power/runtime_suspended_time}=="0"
    ATTRS{power/wakeup}=="enabled"
    ATTRS{power/wakeup_abort_count}=="0"
    ATTRS{power/wakeup_active}=="0"
    ATTRS{power/wakeup_active_count}=="0"
    ATTRS{power/wakeup_count}=="0"
    ATTRS{power/wakeup_expire_count}=="0"
    ATTRS{power/wakeup_last_time_ms}=="0"
    ATTRS{power/wakeup_max_time_ms}=="0"
    ATTRS{power/wakeup_total_time_ms}=="0"
    ATTRS{product}=="2.4G Wireless Mouse"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="removable"
    ATTRS{remove}=="(write-only)"
    ATTRS{rx_lanes}=="1"
    ATTRS{speed}=="12"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="22306"
    ATTRS{version}==" 1.10"

Kita dapat melihat lebih detail informasi yang tentang perangkat USB Mouse yang baru saja saya beli, untuk membuat Udev rules saya membutuhkan value dari SUBSYSTEMS pada output di atas.

1
2
3
4
5
6
...
  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-3':
    KERNELS=="3-3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
...

Value dari SUBSYSTEMS adalah usb.

Mari kita buktikan dengan langsung membuat sebuah Udev rules yang akan menciptakan sebuah symlink path pada /dev/ ketika perangkat terhubung, dan hilang saat perangkat tercabut.

1
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="1d57", ATTRS{idProduct}=="fa61", SYMLINK+="usb_mouse_rexus_wired"' | sudo tee -a /etc/udev/rules.d/83-hybrid-wireless-mouse-rexus-rx107.rules

Dengan perintah di atas, saya membuat file baru di direktori /etc/udev/rules.d yang bernama 83-hybrid-wireless-mouse-rexus-rx107.rules. Untuk format nama file pada Udev selalu diawali dengan angka yang akan menjadi nomor urut dari rules tersebut untuk dieksekusi.

Kemudian jalankan ujicoba pada path yang kita dapatkan sebelumnya.

1
sudo udevadm test -a /devices/pci0000:00/0000:00:14.0/usb3/3-3

Jika Udev rules berhasil, maka kita akan mendapatkan output seperti berikut.

1
2
3
4
5
6
7
8
9
...
Reading rules file: /etc/udev/rules.d/83-hybrid-wireless-mouse-rexus-rx107.rules
...
3-3: /etc/udev/rules.d/83-hybrid-wireless-mouse-rexus-rx107.rules:6 LINK 'usb_mouse_rexus_wireless'
...
ID_VENDOR_ID=1d57
ID_MODEL_ID=fa60
DEVLINKS=/dev/usb_mouse_rexus_wireless
...

Periksa juga apakah symlink telah terbuat di direktori /dev/.

1
2
$ ls -l /dev/usb_mouse_rexus_wireless
lrwxrwxrwx 1 root root 15 Jan 21 20:24 /dev/usb_mouse_rexus_wireless -> bus/usb/003/009

Dan saat mouse dicabut, symlink tersebut akan hilang.

1
2
ls -l /dev/usb_mouse_rexus_wireless
ls: cannot access '/dev/usb_mouse_rexus_wireless': No such file or directory

Plug And Play

Sebenarnya menggunakan istilah PnP atau Plug and Play kurang tepat, karena mouse langsung dapat digunakan tanpa perlu memasang driver dan sebagainya. Hanya saja, seperti yang saya tulis sebelumnya bahwa konfigurasi properties pada mouse perlu tidaklah permanen. Artinya saya perlu melakukannya setiap kali reconnecting mouse, namun terimakasih kepada udev dan shell script sederhana yang akan melakukannya secara otomatis.

Udev rules

Sebelumnya kita telah mencoba membuat rules untuk path symlink, kali ini kita akan menambahkan beberapa baris rules lagi untuk mengeksekusi sebuah shell script yang berisi perintah xinput untuk konfigurasi properties pada mouse.

1
2
3
4
5
6
7
# Wired
SUBSYSTEM=="usb", ATTRS{idVendor}=="1d57", ATTRS{idProduct}=="fa61", SYMLINK+="usb_mouse_rexus_wired"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1d57", ATTRS{idProduct}=="fa61", ENV{DISPLAY}=":0.0", ENV{XAUTHORITY}="/home/pwn3r/.Xauthority", RUN+="/usr/local/bin/set-prop-rexus-mouse"

# Wireless
SUBSYSTEM=="usb", ATTRS{idVendor}=="1d57", ATTRS{idProduct}=="fa60", SYMLINK+="usb_mouse_rexus_wireless"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1d57", ATTRS{idProduct}=="fa60", ENV{DISPLAY}=":0.0", ENV{XAUTHORITY}="/home/pwn3r/.Xauthority", RUN+="/usr/local/bin/set-prop-rexus-mouse"

Kenapa saya membuat dua symlink dan terdapat dua idProduct yang berbeda? Hal ini karena ketika mouse mempunyai dual-mode, yang ternyata memiliki idProduct berbeda saat dioperasikan secara nirkabel ataupun berkabel.

Lalu kita dapat melihat ACTION=="add" yang artinya rules akan mulai menjalankan RUN saat mendeteksi action berupa add pada atribut yang sesuai dengan SUBSYSTEM, idVendor dan idProduct. Sementara ENV adalah environment variable yang akan dilewatkan ketika RUN dieksekusi, hal ini diperlukan karena perintah xinput pada shell script akan dieksekusi oleh sistem (root). Maka udev perlu tahu mana user yang dimaksud, dan mana letak sesi display manager user tersebut.

Selanjutnya muat ulang Udev rules yang telah kita buat supaya daemon akan menerapkannya.

1
sudo udevadm control --reload

Response

Dari sini kita akan melakukan sedikit shell scripting, kurang lebih seperti berikut.

1
2
3
4
5
6
7
#!/usr/bin/bash

export DISPLAY=${DISPLAY}
export HOME=/home/pwn3r
export XAUTHORITY=$HOME/.Xauthority

/usr/local/bin/set-prop-rexus-mouse-worker &

Namun file tersebut tidak akan menjalankan perintah xinput. Karena mouse belum terdeteksi pada xinput list ketika Udev rules pertama kali dieksekusi. Maka kita akan memanggil shell script lain di background seperti berikut.

1
2
3
4
5
6
7
8
#!/usr/bin/bash

sleep 2

for i in $(xinput list | grep -i "LXDDZ 2.4G Wireless Mouse" | grep -iEv "Consumer|Control|keyboard" | sed -e 's/^.*id=\([0-9]*.\).*$/\1/')
do 
    xinput set-prop $i 321 --type=float -0.6
done
Perhatian
Perhatikan argumen dari perintah grep di atas, kita perlu menyesuaikannya untuk mendapatkan id dari perangkat yang terdeteksi oleh xinput list. Artinya setiap perangkat memiliki karakteristik yang berbeda, dan silahkan bermain-main untuk mencari value yang sesuai dengan perangkat kalian.

Saya menyimpan kedua file shell script tersebut ke direktori /usr/local/bin dan jangan lupa tambahkan executable permission.

1
2
sudo chmod +x /usr/local/bin/set-prop-rexus-mouse.sh
sudo chmod +x /usr/local/bin/set-prop-rexus-mouse-worker.sh

Dari sini kita dapat memicu Udev rules dengan perintah berikut. Atau sederhana saja, cukup cabut dan hubungkan kembali mouse. Maka kedua shell script tersebut akan dieksekusi oleh Udev rules.

1
sudo udevadm trigger -c add

Kesimpulan

Sebenarnya udev tidak terlalu rumit untuk digunakan, hanya sedikit susah dalam hal debug perangkat. Faktanya udev juga dapat digunakan untuk berbagai macam perangkat dengan interface lain seperti SCSI, SATA/eSATA, PCI, hingga VGA dan HDMI. Jadi tidak untuk USB saja, udev dipakai oleh sistem operasi untuk handling berbagai peripheral yang terhubung ke komputer.


Referensi