Zobrazují se příspěvky se štítkemLinux. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemLinux. Zobrazit všechny příspěvky

čtvrtek 3. července 2025

Build Linux pro RPi

 Instalovat:

sudo apt update
sudo apt install build-essential git cpio unzip rsync bc libncurses5-dev libssl-dev

Naklonovat repozitář:

git clone https://github.com/buildroot/buildroot.git
cd buildroot

Zkopírovat vzorový konfig pro RPi4

cp configs/raspberrypi4_64_defconfig .config

Upravit dle potřeby:

make menuconfig

vyřešit problém s mezerami v PATH:

#!/bin/bash
export PATH="/usr/local/bin:/usr/bin:/bin" # základní cesty bez mezer

Přeložit a čekat

make -j 6 # počet jader CPU pro kompilaci

Výsledný obraz nalezneme v output/images/sdcard.img

sudo dd if=output/images/sdcard.img of=/dev/sdX bs=4M status=progress && sync

Nyní vytvoříme helloword a pokusíme se ho spustit

nano hello.c
./buildroot/output/host/bin/aarch64-linux-gcc -o hello hello.c

#include <stdio.h> void main() { printf("Funguje to!\n"); }

pátek 3. ledna 2025

Přidání nového modulu do jádra a Device Tree na Raspberry Pi

V tomto článku se podíváme na proces přidání nového modulu do linuxového jádra na Raspberry Pi a jeho konfiguraci pomocí Device Tree (DT). Ukážeme si konkrétní příklad s EEPROM pamětí připojenou přes I2C sběrnici.


1. Stažení a příprava modulu

Nejprve stáhneme zdrojový kód ovladače z repozitáře Linuxu. Použijeme EEPROM ovladač at24:

wget https://raw.githubusercontent.com/torvalds/linux/refs/tags/v6.6/drivers/misc/eeprom/at24.c

Tento ovladač slouží k práci s paměťmi EEPROM přes sběrnici I2C. Zajišťuje správu komunikace mezi jádrem systému a zařízením připojeným přes I2C.


2. Vytvoření Makefile

Makefile definuje pravidla pro kompilaci modulu. Vytvořte soubor s názvem Makefile s následujícím obsahem:

obj-m += at24.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Popis obsahu Makefile:

  • obj-m += at24.o: Určuje, že chceme sestavit modul at24.
  • all: Používá se pro sestavení modulu pomocí Makefile. Spustí se příkaz pro kompilaci modulu ve správném adresáři jádra.
  • clean: Smaže dočasné soubory vytvořené během kompilace.

Pro spuštění kompilace použijte:

make

Výstupem bude soubor at24.ko, což je zkompilovaný modul jádra.


3. Vytvoření Device Tree pro I2C zařízení

Device Tree (DT) je systémová konfigurace, která popisuje hardwarová zařízení. Pro konfiguraci EEPROM pamětí vytvoříme soubor at24.dts s následujícím obsahem:

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835";

    fragment@0 {
        target = <&i2c1>;  // Použití I2C-1
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;

            EEPROM1@50 {  // první EEPROM
                compatible = "at24,24c02";  // Typ EEPROM
                reg = <0x50>;               // Adresa na I2C sběrnici
                pagesize = <16>;            // Velikost stránky
                size = <256>;               // Celková velikost EEPROM
            };
            EEPROM2@57 {  // druhá EEPROM
                compatible = "at24,24c02";
                reg = <0x57>;               // Adresa na I2C sběrnici
                pagesize = <16>;
                size = <256>;
            };
        };
    };
};

Vysvětlení obsahu souboru:

  • compatible = "brcm,bcm2835";: Specifikuje, že konfigurace je určena pro BCM2835 (Raspberry Pi SoC).
  • reg = <0x50>;: Specifikuje skutečnou adresu zařízení na I2C sběrnici, která bude jádrem použita ke komunikaci se zařízením.
  • pagesize a size: Definují parametry paměti EEPROM.

4. Kompilace Device Tree

Pro převedení souboru na binární formát použijeme nástroj:

dtc -I dts -O dtb -o at24.dtbo at24.dts

Tímto příkazem vznikne binární soubor at24.dtbo, který je připraven pro použití.

Nahrání overlay:

Zkopírujeme výsledný soubor do adresáře s DT overlays:

sudo cp at24.dtbo /boot/firmware/overlays/

Přidáme overlay do konfiguračního souboru:

echo 'dtoverlay=at24' | sudo tee -a /boot/firmware/config.txt

5. Testování EEPROM

Zápis dat do EEPROM:

Pro otestování funkce EEPROM můžeme zapsat řetězec do paměti:

echo "Zapis do I2C EEPROM" | sudo dd of=/sys/bus/i2c/devices/1-0057/eeprom bs=1 seek=0

Čtení dat z EEPROM:

Následně ověříme zápis čtením obsahu EEPROM:

sudo hexdump -C /sys/bus/i2c/devices/1-0057/eeprom

Ukázkový výstup:

00000000  5a 61 70 69 73 20 64 6f  20 49 32 43 20 45 45 50  |Zapis do I2C EEP|
00000010  52 4f 4d 0a 01 00 0f 00  00 00 00 14 0f 14 2d 10  |ROM...........-.|

sobota 28. ledna 2023

VLANy

Když je potřeba do jednoho kabelu dát dva a více ethernetů. :-) Vytvoříme VLAN.

Příklad PC + RPi:

RPi zakomentovat /etc/network/interface.d/eth0

vytvořit /etc/network/interface.d/vlan

auto eth0.10
iface eth0.10 inet static
 address 192.168.1.195
 netmask 255.255.255.0

 na druhé straně podobně: 

 auto eth0.10
iface eth0.10 inet static
 address 192.168.1.195
 netmask 255.255.255.0

Výpis ip addr:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether b8:27:eb:7d:d1:76 brd ff:ff:ff:ff:ff:ff
3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether 36:1c:f9:d9:85:ae brd ff:ff:ff:ff:ff:ff permaddr b8:27:eb:28:84:23
7: eth0.10@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:7d:d1:76 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.195/24 brd 192.168.1.255 scope global secondary eth0.10
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:fe7d:d176/64 scope link 
       valid_lft forever preferred_lft forever
8: eth0.1@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:7d:d1:76 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.191/24 brd 192.168.1.255 scope global eth0.1
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:fe7d:d176/64 scope link 
       valid_lft forever preferred_lft forever

Příklad logu komunikace:



čtvrtek 11. srpna 2022

AT - plánování v Linuxu

 Pro plánování jednorázových útolů je možné využít AT.

takto naplánujeme spuštění  "curl --user username:heslo http://<IP>/settings/relay/0?schedule=1" na 14.8.2022 15:00 zadáme následující:

echo "curl --user username:heslo http://<IP>/settings/relay/0?schedule=1" | at -t 2208141500

Nebo pomocí interaktivního režimu:

Zadávání skriptu se ukončí stiskem CTRL+D, zruší stiskem CTRL+C.

Naplánované úlohy se zobrazí takto:




středa 11. května 2022

mdadm

 cat /proc/mdstat #status

mdadm --detail /dev/md0 # také status

mdadm --create /dev/md0 -n2 -l1 /dev/sda1 /dev/sdb1 # vytvoření nového pole z sda1 a sda2

mdadm --add /dev/md0 /dev/sdc1 # přidání sdc1 do pole

mdadm --detail --scan # zobrazení parametrů pole

Pokud se pole rozpadne, tak to poznáme takto:

root@MB:~# mdadm --detail /dev/md1 # také status
/dev/md1:
           Version : 1.2
     Creation Time : Thu May  5 16:24:29 2022
        Raid Level : raid1
        Array Size : 4882680832 (4656.49 GiB 4999.87 GB)
     Used Dev Size : 4882680832 (4656.49 GiB 4999.87 GB)
      Raid Devices : 2
     Total Devices : 1
       Persistence : Superblock is persistent
 
     Intent Bitmap : Internal
 
       Update Time : Sun Nov 27 11:48:42 2022
             State : clean, degraded
    Active Devices : 1
   Working Devices : 1
    Failed Devices : 0
     Spare Devices : 0
 
Consistency Policy : bitmap
 
              Name : MB.JFila.cz:1  (local to host MB.JF)
              UUID : db6464ea:3b6ac1a1:3a3f26ec:20cb5e65
            Events : 70585
 
    Number   Major   Minor   RaidDevice State
       -       0        0        0      removed
       1       8       17        1      active sync   /dev/sdb1

Nejprve si zjistíme, který disk vypadl:

root@MB:~# blkid  | grep MB.JFil
/dev/sda1: UUID="db6464ea-3b6a-c1a1-3a3f-26ec20cb5e65" UUID_SUB="f85690c7-00b4-bdaf-9678-ba49025766ce" LABEL="MB.JF:1" TYPE="linux_raid_member" PARTUUID="8e221fd9-1b67-4b6c-8dad-6fb1f6a3e420"
/dev/sdb1: UUID="db6464ea-3b6a-c1a1-3a3f-26ec20cb5e65" UUID_SUB="3af1ed68-00dd-c355-40cf-ad836f0a3647" LABEL="MB.JF:1" TYPE="linux_raid_member" PARTUUID="d3360b04-a4f3-764c-82ec-da41c5dd5d30"

a druhý HDD přidáme následujícím příkazem:

root@MB:~# mdadm /dev/md1 -a /dev/sda1

mdadm: re-added /dev/sda1
root@MB:~# mdadm --detail /dev/md1 # také status
/dev/md1:
           Version : 1.2
     Creation Time : Thu May  5 16:24:29 2022
        Raid Level : raid1
        Array Size : 4882680832 (4656.49 GiB 4999.87 GB)
     Used Dev Size : 4882680832 (4656.49 GiB 4999.87 GB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent
     Intent Bitmap : Internal
       Update Time : Sun Nov 27 11:52:39 2022
             State : clean, degraded, recovering
    Active Devices : 1
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 1
Consistency Policy : bitmap
    Rebuild Status : 2% complete
              Name : MB.JFila.cz:1  (local to host MB.JF)
              UUID : db6464ea:3b6ac1a1:3a3f26ec:20cb5e65
            Events : 70587
    Number   Major   Minor   RaidDevice State
       3       8        1        0      spare rebuilding   /dev/sda1
       1       8       17        1      active sync   /dev/sdb1

A nyní již probíhá obnova:

root@MB:~# cat /proc/mdstat #status
Personalities : [linear] [raid0] [raid1] [raid10] [raid6] [raid5] [raid4] [multipath]
md1 : active raid1 sda1[3] sdb1[1]
      4882680832 blocks super 1.2 [2/1] [_U]
      [>....................]  recovery =  2.9% (144065984/4882680832) finish=453.6min speed=174080K/sec
      bitmap: 27/37 pages [108KB], 65536KB chunk

A hotovo, vše ok:
root@MB:~# mdadm --detail /dev/md1 # také status
/dev/md1:
           Version : 1.2
     Creation Time : Thu May  5 16:24:29 2022
        Raid Level : raid1
        Array Size : 4882680832 (4656.49 GiB 4999.87 GB)
     Used Dev Size : 4882680832 (4656.49 GiB 4999.87 GB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent

     Intent Bitmap : Internal

       Update Time : Sun Nov 27 11:56:15 2022
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : bitmap

              Name : MB.JFila.cz:1  (local to host MB.JF)
              UUID : db6464ea:3b6ac1a1:3a3f26ec:20cb5e65
            Events : 70639

    Number   Major   Minor   RaidDevice State
       3       8        1        0      active sync   /dev/sda1
       1       8       17        1      active sync   /dev/sdb1

středa 11. dubna 2018

USB Blaster + OpenOCD a STM32





root@Jenda:/usr/local/share/openocd# openocd -f interface/altera-usb-blaster.cfg  \
> -c "transport select jtag"  \
> -f target/stm32f3x.cfg
Open On-Chip Debugger 0.10.0+dev-00362-g78a44055 (2018-03-27-17:48)
Licensed under GNU GPL v2
For bug reports, read
 http://openocd.org/doc/doxygen/bugs.html
Warn : Adapter driver 'usb_blaster' did not declare which transports it allows; assuming legacy JTAG-only
Info : only one transport option; autoselect 'jtag'
Warn : Transport "jtag" was already selected
jtag
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
none separate
cortex_m reset_config sysresetreq
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : usb blaster interface using libftdi
Info : This adapter doesn't support configurable speed
Info : JTAG tap: stm32f3x.cpu tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x4)
Info : JTAG tap: stm32f3x.bs tap/device found: 0x06422041 (mfg: 0x020 (STMicroelectronics), part: 0x6422, ver: 0x0)
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444
Error: Translation from khz to jtag_speed not implemented
in procedure 'reset' 
in procedure 'ocd_bouncer' 
in procedure 'ocd_process_reset' 
in procedure 'ocd_process_reset_inner' called at file "embedded:startup.tcl", line 248
in procedure 'stm32f3x.cpu' called at file "embedded:startup.tcl", line 286
in procedure 'ocd_bouncer'

Info : JTAG tap: stm32f3x.cpu tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x4)
Info : JTAG tap: stm32f3x.bs tap/device found: 0x06422041 (mfg: 0x020 (STMicroelectronics), part: 0x6422, ver: 0x0)
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800045c msp: 0x20000408
===== arm v7m registers
(0) r0 (/32): 0x00000000
(1) r1 (/32): 0x00000000
(2) r2 (/32): 0x00000000
(3) r3 (/32): 0x00000000
(4) r4 (/32): 0x00000000
(5) r5 (/32): 0x00000000
(6) r6 (/32): 0x00000000
(7) r7 (/32): 0x00000000
(8) r8 (/32): 0x00000000
(9) r9 (/32): 0x00000000
(10) r10 (/32): 0x00000000
(11) r11 (/32): 0x00000000
(12) r12 (/32): 0x00000000
(13) sp (/32): 0x20000408
(14) lr (/32): 0xFFFFFFFF
(15) pc (/32): 0x0800045C
(16) xPSR (/32): 0x01000000
(17) msp (/32): 0x20000408
(18) psp (/32): 0x00000000
(19) primask (/1): 0x00
(20) basepri (/8): 0x00
(21) faultmask (/1): 0x00
(22) control (/2): 0x00
(23) d0 (/64): 0x0000000000000000
(24) d1 (/64): 0x0000000000000000
(25) d2 (/64): 0x0000000000000000
(26) d3 (/64): 0x0000000000000000
(27) d4 (/64): 0x0000000000000000
(28) d5 (/64): 0x0000000000000000
(29) d6 (/64): 0x0000000000000000
(30) d7 (/64): 0x0000000000000000
(31) d8 (/64): 0x0000000000000000
(32) d9 (/64): 0x0000000000000000
(33) d10 (/64): 0x0000000000000000
(34) d11 (/64): 0x0000000000000000
(35) d12 (/64): 0x0000000000000000
(36) d13 (/64): 0x0000000000000000
(37) d14 (/64): 0x0000000000000000
(38) d15 (/64): 0x0000000000000000
(39) fpscr (/32): 0x00000000
===== Cortex-M DWT registers
(40) dwt_ctrl (/32)
(41) dwt_cyccnt (/32)
(42) dwt_0_comp (/32)
(43) dwt_0_mask (/4)
(44) dwt_0_function (/32)
(45) dwt_1_comp (/32)
(46) dwt_1_mask (/4)
(47) dwt_1_function (/32)
(48) dwt_2_comp (/32)
(49) dwt_2_mask (/4)
(50) dwt_2_function (/32)
(51) dwt_3_comp (/32)
(52) dwt_3_mask (/4)
(53) dwt_3_function (/32)
https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_usb_blstr.pdf

neděle 25. března 2018

Reverzní inženýrství

Začalo to pokusem zprovoznit JTAG pod OpenOCD. S ASIX Presto jsem si s touto kombinací vylámal zuby už dávno ale s RaspberryPi 3 by to mohlo jít.

Nejprve je nutné OpenOCD pro RaspberryPi stáhnout a přeložit (tak například takto):

git clone git://git.code.sf.net/p/openocd/code openocd-code

Dále je potřeba v konfiguraci povolit veškeré požadované rozhraní (hlavně --enable-sysfsgpio --enable-bcm2835gpio ale FTDIčko také není na závadu)

./bootstrap
./configure

A potom už jen make a nainstalovat,

make
sudo make install

všechny potřebné skripty pro jeho používání nalezneme v /usr/local/share/openocd/scripts/

Nyní již stačí správně propojit drátky, kdo má drátků málo, tak použije SWD (SWDIO, SWDCLK, GND) kdo má drátků hodně nebo tak akorát může použít JTAG (TCK, TMS, TDI, TDO, TRST, SRST).

Pro RaspberryPi 3 jsem použil soubor s konfigurací raspberrypi2-native.cfg, zde je možné zvolit zda JTAG nebo SWD.

Po drobném laborování jsem si udělal upravil soubor raspberrypi2.cfg, tak aby bylo možné použít jedno nebo druhé se stejným zapojením:

#
# Config for using Raspberry Pi's expansion header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, pin 6 of the expansion header.
#

interface bcm2835gpio

#RPi2 & RPi3
bcm2835gpio_peripheral_base 0x3F000000
#RPi1
#bcm2835gpio_peripheral_base 0x20000000

# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on system clock, calibrated for stock 700MHz
# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET
#RPi2 & RPi3
bcm2835gpio_speed_coeffs 146203 36
#RPi1
#bcm2835gpio_speed_coeffs 113714 28

# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 22 19 21
bcm2835gpio_jtag_nums 11 25 10 9

# or if you have both connected,
# reset_config trst_and_srst srst_push_pull

# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 22
bcm2835gpio_swd_nums 11 25

# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18

bcm2835gpio_trst_num 7
# reset_config trst_only

bcm2835gpio_srst_num 18
#reset_config srst_only srst_push_pull

# or if you have both connected,
reset_config trst_and_srst srst_push_pull

OpenOCD spustíme příkazem (pozor na pořadí parametrů):

sudo openocd -f interface/raspberrypi2-native.cfg -c "transport select swd" -f target/stm32f3x.cfg
nebo
sudo openocd -f interface/raspberrypi2-native.cfg -c "transport select jtag" -f target/stm32f3x.cfg

A už nám OpenOCD pěkně čeká na spojení (pozor na Discavery Boardech je třeba odpojit piny STLinku a někdy i tahá za další, takže odpojení a připojení napájení destičky vždy pomohlo).


Po připojení většinou procesor běží, je nutné ho zastavit příkazem:
reset halt

a nyní již můžeme vyčíst registry:


Dále si můžeme nechat zobrazit paměť (šuf obsah FLASH).


Dále se zeptáme na paměťové banky - ověříme si, že FLASH je zde namapována od adresy 0x08000000


A stáhneme si obsah flash paměti





a když už máme FW, tak co se takhle do něho podívat? Využil jsem to jako první seznámení s radare2:

ToDo:

pohrát si s binwalk, nejlépe si vyčíst FW z OpenWRT routeru.
https://www.youtube.com/watch?v=GIU4yJn2-2A
https://www.youtube.com/watch?v=8dXhrOEGHTY
https://www.youtube.com/watch?v=oXSx0Qo2Upk

Jinak OpenOCD bylo nutné přeložit, pro Presto je potřeba ještě přeložit také knihovnu libftdi a potom už svatá trojka.

nebo libftdi je možné nainstalovat sudo apt-get install libusb-1.0 libusb-dev a změnit --prefix na "--prefix=/usr/"

./configure \
--enable-ftdi \
--enable-stlink \
--enable-ti-icdi \
--enable-ulink \
--enable-dummy \
--enable-usb-blaster-2 \
--enable-jlink \
--enable-osbdm \
--enable-opendous \
--enable-aice \
--enable-vsllink \
--enable-usbprog \
--enable-rlink \
--enable-armjtagew \
--enable-parport \
--enable-jtag_vpi \
--enable-usb_blaster_libftdi \
--enable-amtjtagaccel \
--enable-gw16012 \
--enable-ep93xx \
--enable-presto_libftdi \
--enable-openjtag_ftdi \
--enable-buspirate \
--enable-sysfsgpio \
--enable-arm-jtag-ew \
--enable-bcm2835gpio \
--enable-at91rm9200 \
--enable-ft2232_libftdi \
--enable-parport-ppdev \
--enable-parport-giveio \
--enable-remote-bitbang \
--prefix=/home/pi/libftdi1-1.4/libftdi1-1.4/
make
make install

https://pinout.xyz/

pondělí 14. března 2016

Bulid jaderného balíčku pro hwmon

Nejprve je třeba naklonovat verzi OpenWRT pro aktuálně používané jádro. Pomocí příkazu git tag, se nám zobrazí seznam "otagovaných" verzí. Pro verzi Turris OS 2.8 je to vyznačené vydání deploy-2015-12-18.

$ git tag
deploy-2014-04-24
deploy-2015-11-25
deploy-2015-12-18
gen-certuma-0.v1
gen-certuma-0.v2
hotfix-2015-08-18
upstream-merge-2014-06-27

A když už máme představu, jakou verzi požadujeme, tak si ji prostřednictvím checkout můžeme stáhnout.


git checkout deploy-2015-12-18

Nyní necháme jádro přeložit, tak aby se nám stáhly všechny zdroje. Při tvorbě balíčku jsem vycházel z kmod-hwmon-sht21, ten je nutné povolil v make menuconfig (podmenu Kernel modules -> Hardware Monitoring Support).

Soubor příkladu by měl pro jedno zařízení vytvořit dva virtuální soubory, které při čtení vrací inkrementující se hodnoty, viz následující soubor pokus.c.

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/jiffies.h>

/**
* struct pokus - pokus device specific data
* @hwmon_dev: device registered with hwmon
* @lock: mutex to protect measurement values
* @valid: only 0 before first measurement is taken
* @last_update: time of last update (jiffies)
* @number1:
* @number2:
*/
struct pokus
{
        struct device *hwmon_dev;
        struct mutex lock;
        char valid;
        unsigned long last_update;
        int number1;
        int number2;
};

/**
* pokus_show_number1() - return value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
*
* Will be called on read access to number1 sysfs attribute.
* Returns number of bytes written into buffer, negative errno on error.
*/
static ssize_t pokus_show_number1(struct device *dev, struct device_attribute *attr, char *buf)
{
        struct pokus *pokus = dev_get_drvdata(dev);
        /*int ret;

        ret = pokus_update_measurements(dev);
        if (ret < 0) return ret;*/
        return sprintf(buf, "%d\n", pokus->number1++);
}

/**
* pokus_show_number2() - return value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
*
* Will be called on read access to number1 sysfs attribute.
* Returns number of bytes written into buffer, negative errno on error.
*/
static ssize_t pokus_show_number2(struct device *dev, struct device_attribute *attr, char *buf)
{
        struct pokus *pokus = dev_get_drvdata(dev);
        /*int ret;

        ret = pokus_update_measurements(dev);
        if (ret < 0) return ret;*/
        return sprintf(buf, "%d\n", pokus->number2++);
}

/* sysfs attributes */
static SENSOR_DEVICE_ATTR(number1, S_IRUGO, pokus_show_number1,
        NULL, 0);
static SENSOR_DEVICE_ATTR(number2, S_IRUGO, pokus_show_number2,
        NULL, 0);

static struct attribute *pokus_attributes[] =
{
        &sensor_dev_attr_number1.dev_attr.attr,
        &sensor_dev_attr_number2.dev_attr.attr,
        NULL
};

static const struct attribute_group pokus_attr_group = {
        .attrs = pokus_attributes,
};

static int pokus_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
{
        struct pokus *pokus;
        int err;

        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
        {
                dev_err(&client->dev, "adapter does not support SMBus word transactions\n");
                return -ENODEV;
        }

        pokus = devm_kzalloc(&client->dev, sizeof(*pokus), GFP_KERNEL);
        if (!pokus) return -ENOMEM;

        i2c_set_clientdata(client, pokus);

        mutex_init(&pokus->lock);

        err = sysfs_create_group(&client->dev.kobj, &pokus_attr_group);
        if (err) {
                dev_dbg(&client->dev, "could not create sysfs files\n");
                return err;
        }
        pokus->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(pokus->hwmon_dev)) {
                dev_dbg(&client->dev, "unable to register hwmon device\n");
                err = PTR_ERR(pokus->hwmon_dev);
                goto fail_remove_sysfs;
        }

        dev_info(&client->dev, "initialized\n");

        return 0;

fail_remove_sysfs:
        sysfs_remove_group(&client->dev.kobj, &pokus_attr_group);
        return err;

}

/**
 * pokus_remove() - remove device
 * @client: I2C client device
 */
static int pokus_remove(struct i2c_client *client)
{
        struct pokus *pokus = i2c_get_clientdata(client);

        hwmon_device_unregister(pokus->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &pokus_attr_group);

        return 0;
}

/* Device ID table */
static const struct i2c_device_id pokus_id[] =
{
        { "pokus", 0 },
        { }
};
MODULE_DEVICE_TABLE(i2c, pokus_id);

static struct i2c_driver pokus_driver =
{
        .driver.name = "pokus",
        .probe       = pokus_probe,
        .remove      = pokus_remove,
        .id_table    = pokus_id,
};

module_i2c_driver(pokus_driver);

MODULE_AUTHOR("JFila <jfila@xxx.cz>");
MODULE_DESCRIPTION("Pokus driver");
MODULE_LICENSE("GPL");



Do Kconfig doplnit následující definici (build_dir/target-powerpc_8540_uClibc-0.9.33.2/linux-mpc85xx_p2020-nand/linux-3.10.49/drivers/hwmon/Kconfig)

config SENSORS_POKUS
tristate "JFíla pokus driver."
depends on GPIOLIB
help
Pokusný balíček pro hwmon

Do Makefile (build_dir/target-powerpc_8540_uClibc-0.9.33.2/linux-mpc85xx_p2020-nand/linux-3.10.49/drivers/hwmon/Makefile) přidat binárku s názvem balíčku (pokus.o)

obj-$(CONFIG_SENSORS_POKUS) += pokus.o

A hwmon.mk také doplnit popis balíčku a jeho závislostí. (package/kernel/linux/modules/hwmon.mk)

define KernelPackage/hwmon-pokus
  TITLE:=pokus device for test
  KCONFIG:=CONFIG_SENSORS_POKUS
  FILES:=$(LINUX_DIR)/drivers/hwmon/pokus.ko
  AUTOLOAD:=$(call AutoProbe,pokus)
  $(call AddDepends/hwmon,+kmod-i2c-core)
endef

define KernelPackage/hwmon-pokus/description
 Kernel module for pokus device (for test only)
endef

$(eval $(call KernelPackage,hwmon-pokus))

Hotový modul můžeme instalovat jako balíček ale pozor na hash jádra, pro otestování stačí pokus.ko nakopírovat do /lib/modules/3.10.49-xxxxx

Zavedeme modul do jádra a je to:

root@JFila:/# insmod pokus.ko
root@JFila:/# lsmod | grep pokus
hwmon                    990  3 pokus
pokus                   1468  0

Nyní by již mělo stačit vytvořit nové zařízení:

root@JFila:/# echo pokus 0x27 > /sys/bus/i2c/devices/i2c-1/new_device
root@JFila:/# cd /sys/bus/i2c/devices/
0-004c/  0-006f/  1-0027/  1-0040/  i2c-0/   i2c-1/   i2c-2/
root@JFila:/# cd /sys/bus/i2c/devices/1-0027/
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# ls
driver     hwmon      modalias   name       number1    number2    power      subsystem  uevent

A čtením number jedna bychom měli získávat inkrementující hodnotu:

root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
0
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
1
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
2
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
3

https://blog.root.cz/posvic/jak-napsat-ovladac-pro-zarizeni-usb-pro-linux/