├── Chapter02 └── library │ ├── README │ ├── hello-arm │ ├── Makefile │ └── hello-arm.c │ ├── inc │ └── testlib.h │ ├── shared │ ├── Makefile │ └── testlib.c │ └── static │ ├── Makefile │ └── testlib.c ├── Chapter03 ├── 0001-BSP-for-Nova.patch └── simpledts-1.dts ├── Chapter04 ├── build-linux-rpi4.sh └── nova.dts ├── Chapter05 ├── device-tables.txt └── run-qemu-initramfs.sh ├── Chapter06 ├── buildroot │ ├── board │ │ └── meld │ │ │ └── nova │ │ │ ├── genimage.cfg │ │ │ ├── linux.config │ │ │ ├── nova.dts │ │ │ └── post-image.sh │ ├── configs │ │ └── nova_defconfig │ └── package │ │ ├── Config.in │ │ └── helloworld │ │ ├── Config.in │ │ └── helloworld.mk ├── helloworld │ ├── Makefile │ └── helloworld.c └── meta-nova │ ├── README │ ├── conf │ └── layer.conf │ └── recipes-local │ ├── helloworld │ ├── files │ │ └── helloworld.c │ └── helloworld_1.0.bb │ └── images │ └── nova-image.bb ├── Chapter07 ├── meta-gattd │ ├── README │ ├── conf │ │ └── layer.conf │ └── recipes-gattd │ │ └── gattd │ │ └── gattd_0.1.bb └── meta-mackerel │ ├── COPYING.MIT │ ├── README │ └── conf │ ├── distro │ └── mackerel.conf │ └── layer.conf ├── Chapter10 └── meta-ota │ ├── COPYING.MIT │ ├── README │ ├── conf │ └── layer.conf │ └── recipes-core │ └── base-files │ └── base-files_%.bbappend ├── Chapter11 └── meta-device-drivers │ ├── COPYING.MIT │ ├── README │ ├── conf │ └── layer.conf │ ├── recipes-kernel │ └── dummy-driver │ │ ├── dummy-driver_1.0.bb │ │ └── files │ │ ├── Makefile │ │ └── dummy.c │ └── recipes-local │ ├── gpio-int │ ├── files │ │ ├── config-gpio.sh │ │ └── gpio-int.c │ └── gpio-int_1.0.bb │ ├── i2c-eeprom-read │ ├── files │ │ └── i2c-eeprom-read.c │ └── i2c-eeprom-read_1.0.bb │ ├── read-urandom │ ├── files │ │ └── read-urandom.c │ └── read-urandom_1.0.bb │ └── show-mac-address │ ├── files │ └── show-mac-address.c │ └── show-mac-address_1.0.bb ├── Chapter12 ├── display.py ├── parse_nmea.py └── sensors.py ├── Chapter13 ├── simpleserver-systemd │ └── simpleserver.service ├── simpleserver-sysvinit │ └── init.d │ │ └── simpleserver └── simpleserver │ ├── Makefile │ └── simpleserver.c ├── Chapter14 ├── cpufrequtils └── do-work │ ├── Makefile │ └── do-work.c ├── Chapter15 ├── conda │ └── my-environment.yaml └── setuptools │ └── setup.py ├── Chapter16 ├── build-rpi │ └── conf │ │ └── local.conf └── gattd │ ├── Dockerfile │ └── main.yml ├── Chapter17 ├── condvar-demo │ ├── Makefile │ └── condvar-demo.c ├── exec-demo │ ├── Makefile │ └── exec-demo.c ├── fork-demo │ ├── Makefile │ └── fork-demo.c ├── shared-mem-demo │ ├── Makefile │ └── shared-mem-demo.c ├── thread-demo │ ├── Makefile │ └── thread-demo.c └── zeromq │ ├── client.py │ ├── coroutines.py │ ├── planets.sh │ └── server.py ├── Chapter18 ├── mtrace-example │ ├── Makefile │ └── mtrace-example.c └── pagefault-demo │ ├── Makefile │ └── pagefault-demo.c ├── Chapter19 ├── buildroot │ ├── configs │ │ └── rpi4_64_gdb_defconfig │ └── package │ │ ├── Config.in │ │ ├── mbx-driver-oops │ │ ├── Config.in │ │ └── mbx_driver.mk │ │ └── mbx-driver │ │ ├── Config.in │ │ └── mbx_driver.mk ├── mbx-driver-oops │ ├── Makefile │ └── mbx.c ├── mbx-driver │ ├── Makefile │ └── mbx.c └── tp.py ├── Chapter20 └── buildroot │ ├── board │ └── raspberrypi │ │ └── linux_defconfig_4_64bit │ ├── configs │ ├── rpi4_64_lttng_defconfig │ └── rpi4_64_ply_defconfig │ └── package │ ├── Config.in │ └── ebpf │ ├── Config.in │ ├── count-syscalls.ply │ ├── ebpf.mk │ ├── fstab │ ├── heap-allocs.ply │ ├── i2c-stack.ply │ ├── opensnoop.ply │ ├── read-dist.ply │ ├── self-test.sh │ ├── tcp-send-recv.ply │ └── test.sh ├── LICENSE ├── README.md ├── format-sdcard.sh └── list-libs /Chapter02/library/README: -------------------------------------------------------------------------------- 1 | This is a demonstration of writing and linking shared and static libraries. 2 | The library file, testlib.c, contains two functions: 3 | int add_ints(int n1, int n2); 4 | int multiply_ints(int n1, int n2); 5 | 6 | There is a header file with these definitions in inc/testlib.h 7 | 8 | The directories shared/ and static/ contain identical copies of the 9 | library code but the first creates a shared library, testlib.so and 10 | the second creates a static library, testlib.a 11 | 12 | There is a program in hello-arm which links to each. 13 | Here is the directory layout: 14 | 15 | $ tree 16 | . 17 | ├── hello-arm 18 | │   ├── hello-arm.c 19 | │   └── Makefile 20 | ├── inc 21 | │   └── testlib.h 22 | ├── shared 23 | │   ├── Makefile 24 | │   └── testlib.c 25 | └── static 26 | ├── Makefile 27 | └── testlib.c 28 | 29 | Building 30 | ======== 31 | Compile the libraries first: 32 | 33 | $ cd shared 34 | $ make 35 | 36 | $ cd static 37 | $ make 38 | 39 | Then compile the application 40 | $ cd hello-arm 41 | $ make 42 | 43 | You should have two executables: hello-arm-shared and hello-arm-static 44 | $ list-libs hello-arm-shared 45 | [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] 46 | 0x0000000000000001 (NEEDED) Shared library: [libtest.so] 47 | 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 48 | 49 | $ list-libs hello-arm-static 50 | [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] 51 | 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 52 | 53 | 54 | Running 55 | ======= 56 | 57 | Executing the two executables gives different results: 58 | 59 | $ ./hello-arm-static 60 | Hello from ARM 61 | add_ints 62 | 4 + 5 = 9 63 | multiply_ints 64 | 4 * 5 = 20 65 | 66 | $ ./hello-arm-shared 67 | ./hello-arm-shared: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory 68 | 69 | 70 | If you add the directory containing libtest.so to the library loader path, 71 | then it works: 72 | 73 | $ LD_LIBRARY_PATH=../shared ./hello-arm-shared 74 | Hello from ARM 75 | add_ints 76 | 4 + 5 = 9 77 | multiply_ints 78 | 4 * 5 = 20 79 | 80 | -------------------------------------------------------------------------------- /Chapter02/library/hello-arm/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -c -Wall -I../inc 2 | PROGS := hello-arm-static hello-arm-shared 3 | 4 | all: $(PROGS) 5 | 6 | hello-arm.o: hello-arm.c 7 | $(CC) $(CFLAGS) -o $@ $^ 8 | 9 | hello-arm-static: hello-arm.o 10 | # $(CC) $(LDFLAGS) -o $@ $^ ../static/libtest.a 11 | $(CC) -o $@ $^ -L../static -ltest 12 | 13 | hello-arm-shared: hello-arm.o 14 | $(CC) -o $@ $^ -L../shared -ltest 15 | 16 | clean: 17 | rm -f *.o 18 | rm -f $(PROGS) 19 | 20 | install: 21 | cp $(PROGS) $(TARGET_DIR)/usr/local/bin 22 | 23 | -------------------------------------------------------------------------------- /Chapter02/library/hello-arm/hello-arm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main (int argc, char *argv[]) 6 | { 7 | int n1 = 4; 8 | int n2 = 5; 9 | 10 | printf("Hello from ARM\n"); 11 | printf("%d + %d = %d\n", n1, n2, add_ints(n1, n2)); 12 | printf("%d * %d = %d\n", n1, n2, multiply_ints(n1, n2)); 13 | return 0; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Chapter02/library/inc/testlib.h: -------------------------------------------------------------------------------- 1 | int add_ints(int n1, int n2); 2 | int multiply_ints(int n1, int n2); 3 | 4 | -------------------------------------------------------------------------------- /Chapter02/library/shared/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -Wall -g -fPIC -I../inc 2 | OBJECTS := testlib.o 3 | 4 | all: libtest.so 5 | 6 | # Build the shared library 7 | libtest.so: $(OBJECTS) 8 | $(CC) -shared -o libtest.so $(OBJECTS) 9 | 10 | testlib.o: testlib.c 11 | $(CC) $(CFLAGS) -c testlib.c 12 | 13 | clean: 14 | rm -f $(OBJECTS) 15 | rm -f libtest.so 16 | 17 | -------------------------------------------------------------------------------- /Chapter02/library/shared/testlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "testlib.h" 3 | 4 | int add_ints(int n1, int n2) 5 | { 6 | printf("%s\n", __func__); 7 | return n1 + n2; 8 | } 9 | 10 | int multiply_ints(int n1, int n2) 11 | { 12 | printf("%s\n", __func__); 13 | return n1 * n2; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Chapter02/library/static/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -Wall -g -I../inc 2 | OBJECTS = testlib.o 3 | 4 | all: libtest.a 5 | 6 | # Build the static library 7 | libtest.a: $(OBJECTS) 8 | ar rc libtest.a $(OBJECTS) 9 | 10 | testlib.o: testlib.c 11 | $(CC) $(CFLAGS) -c testlib.c 12 | 13 | clean: 14 | rm -f $(OBJECTS) 15 | rm -f libtest.a 16 | 17 | -------------------------------------------------------------------------------- /Chapter02/library/static/testlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "testlib.h" 3 | 4 | int add_ints(int n1, int n2) 5 | { 6 | printf("%s\n", __func__); 7 | return n1 + n2; 8 | } 9 | 10 | int multiply_ints(int n1, int n2) 11 | { 12 | printf("%s\n", __func__); 13 | return n1 * n2; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Chapter03/simpledts-1.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | 3 | / { 4 | node1 { 5 | a-string-property = "A string"; 6 | a-string-list-property = "first string", "second string"; 7 | // hex is implied in byte arrays. no '0x' prefix is required 8 | a-byte-data-property = [01 23 34 56]; 9 | child-node1 { 10 | first-child-property; 11 | second-child-property = <1>; 12 | a-string-property = "Hello, world"; 13 | }; 14 | child-node2 { 15 | }; 16 | }; 17 | node2 { 18 | an-empty-property; 19 | a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ 20 | child-node1 { 21 | }; 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Chapter04/build-linux-rpi4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Replace 2024.02-1 with the actual version of your Bootlin toolchain 3 | 4 | set -e 5 | 6 | $ git clone --depth=1 -b rpi-6.6.y https://github.com/raspberrypi/linux.git linux-rpi 7 | $ git clone --depth=1 -b 1.20240529 https://github.com/raspberrypi/firmware.git firmware-rpi 8 | 9 | mv firmware-rpi/boot . 10 | rm -rf firmware-rpi 11 | 12 | rm boot/kernel* 13 | rm boot/*.dtb 14 | rm boot/overlays/*.dtbo 15 | 16 | PATH=${HOME}/aarch64--glibc--stable-2024.02-1/bin/:$PATH 17 | 18 | cd linux-rpi 19 | mkdir ../build_rpi 20 | 21 | make ARCH=arm64 CROSS_COMPILE=aarch64-buildroot-linux-gnu- bcm2711_defconfig O=../build_rpi 22 | make -j4 ARCH=arm64 CROSS_COMPILE=aarch64-buildroot-linux-gnu- O=../build_rpi 23 | 24 | cp ../build_rpi/arch/arm64/boot/Image ../boot/kernel8.img 25 | cp ../build_rpi/arch/arm64/boot/dts/overlays/*.dtbo ../boot/overlays/ 26 | cp ../build_rpi/arch/arm64/boot/dts/broadcom/*.dtb ../boot/ 27 | 28 | cat << EOF > ../boot/config.txt 29 | enable_uart=1 30 | arm_64bit=1 31 | EOF 32 | 33 | cat << EOF > ../boot/cmdline.txt 34 | console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootwait 35 | EOF 36 | -------------------------------------------------------------------------------- /Chapter04/nova.dts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * https://beagleplay.org/ 4 | * 5 | * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ 6 | * Copyright (C) 2022-2023 Robert Nelson, BeagleBoard.org Foundation 7 | */ 8 | 9 | /dts-v1/; 10 | 11 | #include 12 | #include 13 | #include 14 | #include "k3-am625.dtsi" 15 | 16 | / { 17 | compatible = "beagle,am625-beagleplay", "ti,am625"; 18 | model = "Nova"; 19 | 20 | aliases { 21 | ethernet0 = &cpsw_port1; 22 | ethernet1 = &cpsw_port2; 23 | gpio0 = &main_gpio0; 24 | gpio1 = &main_gpio1; 25 | gpio2 = &mcu_gpio0; 26 | i2c0 = &main_i2c0; 27 | i2c1 = &main_i2c1; 28 | i2c2 = &main_i2c2; 29 | i2c3 = &main_i2c3; 30 | i2c4 = &wkup_i2c0; 31 | i2c5 = &mcu_i2c0; 32 | mdio-gpio0 = &mdio0; 33 | mmc0 = &sdhci0; 34 | mmc1 = &sdhci1; 35 | mmc2 = &sdhci2; 36 | rtc0 = &rtc; 37 | serial0 = &main_uart5; 38 | serial1 = &main_uart6; 39 | serial2 = &main_uart0; 40 | usb0 = &usb0; 41 | usb1 = &usb1; 42 | }; 43 | 44 | chosen { 45 | stdout-path = "serial2:115200n8"; 46 | }; 47 | 48 | memory@80000000 { 49 | device_type = "memory"; 50 | /* 2G RAM */ 51 | reg = <0x00000000 0x80000000 0x00000000 0x80000000>; 52 | }; 53 | 54 | reserved-memory { 55 | #address-cells = <2>; 56 | #size-cells = <2>; 57 | ranges; 58 | 59 | ramoops: ramoops@9ca00000 { 60 | compatible = "ramoops"; 61 | reg = <0x00 0x9ca00000 0x00 0x00100000>; 62 | record-size = <0x8000>; 63 | console-size = <0x8000>; 64 | ftrace-size = <0x00>; 65 | pmsg-size = <0x8000>; 66 | }; 67 | 68 | secure_tfa_ddr: tfa@9e780000 { 69 | reg = <0x00 0x9e780000 0x00 0x80000>; 70 | no-map; 71 | }; 72 | 73 | secure_ddr: optee@9e800000 { 74 | reg = <0x00 0x9e800000 0x00 0x01800000>; 75 | no-map; 76 | }; 77 | 78 | wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9db00000 { 79 | compatible = "shared-dma-pool"; 80 | reg = <0x00 0x9db00000 0x00 0xc00000>; 81 | no-map; 82 | }; 83 | }; 84 | 85 | vsys_5v0: regulator-1 { 86 | compatible = "regulator-fixed"; 87 | regulator-name = "vsys_5v0"; 88 | regulator-min-microvolt = <5000000>; 89 | regulator-max-microvolt = <5000000>; 90 | regulator-always-on; 91 | regulator-boot-on; 92 | }; 93 | 94 | vdd_3v3: regulator-2 { 95 | /* output of TLV62595DMQR-U12 */ 96 | compatible = "regulator-fixed"; 97 | regulator-name = "vdd_3v3"; 98 | regulator-min-microvolt = <3300000>; 99 | regulator-max-microvolt = <3300000>; 100 | vin-supply = <&vsys_5v0>; 101 | regulator-always-on; 102 | regulator-boot-on; 103 | }; 104 | 105 | wlan_en: regulator-3 { 106 | /* OUTPUT of SN74AVC2T244DQMR */ 107 | compatible = "regulator-fixed"; 108 | regulator-name = "wlan_en"; 109 | regulator-min-microvolt = <1800000>; 110 | regulator-max-microvolt = <1800000>; 111 | enable-active-high; 112 | regulator-always-on; 113 | vin-supply = <&vdd_3v3>; 114 | gpio = <&main_gpio0 38 GPIO_ACTIVE_HIGH>; 115 | pinctrl-names = "default"; 116 | pinctrl-0 = <&wifi_en_pins_default>; 117 | }; 118 | 119 | vdd_3v3_sd: regulator-4 { 120 | /* output of TPS22918DBVR-U21 */ 121 | pinctrl-names = "default"; 122 | pinctrl-0 = <&vdd_3v3_sd_pins_default>; 123 | 124 | compatible = "regulator-fixed"; 125 | regulator-name = "vdd_3v3_sd"; 126 | regulator-min-microvolt = <3300000>; 127 | regulator-max-microvolt = <3300000>; 128 | enable-active-high; 129 | regulator-always-on; 130 | vin-supply = <&vdd_3v3>; 131 | gpio = <&main_gpio1 19 GPIO_ACTIVE_HIGH>; 132 | }; 133 | 134 | vdd_sd_dv: regulator-5 { 135 | compatible = "regulator-gpio"; 136 | regulator-name = "sd_hs200_switch"; 137 | pinctrl-names = "default"; 138 | pinctrl-0 = <&vdd_sd_dv_pins_default>; 139 | regulator-min-microvolt = <1800000>; 140 | regulator-max-microvolt = <3300000>; 141 | regulator-boot-on; 142 | vin-supply = <&ldo1_reg>; 143 | gpios = <&main_gpio1 49 GPIO_ACTIVE_HIGH>; 144 | states = <1800000 0x0>, 145 | <3300000 0x1>; 146 | }; 147 | 148 | leds { 149 | compatible = "gpio-leds"; 150 | 151 | led-0 { 152 | gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; 153 | linux,default-trigger = "heartbeat"; 154 | function = LED_FUNCTION_HEARTBEAT; 155 | default-state = "off"; 156 | }; 157 | 158 | led-1 { 159 | gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; 160 | linux,default-trigger = "disk-activity"; 161 | function = LED_FUNCTION_DISK_ACTIVITY; 162 | default-state = "keep"; 163 | }; 164 | 165 | led-2 { 166 | gpios = <&main_gpio0 5 GPIO_ACTIVE_HIGH>; 167 | function = LED_FUNCTION_CPU; 168 | }; 169 | 170 | led-3 { 171 | gpios = <&main_gpio0 6 GPIO_ACTIVE_HIGH>; 172 | function = LED_FUNCTION_LAN; 173 | }; 174 | 175 | led-4 { 176 | gpios = <&main_gpio0 9 GPIO_ACTIVE_HIGH>; 177 | function = LED_FUNCTION_WLAN; 178 | }; 179 | }; 180 | 181 | gpio_keys: gpio-keys { 182 | compatible = "gpio-keys"; 183 | autorepeat; 184 | pinctrl-names = "default"; 185 | pinctrl-0 = <&usr_button_pins_default>; 186 | 187 | usr: button-usr { 188 | label = "User Key"; 189 | linux,code = ; 190 | gpios = <&main_gpio0 18 GPIO_ACTIVE_LOW>; 191 | }; 192 | 193 | }; 194 | 195 | hdmi0: connector-hdmi { 196 | compatible = "hdmi-connector"; 197 | label = "hdmi"; 198 | type = "a"; 199 | port { 200 | hdmi_connector_in: endpoint { 201 | remote-endpoint = <&it66121_out>; 202 | }; 203 | }; 204 | }; 205 | 206 | sound { 207 | compatible = "simple-audio-card"; 208 | simple-audio-card,name = "it66121 HDMI"; 209 | simple-audio-card,format = "i2s"; 210 | simple-audio-card,bitclock-master = <&hdmi_dailink_master>; 211 | simple-audio-card,frame-master = <&hdmi_dailink_master>; 212 | 213 | hdmi_dailink_master: simple-audio-card,cpu { 214 | sound-dai = <&mcasp1>; 215 | system-clock-direction-out; 216 | }; 217 | 218 | simple-audio-card,codec { 219 | sound-dai = <&it66121>; 220 | }; 221 | }; 222 | 223 | /* Workaround for errata i2329 - just use mdio bitbang */ 224 | mdio0: mdio { 225 | compatible = "virtual,mdio-gpio"; 226 | pinctrl-names = "default"; 227 | pinctrl-0 = <&mdio0_pins_default>; 228 | gpios = <&main_gpio0 86 GPIO_ACTIVE_HIGH>, /* MDC */ 229 | <&main_gpio0 85 GPIO_ACTIVE_HIGH>; /* MDIO */ 230 | #address-cells = <1>; 231 | #size-cells = <0>; 232 | 233 | cpsw3g_phy0: ethernet-phy@0 { 234 | reg = <0>; 235 | }; 236 | 237 | cpsw3g_phy1: ethernet-phy@1 { 238 | reg = <1>; 239 | reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>; 240 | reset-assert-us = <25>; 241 | reset-deassert-us = <60000>; /* T2 */ 242 | }; 243 | }; 244 | }; 245 | 246 | &main_pmx0 { 247 | gpio0_pins_default: gpio0-default-pins { 248 | pinctrl-single,pins = < 249 | AM62X_IOPAD(0x0004, PIN_INPUT, 7) /* (G25) OSPI0_LBCLKO.GPIO0_1 */ 250 | AM62X_IOPAD(0x0008, PIN_INPUT, 7) /* (J24) OSPI0_DQS.GPIO0_2 */ 251 | AM62X_IOPAD(0x000c, PIN_INPUT, 7) /* (E25) OSPI0_D0.GPIO0_3 */ 252 | AM62X_IOPAD(0x0010, PIN_INPUT, 7) /* (G24) OSPI0_D1.GPIO0_4 */ 253 | AM62X_IOPAD(0x0014, PIN_INPUT, 7) /* (F25) OSPI0_D2.GPIO0_5 */ 254 | AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ 255 | AM62X_IOPAD(0x0024, PIN_INPUT, 7) /* (H25) OSPI0_D6.GPIO0_9 */ 256 | AM62X_IOPAD(0x0028, PIN_INPUT, 7) /* (J22) OSPI0_D7.GPIO0_10 */ 257 | AM62X_IOPAD(0x002c, PIN_INPUT, 7) /* (F23) OSPI0_CSn0.GPIO0_11 */ 258 | AM62X_IOPAD(0x0030, PIN_INPUT, 7) /* (G21) OSPI0_CSn1.GPIO0_12 */ 259 | AM62X_IOPAD(0x0034, PIN_INPUT, 7) /* (H21) OSPI0_CSn2.GPIO0_13 */ 260 | AM62X_IOPAD(0x0038, PIN_INPUT, 7) /* (E24) OSPI0_CSn3.GPIO0_14 */ 261 | AM62X_IOPAD(0x00a4, PIN_INPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */ 262 | AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */ 263 | >; 264 | }; 265 | 266 | vdd_sd_dv_pins_default: vdd-sd-default-pins { 267 | pinctrl-single,pins = < 268 | AM62X_IOPAD(0x0244, PIN_OUTPUT, 7) /* (C17) MMC1_SDWP.GPIO1_49 */ 269 | >; 270 | }; 271 | 272 | usr_button_pins_default: usr-button-default-pins { 273 | pinctrl-single,pins = < 274 | AM62X_IOPAD(0x0048, PIN_INPUT, 7) /* (N25) GPMC0_AD3.GPIO0_18 */ 275 | >; 276 | }; 277 | 278 | grove_pins_default: grove-default-pins { 279 | pinctrl-single,pins = < 280 | AM62X_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ 281 | AM62X_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (A17) I2C1_SDA */ 282 | >; 283 | }; 284 | 285 | local_i2c_pins_default: local-i2c-default-pins { 286 | pinctrl-single,pins = < 287 | AM62X_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (B16) I2C0_SCL */ 288 | AM62X_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (A16) I2C0_SDA */ 289 | >; 290 | }; 291 | 292 | i2c2_1v8_pins_default: i2c2-default-pins { 293 | pinctrl-single,pins = < 294 | AM62X_IOPAD(0x00b0, PIN_INPUT_PULLUP, 1) /* (K22) GPMC0_CSn2.I2C2_SCL */ 295 | AM62X_IOPAD(0x00b4, PIN_INPUT_PULLUP, 1) /* (K24) GPMC0_CSn3.I2C2_SDA */ 296 | >; 297 | }; 298 | 299 | mdio0_pins_default: mdio0-default-pins { 300 | pinctrl-single,pins = < 301 | AM62X_IOPAD(0x0160, PIN_OUTPUT, 7) /* (AD24) MDIO0_MDC.GPIO0_86 */ 302 | AM62X_IOPAD(0x015c, PIN_INPUT, 7) /* (AB22) MDIO0_MDIO.GPIO0_85 */ 303 | >; 304 | }; 305 | 306 | rgmii1_pins_default: rgmii1-default-pins { 307 | pinctrl-single,pins = < 308 | AM62X_IOPAD(0x014c, PIN_INPUT, 0) /* (AB17) RGMII1_RD0 */ 309 | AM62X_IOPAD(0x0150, PIN_INPUT, 0) /* (AC17) RGMII1_RD1 */ 310 | AM62X_IOPAD(0x0154, PIN_INPUT, 0) /* (AB16) RGMII1_RD2 */ 311 | AM62X_IOPAD(0x0158, PIN_INPUT, 0) /* (AA15) RGMII1_RD3 */ 312 | AM62X_IOPAD(0x0148, PIN_INPUT, 0) /* (AD17) RGMII1_RXC */ 313 | AM62X_IOPAD(0x0144, PIN_INPUT, 0) /* (AE17) RGMII1_RX_CTL */ 314 | AM62X_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AE20) RGMII1_TD0 */ 315 | AM62X_IOPAD(0x0138, PIN_OUTPUT, 0) /* (AD20) RGMII1_TD1 */ 316 | AM62X_IOPAD(0x013c, PIN_OUTPUT, 0) /* (AE18) RGMII1_TD2 */ 317 | AM62X_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AD18) RGMII1_TD3 */ 318 | AM62X_IOPAD(0x0130, PIN_OUTPUT, 0) /* (AE19) RGMII1_TXC */ 319 | AM62X_IOPAD(0x012c, PIN_OUTPUT, 0) /* (AD19) RGMII1_TX_CTL */ 320 | >; 321 | }; 322 | 323 | emmc_pins_default: emmc-default-pins { 324 | pinctrl-single,pins = < 325 | AM62X_IOPAD(0x0220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ 326 | AM62X_IOPAD(0x0218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ 327 | AM62X_IOPAD(0x0214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ 328 | AM62X_IOPAD(0x0210, PIN_INPUT, 0) /* (AA1) MMC0_DAT1 */ 329 | AM62X_IOPAD(0x020c, PIN_INPUT, 0) /* (AA3) MMC0_DAT2 */ 330 | AM62X_IOPAD(0x0208, PIN_INPUT, 0) /* (Y4) MMC0_DAT3 */ 331 | AM62X_IOPAD(0x0204, PIN_INPUT, 0) /* (AB2) MMC0_DAT4 */ 332 | AM62X_IOPAD(0x0200, PIN_INPUT, 0) /* (AC1) MMC0_DAT5 */ 333 | AM62X_IOPAD(0x01fc, PIN_INPUT, 0) /* (AD2) MMC0_DAT6 */ 334 | AM62X_IOPAD(0x01f8, PIN_INPUT, 0) /* (AC2) MMC0_DAT7 */ 335 | >; 336 | }; 337 | 338 | vdd_3v3_sd_pins_default: vdd-3v3-sd-default-pins { 339 | pinctrl-single,pins = < 340 | AM62X_IOPAD(0x01c4, PIN_INPUT, 7) /* (B14) SPI0_D1_GPIO1_19 */ 341 | >; 342 | }; 343 | 344 | sd_pins_default: sd-default-pins { 345 | pinctrl-single,pins = < 346 | AM62X_IOPAD(0x023c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ 347 | AM62X_IOPAD(0x0234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ 348 | AM62X_IOPAD(0x0230, PIN_INPUT, 0) /* (A22) MMC1_DAT0 */ 349 | AM62X_IOPAD(0x022c, PIN_INPUT, 0) /* (B21) MMC1_DAT1 */ 350 | AM62X_IOPAD(0x0228, PIN_INPUT, 0) /* (C21) MMC1_DAT2 */ 351 | AM62X_IOPAD(0x0224, PIN_INPUT, 0) /* (D22) MMC1_DAT3 */ 352 | AM62X_IOPAD(0x0240, PIN_INPUT, 7) /* (D17) MMC1_SDCD.GPIO1_48 */ 353 | >; 354 | }; 355 | 356 | wifi_pins_default: wifi-default-pins { 357 | pinctrl-single,pins = < 358 | AM62X_IOPAD(0x0120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ 359 | AM62X_IOPAD(0x0118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ 360 | AM62X_IOPAD(0x0114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ 361 | AM62X_IOPAD(0x0110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ 362 | AM62X_IOPAD(0x010c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ 363 | AM62X_IOPAD(0x0108, PIN_INPUT, 0) /* (D24) MMC2_DAT3 */ 364 | AM62X_IOPAD(0x0124, PIN_INPUT, 0) /* (A23) MMC2_SDCD */ 365 | AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */ 366 | >; 367 | }; 368 | 369 | wifi_en_pins_default: wifi-en-default-pins { 370 | pinctrl-single,pins = < 371 | AM62X_IOPAD(0x009c, PIN_OUTPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */ 372 | >; 373 | }; 374 | 375 | wifi_wlirq_pins_default: wifi-wlirq-default-pins { 376 | pinctrl-single,pins = < 377 | AM62X_IOPAD(0x00a8, PIN_INPUT, 7) /* (M21) GPMC0_CSn0.GPIO0_41 */ 378 | >; 379 | }; 380 | 381 | spe_pins_default: spe-default-pins { 382 | pinctrl-single,pins = < 383 | AM62X_IOPAD(0x0168, PIN_INPUT, 1) /* (AE21) RGMII2_TXC.RMII2_CRS_DV */ 384 | AM62X_IOPAD(0x0180, PIN_INPUT, 1) /* (AD23) RGMII2_RXC.RMII2_REF_CLK */ 385 | AM62X_IOPAD(0x0184, PIN_INPUT, 1) /* (AE23) RGMII2_RD0.RMII2_RXD0 */ 386 | AM62X_IOPAD(0x0188, PIN_INPUT, 1) /* (AB20) RGMII2_RD1.RMII2_RXD1 */ 387 | AM62X_IOPAD(0x017c, PIN_INPUT, 1) /* (AD22) RGMII2_RX_CTL.RMII2_RX_ER */ 388 | AM62X_IOPAD(0x016c, PIN_INPUT, 1) /* (Y18) RGMII2_TD0.RMII2_TXD0 */ 389 | AM62X_IOPAD(0x0170, PIN_INPUT, 1) /* (AA18) RGMII2_TD1.RMII2_TXD1 */ 390 | AM62X_IOPAD(0x0164, PIN_INPUT, 1) /* (AA19) RGMII2_TX_CTL.RMII2_TX_EN */ 391 | AM62X_IOPAD(0x018c, PIN_OUTPUT, 7) /* (AC21) RGMII2_RD2.GPIO1_5 */ 392 | AM62X_IOPAD(0x0190, PIN_INPUT, 7) /* (AE22) RGMII2_RD3.GPIO1_6 */ 393 | AM62X_IOPAD(0x01f0, PIN_OUTPUT, 5) /* (A18) EXT_REFCLK1.CLKOUT0 */ 394 | >; 395 | }; 396 | 397 | mikrobus_i2c_pins_default: mikrobus-i2c-default-pins { 398 | pinctrl-single,pins = < 399 | AM62X_IOPAD(0x01d0, PIN_INPUT_PULLUP, 2) /* (A15) UART0_CTSn.I2C3_SCL */ 400 | AM62X_IOPAD(0x01d4, PIN_INPUT_PULLUP, 2) /* (B15) UART0_RTSn.I2C3_SDA */ 401 | >; 402 | }; 403 | 404 | mikrobus_uart_pins_default: mikrobus-uart-default-pins { 405 | pinctrl-single,pins = < 406 | AM62X_IOPAD(0x01d8, PIN_INPUT, 1) /* (C15) MCAN0_TX.UART5_RXD */ 407 | AM62X_IOPAD(0x01dc, PIN_OUTPUT, 1) /* (E15) MCAN0_RX.UART5_TXD */ 408 | >; 409 | }; 410 | 411 | mikrobus_spi_pins_default: mikrobus-spi-default-pins { 412 | pinctrl-single,pins = < 413 | AM62X_IOPAD(0x01b0, PIN_INPUT, 1) /* (A20) MCASP0_ACLKR.SPI2_CLK */ 414 | AM62X_IOPAD(0x01ac, PIN_INPUT, 1) /* (E19) MCASP0_AFSR.SPI2_CS0 */ 415 | AM62X_IOPAD(0x0194, PIN_INPUT, 1) /* (B19) MCASP0_AXR3.SPI2_D0 */ 416 | AM62X_IOPAD(0x0198, PIN_INPUT, 1) /* (A19) MCASP0_AXR2.SPI2_D1 */ 417 | >; 418 | }; 419 | 420 | mikrobus_gpio_pins_default: mikrobus-gpio-default-pins { 421 | pinctrl-single,pins = < 422 | AM62X_IOPAD(0x019c, PIN_INPUT, 7) /* (B18) MCASP0_AXR1.GPIO1_9 */ 423 | AM62X_IOPAD(0x01a0, PIN_INPUT, 7) /* (E18) MCASP0_AXR0.GPIO1_10 */ 424 | AM62X_IOPAD(0x01a8, PIN_INPUT, 7) /* (D20) MCASP0_AFSX.GPIO1_12 */ 425 | >; 426 | }; 427 | 428 | console_pins_default: console-default-pins { 429 | pinctrl-single,pins = < 430 | AM62X_IOPAD(0x01c8, PIN_INPUT, 0) /* (D14) UART0_RXD */ 431 | AM62X_IOPAD(0x01cc, PIN_OUTPUT, 0) /* (E14) UART0_TXD */ 432 | >; 433 | }; 434 | 435 | wifi_debug_uart_pins_default: wifi-debug-uart-default-pins { 436 | pinctrl-single,pins = < 437 | AM62X_IOPAD(0x001c, PIN_INPUT, 3) /* (J23) OSPI0_D4.UART6_RXD */ 438 | AM62X_IOPAD(0x0020, PIN_OUTPUT, 3) /* (J25) OSPI0_D5.UART6_TXD */ 439 | >; 440 | }; 441 | 442 | usb1_pins_default: usb1-default-pins { 443 | pinctrl-single,pins = < 444 | AM62X_IOPAD(0x0258, PIN_INPUT, 0) /* (F18) USB1_DRVVBUS */ 445 | >; 446 | }; 447 | 448 | pmic_irq_pins_default: pmic-irq-default-pins { 449 | pinctrl-single,pins = < 450 | AM62X_IOPAD(0x01f4, PIN_INPUT_PULLUP, 0) /* (D16) EXTINTn */ 451 | >; 452 | }; 453 | 454 | hdmi_gpio_pins_default: hdmi-gpio-default-pins { 455 | pinctrl-single,pins = < 456 | AM62X_IOPAD(0x0094, PIN_INPUT_PULLUP | PIN_DEBOUNCE_CONF6, 7) /* (N20) GPMC0_BE1n.GPIO0_36 */ 457 | AM62X_IOPAD(0x0054, PIN_OUTPUT_PULLUP, 7) /* (P21) GPMC0_AD6.GPIO0_21 */ 458 | >; 459 | }; 460 | 461 | mcasp_hdmi_pins_default: mcasp-hdmi-default-pins { 462 | pinctrl-single,pins = < 463 | AM62X_IOPAD(0x0090, PIN_INPUT, 2) /* (M24) GPMC0_BE0n_CLE.MCASP1_ACLKX */ 464 | AM62X_IOPAD(0x0098, PIN_INPUT, 2) /* (U23) GPMC0_WAIT0.MCASP1_AFSX */ 465 | AM62X_IOPAD(0x008c, PIN_OUTPUT, 2) /* (L25) GPMC0_WEn.MCASP1_AXR0 */ 466 | AM62X_IOPAD(0x0088, PIN_INPUT, 2) /* (L24) GPMC0_OEn_REn.MCASP1_AXR1 */ 467 | AM62X_IOPAD(0x0084, PIN_INPUT, 2) /* (L23) GPMC0_ADVn_ALE.MCASP1_AXR2 */ 468 | AM62X_IOPAD(0x007c, PIN_INPUT, 2) /* (P25) GPMC0_CLK.MCASP1_AXR3 */ 469 | >; 470 | }; 471 | 472 | dss0_pins_default: dss0-default-pins { 473 | pinctrl-single,pins = < 474 | AM62X_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC */ 475 | AM62X_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ 476 | AM62X_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK */ 477 | AM62X_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (Y20) VOUT0_DE */ 478 | AM62X_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ 479 | AM62X_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (V24) VOUT0_DATA1 */ 480 | AM62X_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA2 */ 481 | AM62X_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA3 */ 482 | AM62X_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (Y25) VOUT0_DATA4 */ 483 | AM62X_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (Y24) VOUT0_DATA5 */ 484 | AM62X_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA6 */ 485 | AM62X_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7 */ 486 | AM62X_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA8 */ 487 | AM62X_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA9 */ 488 | AM62X_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (V20) VOUT0_DATA10 */ 489 | AM62X_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11 */ 490 | AM62X_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12 */ 491 | AM62X_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13 */ 492 | AM62X_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA14 */ 493 | AM62X_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15 */ 494 | AM62X_IOPAD(0x005c, PIN_OUTPUT, 1) /* (R24) GPMC0_AD8.VOUT0_DATA16 */ 495 | AM62X_IOPAD(0x0060, PIN_OUTPUT, 1) /* (R25) GPMC0_AD9.VOUT0_DATA17 */ 496 | AM62X_IOPAD(0x0064, PIN_OUTPUT, 1) /* (T25) GPMC0_AD10.VOUT0_DATA18 */ 497 | AM62X_IOPAD(0x0068, PIN_OUTPUT, 1) /* (R21) GPMC0_AD11.VOUT0_DATA19 */ 498 | AM62X_IOPAD(0x006c, PIN_OUTPUT, 1) /* (T22) GPMC0_AD12.VOUT0_DATA20 */ 499 | AM62X_IOPAD(0x0070, PIN_OUTPUT, 1) /* (T24) GPMC0_AD13.VOUT0_DATA21 */ 500 | AM62X_IOPAD(0x0074, PIN_OUTPUT, 1) /* (U25) GPMC0_AD14.VOUT0_DATA22 */ 501 | AM62X_IOPAD(0x0078, PIN_OUTPUT, 1) /* (U24) GPMC0_AD15.VOUT0_DATA23 */ 502 | >; 503 | }; 504 | }; 505 | 506 | &mcu_pmx0 { 507 | i2c_qwiic_pins_default: i2c-qwiic-default-pins { 508 | pinctrl-single,pins = < 509 | AM62X_MCU_IOPAD(0x0044, PIN_INPUT, 0) /* (A8) MCU_I2C0_SCL */ 510 | AM62X_MCU_IOPAD(0x0048, PIN_INPUT, 0) /* (D10) MCU_I2C0_SDA */ 511 | >; 512 | }; 513 | 514 | gbe_pmx_obsclk: gbe-pmx-obsclk-default-pins { 515 | pinctrl-single,pins = < 516 | AM62X_MCU_IOPAD(0x0004, PIN_OUTPUT, 1) /* (B8) MCU_SPI0_CS1.MCU_OBSCLK0 */ 517 | >; 518 | }; 519 | 520 | i2c_csi_pins_default: i2c-csi-default-pins { 521 | pinctrl-single,pins = < 522 | AM62X_MCU_IOPAD(0x004c, PIN_INPUT_PULLUP, 0) /* (B9) WKUP_I2C0_SCL */ 523 | AM62X_MCU_IOPAD(0x0050, PIN_INPUT_PULLUP, 0) /* (A9) WKUP_I2C0_SDA */ 524 | >; 525 | }; 526 | 527 | wifi_32k_clk: mcu-clk-out-default-pins { 528 | pinctrl-single,pins = < 529 | AM62X_MCU_IOPAD(0x0084, PIN_OUTPUT, 0) /* (A12) WKUP_CLKOUT0 */ 530 | >; 531 | }; 532 | }; 533 | 534 | &a53_opp_table { 535 | /* Requires VDD_CORE to be at 0.85V */ 536 | opp-1400000000 { 537 | opp-hz = /bits/ 64 <1400000000>; 538 | opp-supported-hw = <0x01 0x0004>; 539 | }; 540 | }; 541 | 542 | &wkup_i2c0 { 543 | pinctrl-names = "default"; 544 | pinctrl-0 = <&i2c_csi_pins_default>; 545 | clock-frequency = <400000>; 546 | /* Enable with overlay for camera sensor */ 547 | }; 548 | 549 | &mcu_i2c0 { 550 | pinctrl-names = "default"; 551 | pinctrl-0 = <&i2c_qwiic_pins_default>; 552 | clock-frequency = <100000>; 553 | status = "okay"; 554 | }; 555 | 556 | &usbss0 { 557 | ti,vbus-divider; 558 | status = "okay"; 559 | }; 560 | 561 | &usb0 { 562 | dr_mode = "peripheral"; 563 | }; 564 | 565 | &usbss1 { 566 | ti,vbus-divider; 567 | status = "okay"; 568 | }; 569 | 570 | &usb1 { 571 | dr_mode = "host"; 572 | pinctrl-names = "default"; 573 | pinctrl-0 = <&usb1_pins_default>; 574 | }; 575 | 576 | &cpsw3g { 577 | pinctrl-names = "default"; 578 | pinctrl-0 = <&rgmii1_pins_default>, <&spe_pins_default>, 579 | <&gbe_pmx_obsclk>; 580 | assigned-clocks = <&k3_clks 157 70>, <&k3_clks 157 20>; 581 | assigned-clock-parents = <&k3_clks 157 72>, <&k3_clks 157 22>; 582 | }; 583 | 584 | &cpsw_port1 { 585 | phy-mode = "rgmii-rxid"; 586 | phy-handle = <&cpsw3g_phy0>; 587 | }; 588 | 589 | &cpsw_port2 { 590 | phy-mode = "rmii"; 591 | phy-handle = <&cpsw3g_phy1>; 592 | }; 593 | 594 | &cpsw3g_mdio { 595 | /* Workaround for errata i2329 - Use mdio bitbang */ 596 | status = "disabled"; 597 | }; 598 | 599 | &main_gpio0 { 600 | pinctrl-names = "default"; 601 | pinctrl-0 = <&gpio0_pins_default>; 602 | gpio-line-names = "BL_EN_3V3", "SPE_PO_EN", "RTC_INT", /* 0-2 */ 603 | "USR0", "USR1", "USR2", "USR3", "", "", "USR4", /* 3-9 */ 604 | "EEPROM_WP", /* 10 */ 605 | "CSI2_CAMERA_GPIO1", "CSI2_CAMERA_GPIO2", /* 11-12 */ 606 | "CC1352P7_BOOT", "CC1352P7_RSTN", "", "", "", /* 13-17 */ 607 | "USR_BUTTON", "", "", "", "", "", "", "", "", /* 18-26 */ 608 | "", "", "", "", "", "", "", "", "", "HDMI_INT", /* 27-36 */ 609 | "", "VDD_WLAN_EN", "", "", "WL_IRQ", "GBE_INTN",/* 37-42 */ 610 | "", "", "", "", "", "", "", "", "", "", "", "", /* 43-54 */ 611 | "", "", "", "", "", "", "", "", "", "", "", "", /* 55-66 */ 612 | "", "", "", "", "", "", "", "", "", "", "", "", /* 67-78 */ 613 | "", "", "", "", "", "", /* 79-84 */ 614 | "BITBANG_MDIO_DATA", "BITBANG_MDIO_CLK", /* 85-86 */ 615 | "", "", "", "", ""; /* 87-91 */ 616 | }; 617 | 618 | &main_gpio1 { 619 | pinctrl-names = "default"; 620 | pinctrl-0 = <&mikrobus_gpio_pins_default>; 621 | gpio-line-names = "", "", "", "", "", /* 0-4 */ 622 | "SPE_RSTN", "SPE_INTN", "MIKROBUS_GPIO1_7", /* 5-7 */ 623 | "MIKROBUS_GPIO1_8", "MIKROBUS_GPIO1_9", /* 8-9 */ 624 | "MIKROBUS_GPIO1_10", "MIKROBUS_GPIO1_11", /* 10-11 */ 625 | "MIKROBUS_GPIO1_12", "MIKROBUS_W1_GPIO0", /* 12-13 */ 626 | "MIKROBUS_GPIO1_14", /* 14 */ 627 | "", "", "", "", "VDD_3V3_SD", "", "", /* 15-21 */ 628 | "MIKROBUS_GPIO1_22", "MIKROBUS_GPIO1_23", /* 22-23 */ 629 | "MIKROBUS_GPIO1_24", "MIKROBUS_GPIO1_25", /* 24-25 */ 630 | "", "", "", "", "", "", "", "", "", "", "", "", /* 26-37 */ 631 | "", "", "", "", "", "", "", "", "", "", /* 38-47 */ 632 | "SD_CD", "SD_VOLT_SEL", "", ""; /* 48-51 */ 633 | }; 634 | 635 | &main_i2c0 { 636 | pinctrl-names = "default"; 637 | pinctrl-0 = <&local_i2c_pins_default>; 638 | clock-frequency = <400000>; 639 | status = "okay"; 640 | 641 | eeprom@50 { 642 | compatible = "atmel,24c32"; 643 | reg = <0x50>; 644 | }; 645 | 646 | rtc: rtc@68 { 647 | compatible = "ti,bq32000"; 648 | reg = <0x68>; 649 | interrupt-parent = <&main_gpio0>; 650 | interrupts = <2 IRQ_TYPE_EDGE_FALLING>; 651 | }; 652 | 653 | tps65219: pmic@30 { 654 | compatible = "ti,tps65219"; 655 | reg = <0x30>; 656 | buck1-supply = <&vsys_5v0>; 657 | buck2-supply = <&vsys_5v0>; 658 | buck3-supply = <&vsys_5v0>; 659 | ldo1-supply = <&vdd_3v3>; 660 | ldo2-supply = <&buck2_reg>; 661 | ldo3-supply = <&vdd_3v3>; 662 | ldo4-supply = <&vdd_3v3>; 663 | 664 | pinctrl-names = "default"; 665 | pinctrl-0 = <&pmic_irq_pins_default>; 666 | interrupt-parent = <&gic500>; 667 | interrupts = ; 668 | interrupt-controller; 669 | #interrupt-cells = <1>; 670 | 671 | system-power-controller; 672 | ti,power-button; 673 | 674 | regulators { 675 | buck1_reg: buck1 { 676 | regulator-name = "VDD_CORE"; 677 | regulator-min-microvolt = <850000>; 678 | regulator-max-microvolt = <850000>; 679 | regulator-boot-on; 680 | regulator-always-on; 681 | }; 682 | 683 | buck2_reg: buck2 { 684 | regulator-name = "VDD_1V8"; 685 | regulator-min-microvolt = <1800000>; 686 | regulator-max-microvolt = <1800000>; 687 | regulator-boot-on; 688 | regulator-always-on; 689 | }; 690 | 691 | buck3_reg: buck3 { 692 | regulator-name = "VDD_1V2"; 693 | regulator-min-microvolt = <1200000>; 694 | regulator-max-microvolt = <1200000>; 695 | regulator-boot-on; 696 | regulator-always-on; 697 | }; 698 | 699 | ldo1_reg: ldo1 { 700 | /* 701 | * Regulator is left as is unused, vdd_sd 702 | * is controlled via GPIO with bypass config 703 | * as per the NVM configuration 704 | */ 705 | regulator-name = "VDD_SD_3V3"; 706 | regulator-min-microvolt = <3300000>; 707 | regulator-max-microvolt = <3300000>; 708 | regulator-allow-bypass; 709 | regulator-boot-on; 710 | regulator-always-on; 711 | }; 712 | 713 | ldo2_reg: ldo2 { 714 | regulator-name = "VDDA_0V85"; 715 | regulator-min-microvolt = <850000>; 716 | regulator-max-microvolt = <850000>; 717 | regulator-boot-on; 718 | regulator-always-on; 719 | }; 720 | 721 | ldo3_reg: ldo3 { 722 | regulator-name = "VDDA_1V8"; 723 | regulator-min-microvolt = <1800000>; 724 | regulator-max-microvolt = <1800000>; 725 | regulator-boot-on; 726 | regulator-always-on; 727 | }; 728 | 729 | ldo4_reg: ldo4 { 730 | regulator-name = "VDD_2V5"; 731 | regulator-min-microvolt = <2500000>; 732 | regulator-max-microvolt = <2500000>; 733 | regulator-boot-on; 734 | regulator-always-on; 735 | }; 736 | }; 737 | }; 738 | }; 739 | 740 | &main_i2c1 { 741 | pinctrl-names = "default"; 742 | pinctrl-0 = <&grove_pins_default>; 743 | clock-frequency = <100000>; 744 | status = "okay"; 745 | }; 746 | 747 | &main_i2c2 { 748 | pinctrl-names = "default"; 749 | pinctrl-0 = <&i2c2_1v8_pins_default>; 750 | clock-frequency = <100000>; 751 | status = "okay"; 752 | 753 | it66121: bridge-hdmi@4c { 754 | compatible = "ite,it66121"; 755 | reg = <0x4c>; 756 | pinctrl-names = "default"; 757 | pinctrl-0 = <&hdmi_gpio_pins_default>; 758 | vcn33-supply = <&vdd_3v3>; 759 | vcn18-supply = <&buck2_reg>; 760 | vrf12-supply = <&buck3_reg>; 761 | reset-gpios = <&main_gpio0 21 GPIO_ACTIVE_LOW>; 762 | interrupt-parent = <&main_gpio0>; 763 | interrupts = <36 IRQ_TYPE_EDGE_FALLING>; 764 | #sound-dai-cells = <0>; 765 | 766 | ports { 767 | #address-cells = <1>; 768 | #size-cells = <0>; 769 | 770 | port@0 { 771 | reg = <0>; 772 | 773 | it66121_in: endpoint { 774 | bus-width = <24>; 775 | remote-endpoint = <&dpi1_out>; 776 | }; 777 | }; 778 | 779 | port@1 { 780 | reg = <1>; 781 | 782 | it66121_out: endpoint { 783 | remote-endpoint = <&hdmi_connector_in>; 784 | }; 785 | }; 786 | }; 787 | }; 788 | }; 789 | 790 | &main_i2c3 { 791 | pinctrl-names = "default"; 792 | pinctrl-0 = <&mikrobus_i2c_pins_default>; 793 | clock-frequency = <400000>; 794 | status = "okay"; 795 | }; 796 | 797 | &main_spi2 { 798 | pinctrl-names = "default"; 799 | pinctrl-0 = <&mikrobus_spi_pins_default>; 800 | status = "okay"; 801 | }; 802 | 803 | &sdhci0 { 804 | pinctrl-names = "default"; 805 | pinctrl-0 = <&emmc_pins_default>; 806 | ti,driver-strength-ohm = <50>; 807 | disable-wp; 808 | status = "okay"; 809 | }; 810 | 811 | &sdhci1 { 812 | /* SD/MMC */ 813 | pinctrl-names = "default"; 814 | pinctrl-0 = <&sd_pins_default>; 815 | 816 | vmmc-supply = <&vdd_3v3_sd>; 817 | vqmmc-supply = <&vdd_sd_dv>; 818 | ti,driver-strength-ohm = <50>; 819 | disable-wp; 820 | cd-gpios = <&main_gpio1 48 GPIO_ACTIVE_LOW>; 821 | cd-debounce-delay-ms = <100>; 822 | ti,fails-without-test-cd; 823 | status = "okay"; 824 | }; 825 | 826 | &sdhci2 { 827 | vmmc-supply = <&wlan_en>; 828 | pinctrl-names = "default"; 829 | pinctrl-0 = <&wifi_pins_default>, <&wifi_32k_clk>; 830 | bus-width = <4>; 831 | non-removable; 832 | ti,fails-without-test-cd; 833 | cap-power-off-card; 834 | keep-power-in-suspend; 835 | ti,driver-strength-ohm = <50>; 836 | assigned-clocks = <&k3_clks 157 158>; 837 | assigned-clock-parents = <&k3_clks 157 160>; 838 | #address-cells = <1>; 839 | #size-cells = <0>; 840 | status = "okay"; 841 | 842 | wlcore: wlcore@2 { 843 | compatible = "ti,wl1807"; 844 | reg = <2>; 845 | pinctrl-names = "default"; 846 | pinctrl-0 = <&wifi_wlirq_pins_default>; 847 | interrupt-parent = <&main_gpio0>; 848 | interrupts = <41 IRQ_TYPE_EDGE_FALLING>; 849 | }; 850 | }; 851 | 852 | &main_uart0 { 853 | pinctrl-names = "default"; 854 | pinctrl-0 = <&console_pins_default>; 855 | status = "okay"; 856 | }; 857 | 858 | &main_uart1 { 859 | /* Main UART1 is used by TIFS firmware */ 860 | status = "reserved"; 861 | }; 862 | 863 | &main_uart5 { 864 | pinctrl-names = "default"; 865 | pinctrl-0 = <&mikrobus_uart_pins_default>; 866 | status = "okay"; 867 | }; 868 | 869 | &main_uart6 { 870 | pinctrl-names = "default"; 871 | pinctrl-0 = <&wifi_debug_uart_pins_default>; 872 | status = "okay"; 873 | }; 874 | 875 | &dss { 876 | status = "okay"; 877 | pinctrl-names = "default"; 878 | pinctrl-0 = <&dss0_pins_default>; 879 | }; 880 | 881 | &dss_ports { 882 | /* VP2: DPI Output */ 883 | port@1 { 884 | reg = <1>; 885 | 886 | dpi1_out: endpoint { 887 | remote-endpoint = <&it66121_in>; 888 | }; 889 | }; 890 | }; 891 | 892 | &mcasp1 { 893 | status = "okay"; 894 | #sound-dai-cells = <0>; 895 | pinctrl-names = "default"; 896 | pinctrl-0 = <&mcasp_hdmi_pins_default>; 897 | auxclk-fs-ratio = <2177>; 898 | op-mode = <0>; /* MCASP_IIS_MODE */ 899 | tdm-slots = <2>; 900 | serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ 901 | 1 0 0 0 902 | 0 0 0 0 903 | 0 0 0 0 904 | 0 0 0 0 905 | >; 906 | }; 907 | -------------------------------------------------------------------------------- /Chapter05/device-tables.txt: -------------------------------------------------------------------------------- 1 | /dev d 755 0 0 - - - - - 2 | /dev/null c 666 0 0 1 3 0 0 - 3 | /dev/console c 600 0 0 5 1 0 0 - 4 | /dev/ttyO0 c 600 0 0 252 0 0 0 - 5 | 6 | -------------------------------------------------------------------------------- /Chapter05/run-qemu-initramfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | KERNEL=${HOME}/build_qemu/arch/arm64/boot/Image 4 | INITRAMFS=${HOME}/initramfs.cpio.gz 5 | 6 | if [ ! -f ${KERNEL} ]; then 7 | echo "${KERNEL} does not exist" 8 | exit 1 9 | fi 10 | 11 | if [ ! -f ${INITRAMFS} ]; then 12 | echo "${INITRAMFS} does not exist" 13 | exit 1 14 | fi 15 | 16 | qemu-system-aarch64 -M virt -cpu cortex-a53 -nographic -smp 1 -kernel ${KERNEL} -append "console=ttyAMA0 rdinit=/bin/sh" -initrd ${INITRAMFS} 17 | -------------------------------------------------------------------------------- /Chapter06/buildroot/board/meld/nova/genimage.cfg: -------------------------------------------------------------------------------- 1 | image boot.vfat { 2 | vfat { 3 | files = { 4 | "tiboot3.bin", 5 | "tispl.bin", 6 | "u-boot.img", 7 | "Image.gz", 8 | "k3-am625-beagleplay.dtb", 9 | } 10 | } 11 | 12 | size = 16M 13 | } 14 | 15 | image sdcard.img { 16 | hdimage { 17 | } 18 | 19 | partition u-boot { 20 | partition-type = 0xC 21 | bootable = "true" 22 | image = "boot.vfat" 23 | } 24 | 25 | partition rootfs { 26 | partition-type = 0x83 27 | image = "rootfs.ext4" 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /Chapter06/buildroot/board/meld/nova/nova.dts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * https://beagleplay.org/ 4 | * 5 | * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ 6 | * Copyright (C) 2022-2023 Robert Nelson, BeagleBoard.org Foundation 7 | */ 8 | 9 | /dts-v1/; 10 | 11 | #include 12 | #include 13 | #include 14 | #include "ti/k3-am625.dtsi" 15 | 16 | / { 17 | compatible = "beagle,am625-beagleplay", "ti,am625"; 18 | model = "Nova"; 19 | 20 | aliases { 21 | ethernet0 = &cpsw_port1; 22 | ethernet1 = &cpsw_port2; 23 | gpio0 = &main_gpio0; 24 | gpio1 = &main_gpio1; 25 | gpio2 = &mcu_gpio0; 26 | i2c0 = &main_i2c0; 27 | i2c1 = &main_i2c1; 28 | i2c2 = &main_i2c2; 29 | i2c3 = &main_i2c3; 30 | i2c4 = &wkup_i2c0; 31 | i2c5 = &mcu_i2c0; 32 | mdio-gpio0 = &mdio0; 33 | mmc0 = &sdhci0; 34 | mmc1 = &sdhci1; 35 | mmc2 = &sdhci2; 36 | rtc0 = &rtc; 37 | serial0 = &main_uart5; 38 | serial1 = &main_uart6; 39 | serial2 = &main_uart0; 40 | usb0 = &usb0; 41 | usb1 = &usb1; 42 | }; 43 | 44 | chosen { 45 | stdout-path = "serial2:115200n8"; 46 | }; 47 | 48 | memory@80000000 { 49 | device_type = "memory"; 50 | /* 2G RAM */ 51 | reg = <0x00000000 0x80000000 0x00000000 0x80000000>; 52 | }; 53 | 54 | reserved-memory { 55 | #address-cells = <2>; 56 | #size-cells = <2>; 57 | ranges; 58 | 59 | ramoops: ramoops@9ca00000 { 60 | compatible = "ramoops"; 61 | reg = <0x00 0x9ca00000 0x00 0x00100000>; 62 | record-size = <0x8000>; 63 | console-size = <0x8000>; 64 | ftrace-size = <0x00>; 65 | pmsg-size = <0x8000>; 66 | }; 67 | 68 | secure_tfa_ddr: tfa@9e780000 { 69 | reg = <0x00 0x9e780000 0x00 0x80000>; 70 | no-map; 71 | }; 72 | 73 | secure_ddr: optee@9e800000 { 74 | reg = <0x00 0x9e800000 0x00 0x01800000>; 75 | no-map; 76 | }; 77 | 78 | wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9db00000 { 79 | compatible = "shared-dma-pool"; 80 | reg = <0x00 0x9db00000 0x00 0xc00000>; 81 | no-map; 82 | }; 83 | }; 84 | 85 | vsys_5v0: regulator-1 { 86 | compatible = "regulator-fixed"; 87 | regulator-name = "vsys_5v0"; 88 | regulator-min-microvolt = <5000000>; 89 | regulator-max-microvolt = <5000000>; 90 | regulator-always-on; 91 | regulator-boot-on; 92 | }; 93 | 94 | vdd_3v3: regulator-2 { 95 | /* output of TLV62595DMQR-U12 */ 96 | compatible = "regulator-fixed"; 97 | regulator-name = "vdd_3v3"; 98 | regulator-min-microvolt = <3300000>; 99 | regulator-max-microvolt = <3300000>; 100 | vin-supply = <&vsys_5v0>; 101 | regulator-always-on; 102 | regulator-boot-on; 103 | }; 104 | 105 | wlan_en: regulator-3 { 106 | /* OUTPUT of SN74AVC2T244DQMR */ 107 | compatible = "regulator-fixed"; 108 | regulator-name = "wlan_en"; 109 | regulator-min-microvolt = <1800000>; 110 | regulator-max-microvolt = <1800000>; 111 | enable-active-high; 112 | regulator-always-on; 113 | vin-supply = <&vdd_3v3>; 114 | gpio = <&main_gpio0 38 GPIO_ACTIVE_HIGH>; 115 | pinctrl-names = "default"; 116 | pinctrl-0 = <&wifi_en_pins_default>; 117 | }; 118 | 119 | vdd_3v3_sd: regulator-4 { 120 | /* output of TPS22918DBVR-U21 */ 121 | pinctrl-names = "default"; 122 | pinctrl-0 = <&vdd_3v3_sd_pins_default>; 123 | 124 | compatible = "regulator-fixed"; 125 | regulator-name = "vdd_3v3_sd"; 126 | regulator-min-microvolt = <3300000>; 127 | regulator-max-microvolt = <3300000>; 128 | enable-active-high; 129 | regulator-always-on; 130 | vin-supply = <&vdd_3v3>; 131 | gpio = <&main_gpio1 19 GPIO_ACTIVE_HIGH>; 132 | }; 133 | 134 | vdd_sd_dv: regulator-5 { 135 | compatible = "regulator-gpio"; 136 | regulator-name = "sd_hs200_switch"; 137 | pinctrl-names = "default"; 138 | pinctrl-0 = <&vdd_sd_dv_pins_default>; 139 | regulator-min-microvolt = <1800000>; 140 | regulator-max-microvolt = <3300000>; 141 | regulator-boot-on; 142 | vin-supply = <&ldo1_reg>; 143 | gpios = <&main_gpio1 49 GPIO_ACTIVE_HIGH>; 144 | states = <1800000 0x0>, 145 | <3300000 0x1>; 146 | }; 147 | 148 | leds { 149 | compatible = "gpio-leds"; 150 | 151 | led-0 { 152 | gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; 153 | linux,default-trigger = "heartbeat"; 154 | function = LED_FUNCTION_HEARTBEAT; 155 | default-state = "off"; 156 | }; 157 | 158 | led-1 { 159 | gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; 160 | linux,default-trigger = "disk-activity"; 161 | function = LED_FUNCTION_DISK_ACTIVITY; 162 | default-state = "keep"; 163 | }; 164 | 165 | led-2 { 166 | gpios = <&main_gpio0 5 GPIO_ACTIVE_HIGH>; 167 | function = LED_FUNCTION_CPU; 168 | }; 169 | 170 | led-3 { 171 | gpios = <&main_gpio0 6 GPIO_ACTIVE_HIGH>; 172 | function = LED_FUNCTION_LAN; 173 | }; 174 | 175 | led-4 { 176 | gpios = <&main_gpio0 9 GPIO_ACTIVE_HIGH>; 177 | function = LED_FUNCTION_WLAN; 178 | }; 179 | }; 180 | 181 | gpio_keys: gpio-keys { 182 | compatible = "gpio-keys"; 183 | autorepeat; 184 | pinctrl-names = "default"; 185 | pinctrl-0 = <&usr_button_pins_default>; 186 | 187 | usr: button-usr { 188 | label = "User Key"; 189 | linux,code = ; 190 | gpios = <&main_gpio0 18 GPIO_ACTIVE_LOW>; 191 | }; 192 | 193 | }; 194 | 195 | hdmi0: connector-hdmi { 196 | compatible = "hdmi-connector"; 197 | label = "hdmi"; 198 | type = "a"; 199 | port { 200 | hdmi_connector_in: endpoint { 201 | remote-endpoint = <&it66121_out>; 202 | }; 203 | }; 204 | }; 205 | 206 | sound { 207 | compatible = "simple-audio-card"; 208 | simple-audio-card,name = "it66121 HDMI"; 209 | simple-audio-card,format = "i2s"; 210 | simple-audio-card,bitclock-master = <&hdmi_dailink_master>; 211 | simple-audio-card,frame-master = <&hdmi_dailink_master>; 212 | 213 | hdmi_dailink_master: simple-audio-card,cpu { 214 | sound-dai = <&mcasp1>; 215 | system-clock-direction-out; 216 | }; 217 | 218 | simple-audio-card,codec { 219 | sound-dai = <&it66121>; 220 | }; 221 | }; 222 | 223 | /* Workaround for errata i2329 - just use mdio bitbang */ 224 | mdio0: mdio { 225 | compatible = "virtual,mdio-gpio"; 226 | pinctrl-names = "default"; 227 | pinctrl-0 = <&mdio0_pins_default>; 228 | gpios = <&main_gpio0 86 GPIO_ACTIVE_HIGH>, /* MDC */ 229 | <&main_gpio0 85 GPIO_ACTIVE_HIGH>; /* MDIO */ 230 | #address-cells = <1>; 231 | #size-cells = <0>; 232 | 233 | cpsw3g_phy0: ethernet-phy@0 { 234 | reg = <0>; 235 | }; 236 | 237 | cpsw3g_phy1: ethernet-phy@1 { 238 | reg = <1>; 239 | reset-gpios = <&main_gpio1 5 GPIO_ACTIVE_LOW>; 240 | reset-assert-us = <25>; 241 | reset-deassert-us = <60000>; /* T2 */ 242 | }; 243 | }; 244 | }; 245 | 246 | &main_pmx0 { 247 | gpio0_pins_default: gpio0-default-pins { 248 | pinctrl-single,pins = < 249 | AM62X_IOPAD(0x0004, PIN_INPUT, 7) /* (G25) OSPI0_LBCLKO.GPIO0_1 */ 250 | AM62X_IOPAD(0x0008, PIN_INPUT, 7) /* (J24) OSPI0_DQS.GPIO0_2 */ 251 | AM62X_IOPAD(0x000c, PIN_INPUT, 7) /* (E25) OSPI0_D0.GPIO0_3 */ 252 | AM62X_IOPAD(0x0010, PIN_INPUT, 7) /* (G24) OSPI0_D1.GPIO0_4 */ 253 | AM62X_IOPAD(0x0014, PIN_INPUT, 7) /* (F25) OSPI0_D2.GPIO0_5 */ 254 | AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ 255 | AM62X_IOPAD(0x0024, PIN_INPUT, 7) /* (H25) OSPI0_D6.GPIO0_9 */ 256 | AM62X_IOPAD(0x0028, PIN_INPUT, 7) /* (J22) OSPI0_D7.GPIO0_10 */ 257 | AM62X_IOPAD(0x002c, PIN_INPUT, 7) /* (F23) OSPI0_CSn0.GPIO0_11 */ 258 | AM62X_IOPAD(0x0030, PIN_INPUT, 7) /* (G21) OSPI0_CSn1.GPIO0_12 */ 259 | AM62X_IOPAD(0x0034, PIN_INPUT, 7) /* (H21) OSPI0_CSn2.GPIO0_13 */ 260 | AM62X_IOPAD(0x0038, PIN_INPUT, 7) /* (E24) OSPI0_CSn3.GPIO0_14 */ 261 | AM62X_IOPAD(0x00a4, PIN_INPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */ 262 | AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */ 263 | >; 264 | }; 265 | 266 | vdd_sd_dv_pins_default: vdd-sd-default-pins { 267 | pinctrl-single,pins = < 268 | AM62X_IOPAD(0x0244, PIN_OUTPUT, 7) /* (C17) MMC1_SDWP.GPIO1_49 */ 269 | >; 270 | }; 271 | 272 | usr_button_pins_default: usr-button-default-pins { 273 | pinctrl-single,pins = < 274 | AM62X_IOPAD(0x0048, PIN_INPUT, 7) /* (N25) GPMC0_AD3.GPIO0_18 */ 275 | >; 276 | }; 277 | 278 | grove_pins_default: grove-default-pins { 279 | pinctrl-single,pins = < 280 | AM62X_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ 281 | AM62X_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (A17) I2C1_SDA */ 282 | >; 283 | }; 284 | 285 | local_i2c_pins_default: local-i2c-default-pins { 286 | pinctrl-single,pins = < 287 | AM62X_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (B16) I2C0_SCL */ 288 | AM62X_IOPAD(0x01e4, PIN_INPUT_PULLUP, 0) /* (A16) I2C0_SDA */ 289 | >; 290 | }; 291 | 292 | i2c2_1v8_pins_default: i2c2-default-pins { 293 | pinctrl-single,pins = < 294 | AM62X_IOPAD(0x00b0, PIN_INPUT_PULLUP, 1) /* (K22) GPMC0_CSn2.I2C2_SCL */ 295 | AM62X_IOPAD(0x00b4, PIN_INPUT_PULLUP, 1) /* (K24) GPMC0_CSn3.I2C2_SDA */ 296 | >; 297 | }; 298 | 299 | mdio0_pins_default: mdio0-default-pins { 300 | pinctrl-single,pins = < 301 | AM62X_IOPAD(0x0160, PIN_OUTPUT, 7) /* (AD24) MDIO0_MDC.GPIO0_86 */ 302 | AM62X_IOPAD(0x015c, PIN_INPUT, 7) /* (AB22) MDIO0_MDIO.GPIO0_85 */ 303 | >; 304 | }; 305 | 306 | rgmii1_pins_default: rgmii1-default-pins { 307 | pinctrl-single,pins = < 308 | AM62X_IOPAD(0x014c, PIN_INPUT, 0) /* (AB17) RGMII1_RD0 */ 309 | AM62X_IOPAD(0x0150, PIN_INPUT, 0) /* (AC17) RGMII1_RD1 */ 310 | AM62X_IOPAD(0x0154, PIN_INPUT, 0) /* (AB16) RGMII1_RD2 */ 311 | AM62X_IOPAD(0x0158, PIN_INPUT, 0) /* (AA15) RGMII1_RD3 */ 312 | AM62X_IOPAD(0x0148, PIN_INPUT, 0) /* (AD17) RGMII1_RXC */ 313 | AM62X_IOPAD(0x0144, PIN_INPUT, 0) /* (AE17) RGMII1_RX_CTL */ 314 | AM62X_IOPAD(0x0134, PIN_OUTPUT, 0) /* (AE20) RGMII1_TD0 */ 315 | AM62X_IOPAD(0x0138, PIN_OUTPUT, 0) /* (AD20) RGMII1_TD1 */ 316 | AM62X_IOPAD(0x013c, PIN_OUTPUT, 0) /* (AE18) RGMII1_TD2 */ 317 | AM62X_IOPAD(0x0140, PIN_OUTPUT, 0) /* (AD18) RGMII1_TD3 */ 318 | AM62X_IOPAD(0x0130, PIN_OUTPUT, 0) /* (AE19) RGMII1_TXC */ 319 | AM62X_IOPAD(0x012c, PIN_OUTPUT, 0) /* (AD19) RGMII1_TX_CTL */ 320 | >; 321 | }; 322 | 323 | emmc_pins_default: emmc-default-pins { 324 | pinctrl-single,pins = < 325 | AM62X_IOPAD(0x0220, PIN_INPUT, 0) /* (Y3) MMC0_CMD */ 326 | AM62X_IOPAD(0x0218, PIN_INPUT, 0) /* (AB1) MMC0_CLK */ 327 | AM62X_IOPAD(0x0214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */ 328 | AM62X_IOPAD(0x0210, PIN_INPUT, 0) /* (AA1) MMC0_DAT1 */ 329 | AM62X_IOPAD(0x020c, PIN_INPUT, 0) /* (AA3) MMC0_DAT2 */ 330 | AM62X_IOPAD(0x0208, PIN_INPUT, 0) /* (Y4) MMC0_DAT3 */ 331 | AM62X_IOPAD(0x0204, PIN_INPUT, 0) /* (AB2) MMC0_DAT4 */ 332 | AM62X_IOPAD(0x0200, PIN_INPUT, 0) /* (AC1) MMC0_DAT5 */ 333 | AM62X_IOPAD(0x01fc, PIN_INPUT, 0) /* (AD2) MMC0_DAT6 */ 334 | AM62X_IOPAD(0x01f8, PIN_INPUT, 0) /* (AC2) MMC0_DAT7 */ 335 | >; 336 | }; 337 | 338 | vdd_3v3_sd_pins_default: vdd-3v3-sd-default-pins { 339 | pinctrl-single,pins = < 340 | AM62X_IOPAD(0x01c4, PIN_INPUT, 7) /* (B14) SPI0_D1_GPIO1_19 */ 341 | >; 342 | }; 343 | 344 | sd_pins_default: sd-default-pins { 345 | pinctrl-single,pins = < 346 | AM62X_IOPAD(0x023c, PIN_INPUT, 0) /* (A21) MMC1_CMD */ 347 | AM62X_IOPAD(0x0234, PIN_INPUT, 0) /* (B22) MMC1_CLK */ 348 | AM62X_IOPAD(0x0230, PIN_INPUT, 0) /* (A22) MMC1_DAT0 */ 349 | AM62X_IOPAD(0x022c, PIN_INPUT, 0) /* (B21) MMC1_DAT1 */ 350 | AM62X_IOPAD(0x0228, PIN_INPUT, 0) /* (C21) MMC1_DAT2 */ 351 | AM62X_IOPAD(0x0224, PIN_INPUT, 0) /* (D22) MMC1_DAT3 */ 352 | AM62X_IOPAD(0x0240, PIN_INPUT, 7) /* (D17) MMC1_SDCD.GPIO1_48 */ 353 | >; 354 | }; 355 | 356 | wifi_pins_default: wifi-default-pins { 357 | pinctrl-single,pins = < 358 | AM62X_IOPAD(0x0120, PIN_INPUT, 0) /* (C24) MMC2_CMD */ 359 | AM62X_IOPAD(0x0118, PIN_INPUT, 0) /* (D25) MMC2_CLK */ 360 | AM62X_IOPAD(0x0114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */ 361 | AM62X_IOPAD(0x0110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */ 362 | AM62X_IOPAD(0x010c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */ 363 | AM62X_IOPAD(0x0108, PIN_INPUT, 0) /* (D24) MMC2_DAT3 */ 364 | AM62X_IOPAD(0x0124, PIN_INPUT, 0) /* (A23) MMC2_SDCD */ 365 | AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */ 366 | >; 367 | }; 368 | 369 | wifi_en_pins_default: wifi-en-default-pins { 370 | pinctrl-single,pins = < 371 | AM62X_IOPAD(0x009c, PIN_OUTPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */ 372 | >; 373 | }; 374 | 375 | wifi_wlirq_pins_default: wifi-wlirq-default-pins { 376 | pinctrl-single,pins = < 377 | AM62X_IOPAD(0x00a8, PIN_INPUT, 7) /* (M21) GPMC0_CSn0.GPIO0_41 */ 378 | >; 379 | }; 380 | 381 | spe_pins_default: spe-default-pins { 382 | pinctrl-single,pins = < 383 | AM62X_IOPAD(0x0168, PIN_INPUT, 1) /* (AE21) RGMII2_TXC.RMII2_CRS_DV */ 384 | AM62X_IOPAD(0x0180, PIN_INPUT, 1) /* (AD23) RGMII2_RXC.RMII2_REF_CLK */ 385 | AM62X_IOPAD(0x0184, PIN_INPUT, 1) /* (AE23) RGMII2_RD0.RMII2_RXD0 */ 386 | AM62X_IOPAD(0x0188, PIN_INPUT, 1) /* (AB20) RGMII2_RD1.RMII2_RXD1 */ 387 | AM62X_IOPAD(0x017c, PIN_INPUT, 1) /* (AD22) RGMII2_RX_CTL.RMII2_RX_ER */ 388 | AM62X_IOPAD(0x016c, PIN_INPUT, 1) /* (Y18) RGMII2_TD0.RMII2_TXD0 */ 389 | AM62X_IOPAD(0x0170, PIN_INPUT, 1) /* (AA18) RGMII2_TD1.RMII2_TXD1 */ 390 | AM62X_IOPAD(0x0164, PIN_INPUT, 1) /* (AA19) RGMII2_TX_CTL.RMII2_TX_EN */ 391 | AM62X_IOPAD(0x018c, PIN_OUTPUT, 7) /* (AC21) RGMII2_RD2.GPIO1_5 */ 392 | AM62X_IOPAD(0x0190, PIN_INPUT, 7) /* (AE22) RGMII2_RD3.GPIO1_6 */ 393 | AM62X_IOPAD(0x01f0, PIN_OUTPUT, 5) /* (A18) EXT_REFCLK1.CLKOUT0 */ 394 | >; 395 | }; 396 | 397 | mikrobus_i2c_pins_default: mikrobus-i2c-default-pins { 398 | pinctrl-single,pins = < 399 | AM62X_IOPAD(0x01d0, PIN_INPUT_PULLUP, 2) /* (A15) UART0_CTSn.I2C3_SCL */ 400 | AM62X_IOPAD(0x01d4, PIN_INPUT_PULLUP, 2) /* (B15) UART0_RTSn.I2C3_SDA */ 401 | >; 402 | }; 403 | 404 | mikrobus_uart_pins_default: mikrobus-uart-default-pins { 405 | pinctrl-single,pins = < 406 | AM62X_IOPAD(0x01d8, PIN_INPUT, 1) /* (C15) MCAN0_TX.UART5_RXD */ 407 | AM62X_IOPAD(0x01dc, PIN_OUTPUT, 1) /* (E15) MCAN0_RX.UART5_TXD */ 408 | >; 409 | }; 410 | 411 | mikrobus_spi_pins_default: mikrobus-spi-default-pins { 412 | pinctrl-single,pins = < 413 | AM62X_IOPAD(0x01b0, PIN_INPUT, 1) /* (A20) MCASP0_ACLKR.SPI2_CLK */ 414 | AM62X_IOPAD(0x01ac, PIN_INPUT, 1) /* (E19) MCASP0_AFSR.SPI2_CS0 */ 415 | AM62X_IOPAD(0x0194, PIN_INPUT, 1) /* (B19) MCASP0_AXR3.SPI2_D0 */ 416 | AM62X_IOPAD(0x0198, PIN_INPUT, 1) /* (A19) MCASP0_AXR2.SPI2_D1 */ 417 | >; 418 | }; 419 | 420 | mikrobus_gpio_pins_default: mikrobus-gpio-default-pins { 421 | pinctrl-single,pins = < 422 | AM62X_IOPAD(0x019c, PIN_INPUT, 7) /* (B18) MCASP0_AXR1.GPIO1_9 */ 423 | AM62X_IOPAD(0x01a0, PIN_INPUT, 7) /* (E18) MCASP0_AXR0.GPIO1_10 */ 424 | AM62X_IOPAD(0x01a8, PIN_INPUT, 7) /* (D20) MCASP0_AFSX.GPIO1_12 */ 425 | >; 426 | }; 427 | 428 | console_pins_default: console-default-pins { 429 | pinctrl-single,pins = < 430 | AM62X_IOPAD(0x01c8, PIN_INPUT, 0) /* (D14) UART0_RXD */ 431 | AM62X_IOPAD(0x01cc, PIN_OUTPUT, 0) /* (E14) UART0_TXD */ 432 | >; 433 | }; 434 | 435 | wifi_debug_uart_pins_default: wifi-debug-uart-default-pins { 436 | pinctrl-single,pins = < 437 | AM62X_IOPAD(0x001c, PIN_INPUT, 3) /* (J23) OSPI0_D4.UART6_RXD */ 438 | AM62X_IOPAD(0x0020, PIN_OUTPUT, 3) /* (J25) OSPI0_D5.UART6_TXD */ 439 | >; 440 | }; 441 | 442 | usb1_pins_default: usb1-default-pins { 443 | pinctrl-single,pins = < 444 | AM62X_IOPAD(0x0258, PIN_INPUT, 0) /* (F18) USB1_DRVVBUS */ 445 | >; 446 | }; 447 | 448 | pmic_irq_pins_default: pmic-irq-default-pins { 449 | pinctrl-single,pins = < 450 | AM62X_IOPAD(0x01f4, PIN_INPUT_PULLUP, 0) /* (D16) EXTINTn */ 451 | >; 452 | }; 453 | 454 | hdmi_gpio_pins_default: hdmi-gpio-default-pins { 455 | pinctrl-single,pins = < 456 | AM62X_IOPAD(0x0094, PIN_INPUT_PULLUP | PIN_DEBOUNCE_CONF6, 7) /* (N20) GPMC0_BE1n.GPIO0_36 */ 457 | AM62X_IOPAD(0x0054, PIN_OUTPUT_PULLUP, 7) /* (P21) GPMC0_AD6.GPIO0_21 */ 458 | >; 459 | }; 460 | 461 | mcasp_hdmi_pins_default: mcasp-hdmi-default-pins { 462 | pinctrl-single,pins = < 463 | AM62X_IOPAD(0x0090, PIN_INPUT, 2) /* (M24) GPMC0_BE0n_CLE.MCASP1_ACLKX */ 464 | AM62X_IOPAD(0x0098, PIN_INPUT, 2) /* (U23) GPMC0_WAIT0.MCASP1_AFSX */ 465 | AM62X_IOPAD(0x008c, PIN_OUTPUT, 2) /* (L25) GPMC0_WEn.MCASP1_AXR0 */ 466 | AM62X_IOPAD(0x0088, PIN_INPUT, 2) /* (L24) GPMC0_OEn_REn.MCASP1_AXR1 */ 467 | AM62X_IOPAD(0x0084, PIN_INPUT, 2) /* (L23) GPMC0_ADVn_ALE.MCASP1_AXR2 */ 468 | AM62X_IOPAD(0x007c, PIN_INPUT, 2) /* (P25) GPMC0_CLK.MCASP1_AXR3 */ 469 | >; 470 | }; 471 | 472 | dss0_pins_default: dss0-default-pins { 473 | pinctrl-single,pins = < 474 | AM62X_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC */ 475 | AM62X_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ 476 | AM62X_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK */ 477 | AM62X_IOPAD(0x00fc, PIN_OUTPUT, 0) /* (Y20) VOUT0_DE */ 478 | AM62X_IOPAD(0x00b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ 479 | AM62X_IOPAD(0x00bc, PIN_OUTPUT, 0) /* (V24) VOUT0_DATA1 */ 480 | AM62X_IOPAD(0x00c0, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA2 */ 481 | AM62X_IOPAD(0x00c4, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA3 */ 482 | AM62X_IOPAD(0x00c8, PIN_OUTPUT, 0) /* (Y25) VOUT0_DATA4 */ 483 | AM62X_IOPAD(0x00cc, PIN_OUTPUT, 0) /* (Y24) VOUT0_DATA5 */ 484 | AM62X_IOPAD(0x00d0, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA6 */ 485 | AM62X_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7 */ 486 | AM62X_IOPAD(0x00d8, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA8 */ 487 | AM62X_IOPAD(0x00dc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA9 */ 488 | AM62X_IOPAD(0x00e0, PIN_OUTPUT, 0) /* (V20) VOUT0_DATA10 */ 489 | AM62X_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11 */ 490 | AM62X_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12 */ 491 | AM62X_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13 */ 492 | AM62X_IOPAD(0x00f0, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA14 */ 493 | AM62X_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15 */ 494 | AM62X_IOPAD(0x005c, PIN_OUTPUT, 1) /* (R24) GPMC0_AD8.VOUT0_DATA16 */ 495 | AM62X_IOPAD(0x0060, PIN_OUTPUT, 1) /* (R25) GPMC0_AD9.VOUT0_DATA17 */ 496 | AM62X_IOPAD(0x0064, PIN_OUTPUT, 1) /* (T25) GPMC0_AD10.VOUT0_DATA18 */ 497 | AM62X_IOPAD(0x0068, PIN_OUTPUT, 1) /* (R21) GPMC0_AD11.VOUT0_DATA19 */ 498 | AM62X_IOPAD(0x006c, PIN_OUTPUT, 1) /* (T22) GPMC0_AD12.VOUT0_DATA20 */ 499 | AM62X_IOPAD(0x0070, PIN_OUTPUT, 1) /* (T24) GPMC0_AD13.VOUT0_DATA21 */ 500 | AM62X_IOPAD(0x0074, PIN_OUTPUT, 1) /* (U25) GPMC0_AD14.VOUT0_DATA22 */ 501 | AM62X_IOPAD(0x0078, PIN_OUTPUT, 1) /* (U24) GPMC0_AD15.VOUT0_DATA23 */ 502 | >; 503 | }; 504 | }; 505 | 506 | &mcu_pmx0 { 507 | i2c_qwiic_pins_default: i2c-qwiic-default-pins { 508 | pinctrl-single,pins = < 509 | AM62X_MCU_IOPAD(0x0044, PIN_INPUT, 0) /* (A8) MCU_I2C0_SCL */ 510 | AM62X_MCU_IOPAD(0x0048, PIN_INPUT, 0) /* (D10) MCU_I2C0_SDA */ 511 | >; 512 | }; 513 | 514 | gbe_pmx_obsclk: gbe-pmx-obsclk-default-pins { 515 | pinctrl-single,pins = < 516 | AM62X_MCU_IOPAD(0x0004, PIN_OUTPUT, 1) /* (B8) MCU_SPI0_CS1.MCU_OBSCLK0 */ 517 | >; 518 | }; 519 | 520 | i2c_csi_pins_default: i2c-csi-default-pins { 521 | pinctrl-single,pins = < 522 | AM62X_MCU_IOPAD(0x004c, PIN_INPUT_PULLUP, 0) /* (B9) WKUP_I2C0_SCL */ 523 | AM62X_MCU_IOPAD(0x0050, PIN_INPUT_PULLUP, 0) /* (A9) WKUP_I2C0_SDA */ 524 | >; 525 | }; 526 | 527 | wifi_32k_clk: mcu-clk-out-default-pins { 528 | pinctrl-single,pins = < 529 | AM62X_MCU_IOPAD(0x0084, PIN_OUTPUT, 0) /* (A12) WKUP_CLKOUT0 */ 530 | >; 531 | }; 532 | }; 533 | 534 | &a53_opp_table { 535 | /* Requires VDD_CORE to be at 0.85V */ 536 | opp-1400000000 { 537 | opp-hz = /bits/ 64 <1400000000>; 538 | opp-supported-hw = <0x01 0x0004>; 539 | }; 540 | }; 541 | 542 | &wkup_i2c0 { 543 | pinctrl-names = "default"; 544 | pinctrl-0 = <&i2c_csi_pins_default>; 545 | clock-frequency = <400000>; 546 | /* Enable with overlay for camera sensor */ 547 | }; 548 | 549 | &mcu_i2c0 { 550 | pinctrl-names = "default"; 551 | pinctrl-0 = <&i2c_qwiic_pins_default>; 552 | clock-frequency = <100000>; 553 | status = "okay"; 554 | }; 555 | 556 | &usbss0 { 557 | ti,vbus-divider; 558 | status = "okay"; 559 | }; 560 | 561 | &usb0 { 562 | dr_mode = "peripheral"; 563 | }; 564 | 565 | &usbss1 { 566 | ti,vbus-divider; 567 | status = "okay"; 568 | }; 569 | 570 | &usb1 { 571 | dr_mode = "host"; 572 | pinctrl-names = "default"; 573 | pinctrl-0 = <&usb1_pins_default>; 574 | }; 575 | 576 | &cpsw3g { 577 | pinctrl-names = "default"; 578 | pinctrl-0 = <&rgmii1_pins_default>, <&spe_pins_default>, 579 | <&gbe_pmx_obsclk>; 580 | assigned-clocks = <&k3_clks 157 70>, <&k3_clks 157 20>; 581 | assigned-clock-parents = <&k3_clks 157 72>, <&k3_clks 157 22>; 582 | }; 583 | 584 | &cpsw_port1 { 585 | phy-mode = "rgmii-rxid"; 586 | phy-handle = <&cpsw3g_phy0>; 587 | }; 588 | 589 | &cpsw_port2 { 590 | phy-mode = "rmii"; 591 | phy-handle = <&cpsw3g_phy1>; 592 | }; 593 | 594 | &cpsw3g_mdio { 595 | /* Workaround for errata i2329 - Use mdio bitbang */ 596 | status = "disabled"; 597 | }; 598 | 599 | &main_gpio0 { 600 | pinctrl-names = "default"; 601 | pinctrl-0 = <&gpio0_pins_default>; 602 | gpio-line-names = "BL_EN_3V3", "SPE_PO_EN", "RTC_INT", /* 0-2 */ 603 | "USR0", "USR1", "USR2", "USR3", "", "", "USR4", /* 3-9 */ 604 | "EEPROM_WP", /* 10 */ 605 | "CSI2_CAMERA_GPIO1", "CSI2_CAMERA_GPIO2", /* 11-12 */ 606 | "CC1352P7_BOOT", "CC1352P7_RSTN", "", "", "", /* 13-17 */ 607 | "USR_BUTTON", "", "", "", "", "", "", "", "", /* 18-26 */ 608 | "", "", "", "", "", "", "", "", "", "HDMI_INT", /* 27-36 */ 609 | "", "VDD_WLAN_EN", "", "", "WL_IRQ", "GBE_INTN",/* 37-42 */ 610 | "", "", "", "", "", "", "", "", "", "", "", "", /* 43-54 */ 611 | "", "", "", "", "", "", "", "", "", "", "", "", /* 55-66 */ 612 | "", "", "", "", "", "", "", "", "", "", "", "", /* 67-78 */ 613 | "", "", "", "", "", "", /* 79-84 */ 614 | "BITBANG_MDIO_DATA", "BITBANG_MDIO_CLK", /* 85-86 */ 615 | "", "", "", "", ""; /* 87-91 */ 616 | }; 617 | 618 | &main_gpio1 { 619 | pinctrl-names = "default"; 620 | pinctrl-0 = <&mikrobus_gpio_pins_default>; 621 | gpio-line-names = "", "", "", "", "", /* 0-4 */ 622 | "SPE_RSTN", "SPE_INTN", "MIKROBUS_GPIO1_7", /* 5-7 */ 623 | "MIKROBUS_GPIO1_8", "MIKROBUS_GPIO1_9", /* 8-9 */ 624 | "MIKROBUS_GPIO1_10", "MIKROBUS_GPIO1_11", /* 10-11 */ 625 | "MIKROBUS_GPIO1_12", "MIKROBUS_W1_GPIO0", /* 12-13 */ 626 | "MIKROBUS_GPIO1_14", /* 14 */ 627 | "", "", "", "", "VDD_3V3_SD", "", "", /* 15-21 */ 628 | "MIKROBUS_GPIO1_22", "MIKROBUS_GPIO1_23", /* 22-23 */ 629 | "MIKROBUS_GPIO1_24", "MIKROBUS_GPIO1_25", /* 24-25 */ 630 | "", "", "", "", "", "", "", "", "", "", "", "", /* 26-37 */ 631 | "", "", "", "", "", "", "", "", "", "", /* 38-47 */ 632 | "SD_CD", "SD_VOLT_SEL", "", ""; /* 48-51 */ 633 | }; 634 | 635 | &main_i2c0 { 636 | pinctrl-names = "default"; 637 | pinctrl-0 = <&local_i2c_pins_default>; 638 | clock-frequency = <400000>; 639 | status = "okay"; 640 | 641 | eeprom@50 { 642 | compatible = "atmel,24c32"; 643 | reg = <0x50>; 644 | }; 645 | 646 | rtc: rtc@68 { 647 | compatible = "ti,bq32000"; 648 | reg = <0x68>; 649 | interrupt-parent = <&main_gpio0>; 650 | interrupts = <2 IRQ_TYPE_EDGE_FALLING>; 651 | }; 652 | 653 | tps65219: pmic@30 { 654 | compatible = "ti,tps65219"; 655 | reg = <0x30>; 656 | buck1-supply = <&vsys_5v0>; 657 | buck2-supply = <&vsys_5v0>; 658 | buck3-supply = <&vsys_5v0>; 659 | ldo1-supply = <&vdd_3v3>; 660 | ldo2-supply = <&buck2_reg>; 661 | ldo3-supply = <&vdd_3v3>; 662 | ldo4-supply = <&vdd_3v3>; 663 | 664 | pinctrl-names = "default"; 665 | pinctrl-0 = <&pmic_irq_pins_default>; 666 | interrupt-parent = <&gic500>; 667 | interrupts = ; 668 | interrupt-controller; 669 | #interrupt-cells = <1>; 670 | 671 | system-power-controller; 672 | ti,power-button; 673 | 674 | regulators { 675 | buck1_reg: buck1 { 676 | regulator-name = "VDD_CORE"; 677 | regulator-min-microvolt = <850000>; 678 | regulator-max-microvolt = <850000>; 679 | regulator-boot-on; 680 | regulator-always-on; 681 | }; 682 | 683 | buck2_reg: buck2 { 684 | regulator-name = "VDD_1V8"; 685 | regulator-min-microvolt = <1800000>; 686 | regulator-max-microvolt = <1800000>; 687 | regulator-boot-on; 688 | regulator-always-on; 689 | }; 690 | 691 | buck3_reg: buck3 { 692 | regulator-name = "VDD_1V2"; 693 | regulator-min-microvolt = <1200000>; 694 | regulator-max-microvolt = <1200000>; 695 | regulator-boot-on; 696 | regulator-always-on; 697 | }; 698 | 699 | ldo1_reg: ldo1 { 700 | /* 701 | * Regulator is left as is unused, vdd_sd 702 | * is controlled via GPIO with bypass config 703 | * as per the NVM configuration 704 | */ 705 | regulator-name = "VDD_SD_3V3"; 706 | regulator-min-microvolt = <3300000>; 707 | regulator-max-microvolt = <3300000>; 708 | regulator-allow-bypass; 709 | regulator-boot-on; 710 | regulator-always-on; 711 | }; 712 | 713 | ldo2_reg: ldo2 { 714 | regulator-name = "VDDA_0V85"; 715 | regulator-min-microvolt = <850000>; 716 | regulator-max-microvolt = <850000>; 717 | regulator-boot-on; 718 | regulator-always-on; 719 | }; 720 | 721 | ldo3_reg: ldo3 { 722 | regulator-name = "VDDA_1V8"; 723 | regulator-min-microvolt = <1800000>; 724 | regulator-max-microvolt = <1800000>; 725 | regulator-boot-on; 726 | regulator-always-on; 727 | }; 728 | 729 | ldo4_reg: ldo4 { 730 | regulator-name = "VDD_2V5"; 731 | regulator-min-microvolt = <2500000>; 732 | regulator-max-microvolt = <2500000>; 733 | regulator-boot-on; 734 | regulator-always-on; 735 | }; 736 | }; 737 | }; 738 | }; 739 | 740 | &main_i2c1 { 741 | pinctrl-names = "default"; 742 | pinctrl-0 = <&grove_pins_default>; 743 | clock-frequency = <100000>; 744 | status = "okay"; 745 | }; 746 | 747 | &main_i2c2 { 748 | pinctrl-names = "default"; 749 | pinctrl-0 = <&i2c2_1v8_pins_default>; 750 | clock-frequency = <100000>; 751 | status = "okay"; 752 | 753 | it66121: bridge-hdmi@4c { 754 | compatible = "ite,it66121"; 755 | reg = <0x4c>; 756 | pinctrl-names = "default"; 757 | pinctrl-0 = <&hdmi_gpio_pins_default>; 758 | vcn33-supply = <&vdd_3v3>; 759 | vcn18-supply = <&buck2_reg>; 760 | vrf12-supply = <&buck3_reg>; 761 | reset-gpios = <&main_gpio0 21 GPIO_ACTIVE_LOW>; 762 | interrupt-parent = <&main_gpio0>; 763 | interrupts = <36 IRQ_TYPE_EDGE_FALLING>; 764 | #sound-dai-cells = <0>; 765 | 766 | ports { 767 | #address-cells = <1>; 768 | #size-cells = <0>; 769 | 770 | port@0 { 771 | reg = <0>; 772 | 773 | it66121_in: endpoint { 774 | bus-width = <24>; 775 | remote-endpoint = <&dpi1_out>; 776 | }; 777 | }; 778 | 779 | port@1 { 780 | reg = <1>; 781 | 782 | it66121_out: endpoint { 783 | remote-endpoint = <&hdmi_connector_in>; 784 | }; 785 | }; 786 | }; 787 | }; 788 | }; 789 | 790 | &main_i2c3 { 791 | pinctrl-names = "default"; 792 | pinctrl-0 = <&mikrobus_i2c_pins_default>; 793 | clock-frequency = <400000>; 794 | status = "okay"; 795 | }; 796 | 797 | &main_spi2 { 798 | pinctrl-names = "default"; 799 | pinctrl-0 = <&mikrobus_spi_pins_default>; 800 | status = "okay"; 801 | }; 802 | 803 | &sdhci0 { 804 | pinctrl-names = "default"; 805 | pinctrl-0 = <&emmc_pins_default>; 806 | ti,driver-strength-ohm = <50>; 807 | disable-wp; 808 | status = "okay"; 809 | }; 810 | 811 | &sdhci1 { 812 | /* SD/MMC */ 813 | pinctrl-names = "default"; 814 | pinctrl-0 = <&sd_pins_default>; 815 | 816 | vmmc-supply = <&vdd_3v3_sd>; 817 | vqmmc-supply = <&vdd_sd_dv>; 818 | ti,driver-strength-ohm = <50>; 819 | disable-wp; 820 | cd-gpios = <&main_gpio1 48 GPIO_ACTIVE_LOW>; 821 | cd-debounce-delay-ms = <100>; 822 | ti,fails-without-test-cd; 823 | status = "okay"; 824 | }; 825 | 826 | &sdhci2 { 827 | vmmc-supply = <&wlan_en>; 828 | pinctrl-names = "default"; 829 | pinctrl-0 = <&wifi_pins_default>, <&wifi_32k_clk>; 830 | bus-width = <4>; 831 | non-removable; 832 | ti,fails-without-test-cd; 833 | cap-power-off-card; 834 | keep-power-in-suspend; 835 | ti,driver-strength-ohm = <50>; 836 | assigned-clocks = <&k3_clks 157 158>; 837 | assigned-clock-parents = <&k3_clks 157 160>; 838 | #address-cells = <1>; 839 | #size-cells = <0>; 840 | status = "okay"; 841 | 842 | wlcore: wlcore@2 { 843 | compatible = "ti,wl1807"; 844 | reg = <2>; 845 | pinctrl-names = "default"; 846 | pinctrl-0 = <&wifi_wlirq_pins_default>; 847 | interrupt-parent = <&main_gpio0>; 848 | interrupts = <41 IRQ_TYPE_EDGE_FALLING>; 849 | }; 850 | }; 851 | 852 | &main_uart0 { 853 | pinctrl-names = "default"; 854 | pinctrl-0 = <&console_pins_default>; 855 | status = "okay"; 856 | }; 857 | 858 | &main_uart1 { 859 | /* Main UART1 is used by TIFS firmware */ 860 | status = "reserved"; 861 | }; 862 | 863 | &main_uart5 { 864 | pinctrl-names = "default"; 865 | pinctrl-0 = <&mikrobus_uart_pins_default>; 866 | status = "okay"; 867 | }; 868 | 869 | &main_uart6 { 870 | pinctrl-names = "default"; 871 | pinctrl-0 = <&wifi_debug_uart_pins_default>; 872 | status = "okay"; 873 | }; 874 | 875 | &dss { 876 | status = "okay"; 877 | pinctrl-names = "default"; 878 | pinctrl-0 = <&dss0_pins_default>; 879 | }; 880 | 881 | &dss_ports { 882 | /* VP2: DPI Output */ 883 | port@1 { 884 | reg = <1>; 885 | 886 | dpi1_out: endpoint { 887 | remote-endpoint = <&it66121_in>; 888 | }; 889 | }; 890 | }; 891 | 892 | &mcasp1 { 893 | status = "okay"; 894 | #sound-dai-cells = <0>; 895 | pinctrl-names = "default"; 896 | pinctrl-0 = <&mcasp_hdmi_pins_default>; 897 | auxclk-fs-ratio = <2177>; 898 | op-mode = <0>; /* MCASP_IIS_MODE */ 899 | tdm-slots = <2>; 900 | serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ 901 | 1 0 0 0 902 | 0 0 0 0 903 | 0 0 0 0 904 | 0 0 0 0 905 | >; 906 | }; 907 | -------------------------------------------------------------------------------- /Chapter06/buildroot/board/meld/nova/post-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | BOARD_DIR="$(dirname $0)" 3 | 4 | cp ${BUILD_DIR}/ti-k3-r5-loader-2022.10/tiboot3.bin $BINARIES_DIR/tiboot3.bin 5 | 6 | GENIMAGE_CFG="${BOARD_DIR}/genimage.cfg" GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp" 7 | 8 | rm -rf "${GENIMAGE_TMP}" 9 | 10 | genimage \ 11 | --rootpath "${TARGET_DIR}" \ 12 | --tmppath "${GENIMAGE_TMP}" \ 13 | --inputpath "${BINARIES_DIR}" \ 14 | --outputpath "${BINARIES_DIR}" \ 15 | --config "${GENIMAGE_CFG}" 16 | -------------------------------------------------------------------------------- /Chapter06/buildroot/configs/nova_defconfig: -------------------------------------------------------------------------------- 1 | BR2_aarch64=y 2 | BR2_ROOTFS_POST_IMAGE_SCRIPT="board/meld/nova/post-image.sh" 3 | BR2_ROOTFS_POST_SCRIPT_ARGS="-c board/meld/nova/genimage.cfg" 4 | BR2_LINUX_KERNEL=y 5 | BR2_LINUX_KERNEL_CUSTOM_VERSION=y 6 | BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.6.46" 7 | BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y 8 | BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/meld/nova/linux.config" 9 | BR2_LINUX_KERNEL_IMAGEGZ=y 10 | BR2_LINUX_KERNEL_DTS_SUPPORT=y 11 | BR2_LINUX_KERNEL_CUSTOM_DTS_PATH="board/meld/nova/nova.dts" 12 | BR2_LINUX_KERNEL_INSTALL_TARGET=y 13 | BR2_PACKAGE_LINUX_FIRMWARE=y 14 | BR2_PACKAGE_LINUX_FIRMWARE_TI_WL18XX=y 15 | BR2_TARGET_ROOTFS_EXT2=y 16 | BR2_TARGET_ROOTFS_EXT2_4=y 17 | BR2_TARGET_ROOTFS_EXT2_SIZE="256M" 18 | BR2_TARGET_ARM_TRUSTED_FIRMWARE=y 19 | BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_VERSION=y 20 | BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_VERSION_VALUE="v2.7" 21 | BR2_TARGET_ARM_TRUSTED_FIRMWARE_PLATFORM="k3" 22 | BR2_TARGET_ARM_TRUSTED_FIRMWARE_TARGET_BOARD="lite" 23 | BR2_TARGET_ARM_TRUSTED_FIRMWARE_BL32_OPTEE=y 24 | BR2_TARGET_OPTEE_OS=y 25 | BR2_TARGET_OPTEE_OS_PLATFORM="k3" 26 | BR2_TARGET_TI_K3_IMAGE_GEN=y 27 | BR2_TARGET_TI_K3_IMAGE_GEN_SOC_AM62X=y 28 | BR2_TARGET_TI_K3_R5_LOADER=y 29 | BR2_TARGET_TI_K3_R5_LOADER_BOARD_DEFCONFIG="am62x_evm_r5" 30 | BR2_TARGET_UBOOT=y 31 | BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y 32 | BR2_TARGET_UBOOT_CUSTOM_GIT=y 33 | BR2_TARGET_UBOOT_CUSTOM_REPO_URL="https://github.com/beagleboard/u-boot" 34 | BR2_TARGET_UBOOT_CUSTOM_REPO_VERSION="f036fb" 35 | BR2_TARGET_UBOOT_PATCH="board/meld/nova/0001-BSP-for-Nova.patch" 36 | BR2_TARGET_UBOOT_BOARD_DEFCONFIG="am62x_evm_a53" 37 | BR2_TARGET_UBOOT_NEEDS_DTC=y 38 | BR2_TARGET_UBOOT_NEEDS_PYLIBFDT=y 39 | BR2_TARGET_UBOOT_NEEDS_OPENSSL=y 40 | BR2_TARGET_UBOOT_NEEDS_ATF_BL31=y 41 | BR2_TARGET_UBOOT_NEEDS_TI_K3_DM=y 42 | # BR2_TARGET_UBOOT_FORMAT_BIN is not set 43 | BR2_TARGET_UBOOT_FORMAT_IMG=y 44 | BR2_TARGET_UBOOT_SPL=y 45 | BR2_TARGET_UBOOT_SPL_NAME="tispl.bin" 46 | BR2_TARGET_UBOOT_CUSTOM_MAKEOPTS="TEE=$(BINARIES_DIR)/tee-pager_v2.bin BINMAN_INDIRS=$(HOME)/ti-linux-firmware" 47 | BR2_PACKAGE_HOST_DOSFSTOOLS=y 48 | BR2_PACKAGE_HOST_GENIMAGE=y 49 | BR2_PACKAGE_HOST_MTOOLS=y 50 | -------------------------------------------------------------------------------- /Chapter06/buildroot/package/helloworld/Config.in: -------------------------------------------------------------------------------- 1 | config BR2_PACKAGE_HELLOWORLD 2 | bool "helloworld" 3 | help 4 | A friendly program that prints Hello World! every 10s 5 | -------------------------------------------------------------------------------- /Chapter06/buildroot/package/helloworld/helloworld.mk: -------------------------------------------------------------------------------- 1 | HELLOWORLD_VERSION = 1.0.0 2 | HELLOWORLD_SITE = /home/frank/MELD/Chapter06/helloworld 3 | HELLOWORLD_SITE_METHOD = local 4 | 5 | define HELLOWORLD_BUILD_CMDS 6 | $(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(@D) all 7 | endef 8 | 9 | define HELLOWORLD_INSTALL_TARGET_CMDS 10 | $(INSTALL) -D -m 0755 $(@D)/helloworld $(TARGET_DIR)/usr/bin/helloworld 11 | endef 12 | 13 | $(eval $(generic-package)) 14 | 15 | -------------------------------------------------------------------------------- /Chapter06/helloworld/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -g 2 | PROGS=helloworld 3 | 4 | all: $(PROGS) 5 | 6 | $(PROGS): $(PROGS).c 7 | $(CC) $(CFLAGS) -o $@ $^ 8 | 9 | clean: 10 | rm -f *.o 11 | rm -f $(PROGS) 12 | 13 | install: 14 | cp $(PROGS) $(TARGET_DIR)/usr/local/bin 15 | 16 | -------------------------------------------------------------------------------- /Chapter06/helloworld/helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (int argc, char *argv[]) 5 | { 6 | printf("Hello world!\n"); 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /Chapter06/meta-nova/README: -------------------------------------------------------------------------------- 1 | This README file contains information on the contents of the 2 | nova layer. 3 | 4 | Please see the corresponding sections below for details. 5 | 6 | 7 | Dependencies 8 | ============ 9 | 10 | This layer depends on: 11 | 12 | URI: git://git.openembedded.org/bitbake 13 | branch: master 14 | 15 | URI: git://git.openembedded.org/openembedded-core 16 | layers: meta 17 | branch: master 18 | 19 | URI: git://git.yoctoproject.org/xxxx 20 | layers: xxxx 21 | branch: master 22 | 23 | 24 | Patches 25 | ======= 26 | 27 | Please submit any patches against the nova layer to the 28 | xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: 29 | 30 | Maintainer: XXX YYYYYY 31 | 32 | 33 | Table of Contents 34 | ================= 35 | 36 | I. Adding the nova layer to your build 37 | II. Misc 38 | 39 | 40 | I. Adding the nova layer to your build 41 | ================================================= 42 | 43 | --- replace with specific instructions for the nova layer --- 44 | 45 | In order to use this layer, you need to make the build system aware of 46 | it. 47 | 48 | Assuming the nova layer exists at the top-level of your 49 | yocto build tree, you can add it to the build system by adding the 50 | location of the nova layer to bblayers.conf, along with any 51 | other layers needed. e.g.: 52 | 53 | BBLAYERS ?= " \ 54 | /path/to/yocto/meta \ 55 | /path/to/yocto/meta-poky \ 56 | /path/to/yocto/meta-yocto-bsp \ 57 | /path/to/yocto/meta-nova \ 58 | " 59 | 60 | 61 | II. Misc 62 | ======== 63 | 64 | --- replace with specific information about the nova layer --- 65 | -------------------------------------------------------------------------------- /Chapter06/meta-nova/conf/layer.conf: -------------------------------------------------------------------------------- 1 | # We have a conf and classes directory, add to BBPATH 2 | BBPATH .= ":${LAYERDIR}" 3 | 4 | # We have recipes-* directories, add to BBFILES 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" 7 | 8 | BBFILE_COLLECTIONS += "nova" 9 | BBFILE_PATTERN_nova = "^${LAYERDIR}/" 10 | BBFILE_PRIORITY_nova = "6" 11 | 12 | LAYERDEPENDS_nova = "core" 13 | LAYERSERIES_COMPAT_nova = "scarthgap" 14 | -------------------------------------------------------------------------------- /Chapter06/meta-nova/recipes-local/helloworld/files/helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | while(1) { 7 | printf("Hello, world!\n"); 8 | sleep(10); 9 | } 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /Chapter06/meta-nova/recipes-local/helloworld/helloworld_1.0.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "A friendly program that prints Hello World!" 2 | PRIORITY = "optional" 3 | SECTION = "examples" 4 | 5 | LICENSE = "GPL-2.0-only" 6 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" 7 | 8 | SRC_URI = "file://helloworld.c" 9 | 10 | S = "${WORKDIR}" 11 | 12 | do_compile() { 13 | ${CC} ${CFLAGS} ${LDFLAGS} helloworld.c -o helloworld 14 | } 15 | 16 | do_install() { 17 | install -d ${D}${bindir} 18 | install -m 0755 helloworld ${D}${bindir} 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Chapter06/meta-nova/recipes-local/images/nova-image.bb: -------------------------------------------------------------------------------- 1 | require recipes-core/images/core-image-minimal.bb 2 | IMAGE_INSTALL += "helloworld strace" 3 | 4 | -------------------------------------------------------------------------------- /Chapter07/meta-gattd/README: -------------------------------------------------------------------------------- 1 | This README file contains information on the contents of the meta-gattd layer. 2 | 3 | Please see the corresponding sections below for details. 4 | 5 | Dependencies 6 | ============ 7 | 8 | URI: git://git.yoctoproject.org/poky.git 9 | branch: kirkstone 10 | 11 | URI: git://git.openembedded.org/meta-openembedded 12 | branch: kirkstone 13 | 14 | URI: git://git.yoctoproject.org/meta-raspberrypi 15 | branch: kirkstone 16 | 17 | Patches 18 | ======= 19 | 20 | Please submit any patches against the meta-gattd layer to the maintainer: 21 | 22 | Maintainer: Frank Vasquez 23 | 24 | Table of Contents 25 | ================= 26 | 27 | I. Adding the meta-gattd layer to your build 28 | II. Misc 29 | 30 | 31 | I. Adding the meta-gattd layer to your build 32 | ================================================= 33 | 34 | bitbake-layers add-layer ../meta-openembedded/meta-oe 35 | bitbake-layers add-layer ../meta-openembedded/meta-python 36 | bitbake-layers add-layer ../meta-openembedded/meta-networking 37 | bitbake-layers add-layer ../meta-openembedded/meta-multimedia 38 | bitbake-layers add-layer ../meta-raspberrypi 39 | bitbake-layers add-layer ../meta-gattd 40 | 41 | II. Misc 42 | ======== 43 | 44 | This layer contains a BLE GATT server written in Python. 45 | This GATT daemon depends on BlueZ which requires D-Bus. 46 | Only the Raspberry Pi 3/4 are targeted because they have a Bluetooth module. 47 | -------------------------------------------------------------------------------- /Chapter07/meta-gattd/conf/layer.conf: -------------------------------------------------------------------------------- 1 | # We have a conf and classes directory, add to BBPATH 2 | BBPATH .= ":${LAYERDIR}" 3 | 4 | # We have recipes-* directories, add to BBFILES 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" 7 | 8 | BBFILE_COLLECTIONS += "meta-gattd" 9 | BBFILE_PATTERN_meta-gattd = "^${LAYERDIR}/" 10 | BBFILE_PRIORITY_meta-gattd = "6" 11 | 12 | LAYERDEPENDS_meta-gattd = "core" 13 | LAYERSERIES_COMPAT_meta-gattd = "scarthgap" 14 | -------------------------------------------------------------------------------- /Chapter07/meta-gattd/recipes-gattd/gattd/gattd_0.1.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "Python BLE GATT server" 2 | HOMEPAGE = "https://github.com/fvasquez/gattd" 3 | LICENSE = "GPL-2.0-only" 4 | LIC_FILES_CHKSUM = "file://LICENSE;md5=c53d04442d1a229d62549856b7ec456a" 5 | 6 | SRC_URI = "https://github.com/fvasquez/gattd/archive/v${PV}.tar.gz" 7 | SRC_URI[md5sum] = "2a5ccd81395ba01534006b815b509c60" 8 | SRC_URI[sha1sum] = "7a4b5fac479e2fade925c4baf53b3e643e320182" 9 | SRC_URI[sha256sum] = "b6ff7bbe95517d0213ce376e7e72a92917b1645ccd995cc4e514c3b3c1a9bc39" 10 | SRC_URI[sha384sum] = "7bf2e3e10ce057b792aa30de5e258ff911de64c8f7efbbee2af5c7dec5974c3fc2162d70335c31ed9c7010d14e459cdc" 11 | SRC_URI[sha512sum] = "c2d0e436e8087d05b0c7017421100ae7b8c4d7ff812879cf9d4f7a5162860974bea49d24d711ecbb08e49ae4ae874d63e236a43e39fdd50c560417e85efb054b" 12 | 13 | RDEPENDS_${PN} = "python3-dbus" 14 | 15 | S = "${WORKDIR}/gattd-${PV}" 16 | 17 | do_install () { 18 | install -d ${D}${bindir} 19 | install -m 0755 ${S}/*.py ${D}${bindir} 20 | } 21 | 22 | FILES_${PN} += "${bindir}/*.py" 23 | -------------------------------------------------------------------------------- /Chapter07/meta-mackerel/COPYING.MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Chapter07/meta-mackerel/README: -------------------------------------------------------------------------------- 1 | This README file contains information on the contents of the meta-mackerel layer. 2 | 3 | Please see the corresponding sections below for details. 4 | 5 | Dependencies 6 | ============ 7 | 8 | URI: git://git.yoctoproject.org/poky.git 9 | branch: kirkstone 10 | 11 | URI: git://git.openembedded.org/meta-openembedded 12 | branch: kirkstone 13 | 14 | Patches 15 | ======= 16 | 17 | Please submit any patches against the meta-mackerel layer to the maintainer: 18 | 19 | Maintainer: Frank Vasquez 20 | 21 | Table of Contents 22 | ================= 23 | 24 | I. Adding the meta-mackerel layer to your build 25 | II. Misc 26 | 27 | 28 | I. Adding the meta-mackerel layer to your build 29 | ================================================= 30 | 31 | bitbake-layers add-layer ../meta-mackerel 32 | 33 | II. Misc 34 | ======== 35 | 36 | This layer is an example of how to configure your own distro. 37 | -------------------------------------------------------------------------------- /Chapter07/meta-mackerel/conf/distro/mackerel.conf: -------------------------------------------------------------------------------- 1 | DISTRO_NAME = "Mackerel (Mackerel Embedded Linux Distro)" 2 | DISTRO_VERSION = "0.1" 3 | 4 | PACKAGE_CLASSES ?= "package_ipk" 5 | -------------------------------------------------------------------------------- /Chapter07/meta-mackerel/conf/layer.conf: -------------------------------------------------------------------------------- 1 | # We have a conf and classes directory, add to BBPATH 2 | BBPATH .= ":${LAYERDIR}" 3 | 4 | # We have recipes-* directories, add to BBFILES 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" 7 | 8 | BBFILE_COLLECTIONS += "meta-mackerel" 9 | BBFILE_PATTERN_meta-mackerel = "^${LAYERDIR}/" 10 | BBFILE_PRIORITY_meta-mackerel = "6" 11 | 12 | LAYERDEPENDS_meta-mackerel = "core" 13 | LAYERSERIES_COMPAT_meta-mackerel = "scarthgap" 14 | -------------------------------------------------------------------------------- /Chapter10/meta-ota/COPYING.MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Chapter10/meta-ota/README: -------------------------------------------------------------------------------- 1 | This README file contains information on the contents of the 2 | ota layer. 3 | 4 | Please see the corresponding sections below for details. 5 | 6 | 7 | Dependencies 8 | ============ 9 | 10 | This layer depends on: 11 | 12 | URI: git://git.openembedded.org/bitbake 13 | branch: master 14 | 15 | URI: git://git.openembedded.org/openembedded-core 16 | layers: meta 17 | branch: master 18 | 19 | URI: git://git.yoctoproject.org/xxxx 20 | layers: xxxx 21 | branch: master 22 | 23 | 24 | Patches 25 | ======= 26 | 27 | Please submit any patches against the ota layer to the 28 | xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: 29 | 30 | Maintainer: XXX YYYYYY 31 | 32 | 33 | Table of Contents 34 | ================= 35 | 36 | I. Adding the ota layer to your build 37 | II. Misc 38 | 39 | 40 | I. Adding the ota layer to your build 41 | ================================================= 42 | 43 | --- replace with specific instructions for the ota layer --- 44 | 45 | In order to use this layer, you need to make the build system aware of 46 | it. 47 | 48 | Assuming the ota layer exists at the top-level of your 49 | yocto build tree, you can add it to the build system by adding the 50 | location of the ota layer to bblayers.conf, along with any 51 | other layers needed. e.g.: 52 | 53 | BBLAYERS ?= " \ 54 | /path/to/yocto/meta \ 55 | /path/to/yocto/meta-poky \ 56 | /path/to/yocto/meta-yocto-bsp \ 57 | /path/to/yocto/meta-ota \ 58 | " 59 | 60 | 61 | II. Misc 62 | ======== 63 | 64 | --- replace with specific information about the ota layer --- 65 | -------------------------------------------------------------------------------- /Chapter10/meta-ota/conf/layer.conf: -------------------------------------------------------------------------------- 1 | # We have a conf and classes directory, add to BBPATH 2 | BBPATH .= ":${LAYERDIR}" 3 | 4 | # We have recipes-* directories, add to BBFILES 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" 7 | 8 | BBFILE_COLLECTIONS += "ota" 9 | BBFILE_PATTERN_ota = "^${LAYERDIR}/" 10 | BBFILE_PRIORITY_ota = "6" 11 | -------------------------------------------------------------------------------- /Chapter10/meta-ota/recipes-core/base-files/base-files_%.bbappend: -------------------------------------------------------------------------------- 1 | do_install:append () { 2 | echo "10.0.2.2 docker.mender.io s3.docker.mender.io" >> ${D}${sysconfdir}/hosts 3 | } 4 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/COPYING.MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/README: -------------------------------------------------------------------------------- 1 | This README file contains information on the contents of the device-drivers layer. 2 | 3 | Please see the corresponding sections below for details. 4 | 5 | Dependencies 6 | ============ 7 | 8 | URI: 9 | branch: 10 | 11 | URI: 12 | branch: 13 | 14 | . 15 | . 16 | . 17 | 18 | Patches 19 | ======= 20 | 21 | Please submit any patches against the device-drivers layer to the xxxx mailing list (xxxx@zzzz.org) 22 | and cc: the maintainer: 23 | 24 | Maintainer: XXX YYYYYY 25 | 26 | Table of Contents 27 | ================= 28 | 29 | I. Adding the device-drivers layer to your build 30 | II. Misc 31 | 32 | 33 | I. Adding the device-drivers layer to your build 34 | ================================================= 35 | 36 | Run 'bitbake-layers add-layer device-drivers' 37 | 38 | II. Misc 39 | ======== 40 | 41 | --- replace with specific information about the device-drivers layer --- 42 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/conf/layer.conf: -------------------------------------------------------------------------------- 1 | # We have a conf and classes directory, add to BBPATH 2 | BBPATH .= ":${LAYERDIR}" 3 | 4 | # We have recipes-* directories, add to BBFILES 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" 7 | 8 | BBFILE_COLLECTIONS += "device-drivers" 9 | BBFILE_PATTERN_device-drivers = "^${LAYERDIR}/" 10 | BBFILE_PRIORITY_device-drivers = "6" 11 | 12 | LAYERDEPENDS_device-drivers = "core" 13 | LAYERSERIES_COMPAT_device-drivers = "scarthgap" 14 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-kernel/dummy-driver/dummy-driver_1.0.bb: -------------------------------------------------------------------------------- 1 | SUMMARY = "Custom Kernel Module Example" 2 | DESCRIPTION = "An example out-of-tree kernel module for Yocto" 3 | LICENSE = "GPL-2.0-only" 4 | LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" 5 | 6 | SRC_URI = " \ 7 | file://dummy.c \ 8 | file://Makefile \ 9 | " 10 | 11 | # The 'module' class simplifies building out-of-tree kernel modules 12 | inherit module 13 | 14 | S = "${WORKDIR}" 15 | UNPACKDIR = "${S}" 16 | 17 | # The inherit of module.bbclass will automatically name module packages with 18 | # "kernel-module-" prefix as required by the oe-core build environment. 19 | RPROVIDES:${PN} += "kernel-module-dummy" 20 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-kernel/dummy-driver/files/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := dummy.o 2 | 3 | SRC := $(shell pwd) 4 | 5 | all: 6 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) 7 | 8 | modules_install: 9 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install 10 | 11 | clean: 12 | rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c 13 | rm -f Module.markers Module.symvers modules.order 14 | rm -rf .tmp_versions Modules.symvers 15 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-kernel/dummy-driver/files/dummy.c: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------- */ 2 | /* */ 3 | /* Dummy char driver */ 4 | /* */ 5 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 6 | /* */ 7 | /* This program is free software; you can redistribute it and/or modify */ 8 | /* it under the terms of the GNU General Public License as published by */ 9 | /* the Free Software Foundation; either version 2 of the License, or */ 10 | /* (at your option) any later version. */ 11 | /* */ 12 | /* This program is distributed in the hope that it will be useful, */ 13 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 14 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ 15 | /* General Public License for more details. */ 16 | /* */ 17 | /* You should have received a copy of the GNU General Public License */ 18 | /* along with this program; if not, write to the Free Software */ 19 | /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 20 | /* */ 21 | /* ------------------------------------------------------------------------- */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define DEVICE_NAME "dummy" 30 | #define MAJOR_NUM 42 31 | #define NUM_DEVICES 4 32 | 33 | static struct class *dummy_class; 34 | 35 | static int dummy_open(struct inode *inode, struct file *file) 36 | { 37 | pr_info("%s\n", __func__); 38 | return 0; 39 | } 40 | 41 | static int dummy_release(struct inode *inode, struct file *file) 42 | { 43 | pr_info("%s\n", __func__); 44 | return 0; 45 | } 46 | 47 | static ssize_t dummy_read(struct file *file, char *buffer, size_t length, loff_t * offset) 48 | { 49 | pr_info("%s %u\n", __func__, length); 50 | return 0; 51 | } 52 | 53 | static ssize_t dummy_write(struct file *file, const char *buffer, size_t length, loff_t * offset) 54 | { 55 | pr_info("%s %u\n", __func__, length); 56 | return length; 57 | } 58 | 59 | struct file_operations dummy_fops = { 60 | .open = dummy_open, 61 | .release = dummy_release, 62 | .read = dummy_read, 63 | .write = dummy_write, 64 | }; 65 | 66 | int __init dummy_init(void) 67 | { 68 | int ret; 69 | int i; 70 | 71 | printk("Dummy loaded\n"); 72 | ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &dummy_fops); 73 | 74 | if (ret != 0) { 75 | return ret; 76 | } 77 | 78 | dummy_class = class_create(DEVICE_NAME); 79 | 80 | for (i = 0; i < NUM_DEVICES; i++) { 81 | device_create(dummy_class, NULL, MKDEV(MAJOR_NUM, i), NULL, "dummy%d", i); 82 | } 83 | 84 | return 0; 85 | } 86 | 87 | void __exit dummy_exit(void) 88 | { 89 | int i; 90 | 91 | for (i = 0; i < NUM_DEVICES; i++) { 92 | device_destroy(dummy_class, MKDEV(MAJOR_NUM, i)); 93 | } 94 | 95 | class_destroy(dummy_class); 96 | 97 | unregister_chrdev(MAJOR_NUM, DEVICE_NAME); 98 | printk("Dummy unloaded\n"); 99 | } 100 | 101 | module_init(dummy_init); 102 | module_exit(dummy_exit); 103 | MODULE_LICENSE("GPL"); 104 | MODULE_AUTHOR("Chris Simmonds"); 105 | MODULE_DESCRIPTION("A dummy driver"); 106 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/gpio-int/files/config-gpio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Configure USR_BUTTON (gpio 557) as input, trigger on falling edge" 4 | echo 557 > /sys/class/gpio/export 5 | echo falling > /sys/class/gpio/gpio557/edge 6 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/gpio-int/files/gpio-int.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2025, Frank Vasquez (frank.vasquez@gmail.com) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * Demonstration of using epoll(2) to wait for an interrupt on GPIO. 11 | * 12 | * USR_BUTTON is configured as gpio 557, so to make it an input which 13 | * triggers on a falling edge, write 14 | * 15 | * echo 557 > /sys/class/gpio/export 16 | * echo falling > /sys/class/gpio/gpio557/edge 17 | * 18 | * Now, the USR_BUTTON pin is normally pulled high, so 19 | * /sys/class/gpio557/value reads as 1'. 20 | * Pushing the button takes it low, and value reads as '0'. 21 | * 22 | * This program waits for the level to fall from 1 to 0 and 23 | * prints out a message each time it does so. 24 | */ 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | int ep; 29 | int f; 30 | struct epoll_event ev, events; 31 | char value[4]; 32 | int ret; 33 | int n; 34 | 35 | ep = epoll_create(1); 36 | 37 | if (ep == -1) { 38 | perror("Can't create epoll"); 39 | return 1; 40 | } 41 | 42 | f = open("/sys/class/gpio/gpio557/value", O_RDONLY | O_NONBLOCK); 43 | 44 | if (f == -1) { 45 | perror("Can't open gpio557"); 46 | return 1; 47 | } 48 | 49 | n = read(f, &value, sizeof(value)); 50 | 51 | if (n > 0) { 52 | printf("Initial value value=%c\n", value[0]); 53 | lseek(f, 0, SEEK_SET); 54 | } 55 | 56 | ev.events = EPOLLPRI; 57 | ev.data.fd = f; 58 | ret = epoll_ctl(ep, EPOLL_CTL_ADD, f, &ev); 59 | 60 | if (ret == -1) { 61 | perror("Can't register target file descriptor with epoll"); 62 | return 1; 63 | } 64 | 65 | while (1) { 66 | printf("Waiting\n"); 67 | ret = epoll_wait(ep, &events, 1, -1); 68 | 69 | if (ret > 0) { 70 | n = read(f, &value, sizeof(value)); 71 | printf("Button pressed: read %d bytes, value=%c\n", n, value[0]); 72 | lseek(f, 0, SEEK_SET); 73 | } 74 | } 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/gpio-int/gpio-int_1.0.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "A program that waits for GPIO interrupts from a button press" 2 | PRIORITY = "optional" 3 | SECTION = "examples" 4 | LICENSE = "MIT" 5 | LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" 6 | 7 | SRC_URI = " \ 8 | file://gpio-int.c \ 9 | file://config-gpio.sh \ 10 | " 11 | 12 | S = "${WORKDIR}" 13 | 14 | do_compile() { 15 | ${CC} ${CFLAGS} ${LDFLAGS} gpio-int.c -o gpio-int 16 | } 17 | 18 | do_install() { 19 | install -d ${D}${bindir} 20 | install -m 0755 gpio-int ${D}${bindir} 21 | install -m 0755 config-gpio.sh ${D}${bindir} 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/i2c-eeprom-read/files/i2c-eeprom-read.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | /* 4 | * Sample program to read the first four bytes of the 5 | * FT24C32A-ELR-T EEPROM from the BeaglePlay 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* Address of the EEPROM on the BeaglePlay board */ 15 | #define I2C_ADDRESS 0x50 16 | 17 | int main(void) 18 | { 19 | int f; 20 | int n; 21 | char buf[10]; 22 | 23 | /* Open the adapter and set the address of the I2C device */ 24 | f = open("/dev/i2c-0", O_RDWR); 25 | 26 | if (f < 0) { 27 | perror("/dev/i2c-0:"); 28 | return 1; 29 | } 30 | 31 | /* Set the address of the i2c slave device */ 32 | if (ioctl(f, I2C_SLAVE, I2C_ADDRESS) == -1) { 33 | perror("ioctl I2C_SLAVE"); 34 | return 1; 35 | } 36 | 37 | /* Set the 16-bit address to read (0) */ 38 | buf[0] = 0; /* address byte 1 */ 39 | buf[1] = 0; /* address byte 2 */ 40 | n = write(f, buf, 2); 41 | 42 | if (n == -1) { 43 | perror("write"); 44 | return 1; 45 | } 46 | 47 | /* Now read 4 bytes from that address */ 48 | n = read(f, buf, 4); 49 | if (n == -1) { 50 | perror("read"); 51 | return 1; 52 | } 53 | 54 | printf("0x%x 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2], buf[3]); 55 | 56 | close(f); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/i2c-eeprom-read/i2c-eeprom-read_1.0.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "A program that reads the first 4 bytes from an EEPROM over I2C" 2 | PRIORITY = "optional" 3 | SECTION = "examples" 4 | LICENSE = "MIT" 5 | LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" 6 | 7 | SRC_URI = "file://i2c-eeprom-read.c" 8 | 9 | S = "${WORKDIR}" 10 | 11 | do_compile() { 12 | ${CC} ${CFLAGS} ${LDFLAGS} i2c-eeprom-read.c -o i2c-eeprom-read 13 | } 14 | 15 | do_install() { 16 | install -d ${D}${bindir} 17 | install -m 0755 i2c-eeprom-read ${D}${bindir} 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/read-urandom/files/read-urandom.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(void) 10 | { 11 | int f; 12 | unsigned int rnd; 13 | int n; 14 | 15 | f = open("/dev/urandom", O_RDONLY); 16 | 17 | if (f < 0) { 18 | perror("Failed to open urandom"); 19 | return 1; 20 | } 21 | 22 | n = read(f, &rnd, sizeof(rnd)); 23 | 24 | if (n != sizeof(rnd)) { 25 | perror("Problem reading urandom"); 26 | return 1; 27 | } 28 | 29 | printf("Random number = 0x%x\n", rnd); 30 | 31 | close(f); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/read-urandom/read-urandom_1.0.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "A program that reads a word of pseudorandom data" 2 | PRIORITY = "optional" 3 | SECTION = "examples" 4 | LICENSE = "MIT" 5 | LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" 6 | 7 | SRC_URI = "file://read-urandom.c" 8 | 9 | S = "${WORKDIR}" 10 | 11 | do_compile() { 12 | ${CC} ${CFLAGS} ${LDFLAGS} read-urandom.c -o read-urandom 13 | } 14 | 15 | do_install() { 16 | install -d ${D}${bindir} 17 | install -m 0755 read-urandom ${D}${bindir} 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/show-mac-address/files/show-mac-address.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int s; 14 | int ret; 15 | struct ifreq ifr; 16 | int i; 17 | 18 | if (argc != 2) { 19 | printf("Usage %s [network interface]\n", argv[0]); 20 | return 1; 21 | } 22 | 23 | s = socket(PF_INET, SOCK_DGRAM, 0); 24 | 25 | if (s < 0) { 26 | perror("socket"); 27 | return 1; 28 | } 29 | 30 | strcpy(ifr.ifr_name, argv[1]); 31 | ret = ioctl(s, SIOCGIFHWADDR, &ifr); 32 | 33 | if (ret < 0) { 34 | perror("ioctl"); 35 | return 1; 36 | } 37 | 38 | for (i = 0; i < 6; i++) { 39 | printf("%02x:", (unsigned char)ifr.ifr_hwaddr.sa_data[i]); 40 | } 41 | 42 | printf("\n"); 43 | close(s); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /Chapter11/meta-device-drivers/recipes-local/show-mac-address/show-mac-address_1.0.bb: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "A program that prints the MAC address of a network interface" 2 | PRIORITY = "optional" 3 | SECTION = "examples" 4 | LICENSE = "MIT" 5 | LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" 6 | 7 | SRC_URI = "file://show-mac-address.c" 8 | 9 | S = "${WORKDIR}" 10 | 11 | do_compile() { 12 | ${CC} ${CFLAGS} ${LDFLAGS} show-mac-address.c -o show-mac-address 13 | } 14 | 15 | do_install() { 16 | install -d ${D}${bindir} 17 | install -m 0755 show-mac-address ${D}${bindir} 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Chapter12/display.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import numpy as np 4 | from PIL import Image 5 | from time import sleep 6 | from luma.core.device import linux_framebuffer 7 | 8 | device = linux_framebuffer() 9 | 10 | def draw(offset): 11 | red = np.zeros((128, 128)) 12 | green = np.zeros((128, 128)) 13 | blue = np.zeros((128, 128)) 14 | red[22 + offset : 65 + offset, 22 + offset : 65 + offset] = 255 15 | green[42:84, 42:84] = 255 16 | blue[63 - offset : 106 - offset, 63 - offset : 106 - offset] = 255 17 | red_img = Image.fromarray(red).convert("L") 18 | green_img = Image.fromarray(green).convert("L") 19 | blue_img = Image.fromarray((blue)).convert("L") 20 | device.display( 21 | Image.merge( 22 | "RGB", 23 | (red_img, green_img, blue_img) 24 | ) 25 | ) 26 | 27 | while True: 28 | for offset in range(0, 21, 1): 29 | draw(offset) 30 | sleep(0.05) 31 | for offset in range(21, 0, -1): 32 | draw(offset) 33 | sleep(0.05) 34 | -------------------------------------------------------------------------------- /Chapter12/parse_nmea.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import pynmea2 5 | 6 | for line in sys.stdin: 7 | try: 8 | msg = pynmea2.parse(line) 9 | print(repr(msg)) 10 | except pynmea2.ParseError as e: 11 | print('Parse error: {}'.format(e)) 12 | continue 13 | -------------------------------------------------------------------------------- /Chapter12/sensors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import time 4 | 5 | paths = [ 6 | '/sys/bus/iio/devices/iio:device0/in_humidityrelative_input', 7 | '/sys/bus/iio/devices/iio:device0/in_pressure_input', 8 | '/sys/bus/iio/devices/iio:device0/in_resistance_input', 9 | '/sys/bus/iio/devices/iio:device0/in_temp_input' 10 | ] 11 | 12 | def read_sysfs_value(path): 13 | with open(path, 'r') as f: 14 | return f.read().strip() 15 | 16 | while True: 17 | values = [0] * len(paths) 18 | for i, path in enumerate(paths): 19 | try: 20 | values[i] = read_sysfs_value(path) 21 | except IOError as e: 22 | print(f"Error: {e}") 23 | print(f"humidity: {values[0]} pressure: {values[1]} resistance: {values[2]} temperature: {values[3]}") 24 | time.sleep(1) 25 | -------------------------------------------------------------------------------- /Chapter13/simpleserver-systemd/simpleserver.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Simple server 3 | 4 | [Service] 5 | Type=forking 6 | ExecStart=/usr/bin/simpleserver 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | 11 | -------------------------------------------------------------------------------- /Chapter13/simpleserver-sysvinit/init.d/simpleserver: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | case "$1" in 4 | start) 5 | echo "Starting simpelserver" 6 | start-stop-daemon -S -n simpleserver -a /usr/bin/simpleserver 7 | ;; 8 | stop) 9 | echo "Stopping simpleserver" 10 | start-stop-daemon -K -n simpleserver 11 | ;; 12 | *) 13 | echo "Usage: $0 {start|stop}" 14 | exit 1 15 | esac 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /Chapter13/simpleserver/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g 7 | PROGRAM = simpleserver 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter13/simpleserver/simpleserver.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static void sig_handler(int sig) 14 | { 15 | printf("Cleaning up\n"); 16 | } 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | time_t start; 21 | int f; 22 | char msg[64]; 23 | 24 | printf("%s starting\n", argv[0]); 25 | 26 | f = open("/dev/kmsg", O_WRONLY); 27 | 28 | if (f == -1) { 29 | printf("Failed to open /dev/kmsg: no messages from me!\n"); 30 | } 31 | 32 | if (argc == 2 && strcmp(argv[1], "-n") == 0) { 33 | printf("Not forking\n"); 34 | } else { 35 | printf("Deamonizing...\n"); 36 | 37 | if (daemon(0, 0) == -1) { 38 | perror("Daemon failed"); 39 | return 1; 40 | } 41 | } 42 | 43 | signal(SIGHUP, sig_handler); 44 | 45 | start = time(NULL); 46 | 47 | while(1) { 48 | snprintf(msg, sizeof(msg), "%s has been running for %ld seconds\n", argv[0], time(NULL) - start); 49 | write(f, msg, strlen(msg)); 50 | sleep(60); 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /Chapter14/cpufrequtils: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: cpufrequtils 4 | # Required-Start: $remote_fs loadcpufreq 5 | # Required-Stop: 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 8 | # Short-Description: set CPUFreq kernel parameters 9 | # Description: utilities to deal with CPUFreq Linux 10 | # kernel support 11 | ### END INIT INFO 12 | # 13 | 14 | DESC="CPUFreq Utilities" 15 | 16 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 17 | CPUFREQ_SET=/usr/bin/cpufreq-set 18 | CPUFREQ_INFO=/usr/bin/cpufreq-info 19 | CPUFREQ_OPTIONS="" 20 | 21 | # use lsb-base 22 | . /lib/lsb/init-functions 23 | 24 | # Which governor to use. Must be one of the governors listed in: 25 | # cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors 26 | # 27 | # and which limits to set. Both MIN_SPEED and MAX_SPEED must be values 28 | # listed in: 29 | # cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies 30 | # a value of 0 for any of the two variables will disabling the use of 31 | # that limit variable. 32 | # 33 | # WARNING: the correct kernel module must already be loaded or compiled in. 34 | # 35 | # Set ENABLE to "true" to let the script run at boot time. 36 | # 37 | # eg: ENABLE="true" 38 | # GOVERNOR="performance" 39 | # MAX_SPEED=1000 40 | # MIN_SPEED=500 41 | 42 | ENABLE="true" 43 | GOVERNOR="performance" 44 | MAX_SPEED="0" 45 | MIN_SPEED="0" 46 | 47 | check_governor_avail() { 48 | info="/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" 49 | if [ -f $info ] && grep -q "\<$GOVERNOR\>" $info ; then 50 | return 0; 51 | fi 52 | return 1; 53 | } 54 | 55 | [ -x $CPUFREQ_SET ] || exit 0 56 | 57 | if [ -f /etc/default/cpufrequtils ] ; then 58 | . /etc/default/cpufrequtils 59 | fi 60 | 61 | # if not enabled then exit gracefully 62 | [ "$ENABLE" = "true" ] || exit 0 63 | 64 | if [ -n "$MAX_SPEED" ] && [ $MAX_SPEED != "0" ] ; then 65 | CPUFREQ_OPTIONS="$CPUFREQ_OPTIONS --max $MAX_SPEED" 66 | fi 67 | 68 | if [ -n "$MIN_SPEED" ] && [ $MIN_SPEED != "0" ] ; then 69 | CPUFREQ_OPTIONS="$CPUFREQ_OPTIONS --min $MIN_SPEED" 70 | fi 71 | 72 | if [ -n "$GOVERNOR" ] ; then 73 | CPUFREQ_OPTIONS="$CPUFREQ_OPTIONS --governor $GOVERNOR" 74 | fi 75 | 76 | CPUS=$(cat /proc/stat|sed -ne 's/^cpu\([[:digit:]]\+\).*/\1/p') 77 | RETVAL=0 78 | case "$1" in 79 | start|force-reload|restart|reload) 80 | log_action_begin_msg "$DESC: Setting $GOVERNOR CPUFreq governor" 81 | if check_governor_avail ; then 82 | for cpu in $CPUS ; do 83 | log_action_cont_msg "CPU${cpu}" 84 | $CPUFREQ_SET --cpu $cpu $CPUFREQ_OPTIONS 2>&1 > /dev/null || \ 85 | RETVAL=$? 86 | done 87 | log_action_end_msg $RETVAL "" 88 | else 89 | log_action_cont_msg "disabled, governor not available" 90 | log_action_end_msg $RETVAL 91 | fi 92 | ;; 93 | stop) 94 | ;; 95 | *) 96 | echo "Usage: $0 {start|stop|restart|reload|force-reload}" 97 | exit 1 98 | esac 99 | 100 | exit 0 101 | 102 | -------------------------------------------------------------------------------- /Chapter14/do-work/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g 7 | PROGRAM = do-work 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter14/do-work/do-work.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int quit_now = 0; 12 | unsigned long loop_count; 13 | sigset_t alarm_sig; 14 | 15 | void sig_int_handler(int n) 16 | { 17 | quit_now = 1; 18 | } 19 | 20 | static unsigned long waste_time(unsigned long v) 21 | { 22 | unsigned long new_v; 23 | new_v = (v * 22)/7; 24 | return new_v; 25 | } 26 | 27 | static void calibrate(void) 28 | { 29 | struct itimerval value; 30 | struct sigaction act; 31 | int i; 32 | 33 | act.sa_handler = sig_int_handler; 34 | sigemptyset(&act.sa_mask); 35 | act.sa_flags = 0; 36 | sigaction(SIGALRM, &act, NULL); 37 | 38 | /* Create a 10ms timer */ 39 | value.it_value.tv_sec = 0; 40 | value.it_value.tv_usec = 10000; 41 | value.it_interval.tv_sec = 0; 42 | value.it_interval.tv_usec = 10000; 43 | if (setitimer(ITIMER_REAL, &value, NULL) != 0) { 44 | perror("Failed to set timer"); 45 | exit(1); 46 | } 47 | 48 | /* See how many times we loop in 10 ms. 49 | Let the timer expire 4 times and take the last count */ 50 | for (i = 0; i < 4; i++) { 51 | quit_now = 0; 52 | loop_count = 0; 53 | while (!quit_now) { 54 | waste_time(123); 55 | loop_count++; 56 | } 57 | } 58 | } 59 | 60 | static void do_work(long msecs) 61 | { 62 | unsigned long local_count; 63 | unsigned long end_count; 64 | 65 | local_count = 0; 66 | end_count = (loop_count * msecs)/10; 67 | while (local_count < end_count) { 68 | waste_time(123); 69 | local_count++; 70 | } 71 | } 72 | 73 | static void wait_next(long msecs) 74 | { 75 | int sig; 76 | sigwait(&alarm_sig, &sig); 77 | } 78 | 79 | static void usage(void) 80 | { 81 | printf("Usage: \n" 82 | " -c calibrate: you need to do this first\n" 83 | " -l [loop count] loop count from calibration\n" 84 | " -n [on count] on (work) time in ms, default 10\n" 85 | " -f [off count] off (sleep) time, default same as on time\n"); 86 | } 87 | 88 | int main(int argc, char *argv[]) 89 | { 90 | int opt; 91 | unsigned long on_time_ms = 10; 92 | unsigned long off_time_ms = -1; 93 | struct itimerval value; 94 | 95 | if (argc == 1) { 96 | usage(); 97 | exit(0); 98 | } 99 | 100 | while ((opt = getopt(argc, argv, "cf:l:n:")) != -1) { 101 | switch (opt) { 102 | case 'c': 103 | printf("Calibrating...\n"); 104 | calibrate(); 105 | printf("Now run %s -l %lu\n", argv[0], loop_count); 106 | exit(0); 107 | break; 108 | case 'f': 109 | off_time_ms = strtoul(optarg, NULL, 0); 110 | break; 111 | case 'l': 112 | loop_count = strtoul(optarg, NULL, 0); 113 | break; 114 | case 'n': 115 | on_time_ms = strtoul(optarg, NULL, 0); 116 | break; 117 | default: 118 | usage(); 119 | exit(0); 120 | } 121 | } 122 | 123 | if (loop_count == 0) { 124 | usage(); 125 | exit(0); 126 | } 127 | 128 | if (off_time_ms == -1) 129 | off_time_ms = on_time_ms; 130 | 131 | printf("working for %lu ms, sleeping for %lu ms\n", 132 | on_time_ms, off_time_ms); 133 | 134 | /* Block SIGALRM */ 135 | sigemptyset (&alarm_sig); 136 | sigaddset (&alarm_sig, SIGALRM); 137 | sigprocmask (SIG_BLOCK, &alarm_sig, NULL); 138 | 139 | /* Create a timer */ 140 | value.it_value.tv_sec = 0; 141 | value.it_value.tv_usec = (off_time_ms + on_time_ms) * 1000; 142 | value.it_interval.tv_sec = 0; 143 | value.it_interval.tv_usec = (off_time_ms + on_time_ms) * 1000; 144 | if (setitimer(ITIMER_REAL, &value, NULL) != 0) { 145 | perror("Failed to set timer"); 146 | exit(1); 147 | } 148 | while (1) { 149 | do_work(on_time_ms); 150 | wait_next(off_time_ms); 151 | } 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /Chapter15/conda/my-environment.yaml: -------------------------------------------------------------------------------- 1 | name: py311 2 | channels: 3 | - defaults 4 | - https://repo.anaconda.com/pkgs/main 5 | - https://repo.anaconda.com/pkgs/r 6 | dependencies: 7 | - _libgcc_mutex=0.1=main 8 | - _openmp_mutex=5.1=1_gnu 9 | - aom=3.6.0=h6a678d5_0 10 | - blas=1.0=openblas 11 | - brotli-python=1.0.9=py311h6a678d5_9 12 | - bzip2=1.0.8=h5eee18b_6 13 | - c-ares=1.19.1=h5eee18b_0 14 | - ca-certificates=2024.12.31=h06a4308_0 15 | - cairo=1.16.0=hb05425b_5 16 | - certifi=2025.1.31=py311h06a4308_0 17 | - contourpy=1.3.1=py311hdb19cb5_0 18 | - cycler=0.11.0=pyhd3eb1b0_0 19 | - cyrus-sasl=2.1.28=h52b45da_1 20 | - dav1d=1.2.1=h5eee18b_0 21 | - dbus=1.13.18=hb2f20db_0 22 | - eigen=3.4.0=hdb19cb5_0 23 | - expat=2.6.4=h6a678d5_0 24 | - ffmpeg=6.1.1=h2a67f75_2 25 | - fontconfig=2.14.1=h55d465d_3 26 | - fonttools=4.55.3=py311h5eee18b_0 27 | - freetype=2.12.1=h4a9f257_0 28 | - giflib=5.2.2=h5eee18b_0 29 | - glib=2.78.4=h6a678d5_0 30 | - glib-tools=2.78.4=h6a678d5_0 31 | - graphite2=1.3.14=h295c915_1 32 | - gst-plugins-base=1.14.1=h6a678d5_1 33 | - gstreamer=1.14.1=h5eee18b_1 34 | - harfbuzz=10.2.0=hf296adc_0 35 | - hdf5=1.14.5=h2b7332f_2 36 | - icu=73.1=h6a678d5_0 37 | - intel-openmp=2023.1.0=hdb19cb5_46306 38 | - jpeg=9e=h5eee18b_3 39 | - kiwisolver=1.4.8=py311h6a678d5_0 40 | - krb5=1.20.1=h143b758_1 41 | - lame=3.100=h7b6447c_0 42 | - lcms2=2.16=hb9589c4_0 43 | - ld_impl_linux-64=2.40=h12ee557_0 44 | - leptonica=1.82.0=h42c8aad_2 45 | - lerc=4.0.0=h6a678d5_0 46 | - libabseil=20240116.2=cxx17_h6a678d5_0 47 | - libarchive=3.7.7=hfab0078_0 48 | - libclang=14.0.6=default_hc6dbbc7_2 49 | - libclang13=14.0.6=default_he11475f_2 50 | - libcups=2.4.2=h2d74bed_1 51 | - libcurl=8.11.1=hc9e6f67_0 52 | - libdeflate=1.22=h5eee18b_0 53 | - libedit=3.1.20230828=h5eee18b_0 54 | - libev=4.33=h7f8727e_1 55 | - libffi=3.4.4=h6a678d5_1 56 | - libgcc-ng=11.2.0=h1234567_1 57 | - libgfortran-ng=11.2.0=h00389a5_1 58 | - libgfortran5=11.2.0=h1234567_1 59 | - libglib=2.78.4=hdc74915_0 60 | - libgomp=11.2.0=h1234567_1 61 | - libiconv=1.16=h5eee18b_3 62 | - libllvm14=14.0.6=hecde1de_4 63 | - libnghttp2=1.57.0=h2d74bed_0 64 | - libogg=1.3.5=h27cfd23_1 65 | - libopenblas=0.3.21=h043d6bf_0 66 | - libopus=1.3.1=h5eee18b_1 67 | - libpng=1.6.39=h5eee18b_0 68 | - libpq=12.20=hdbd6064_0 69 | - libprotobuf=4.25.3=he621ea3_0 70 | - libssh2=1.11.1=h251f7ec_0 71 | - libstdcxx-ng=11.2.0=h1234567_1 72 | - libtheora=1.1.1=h7f8727e_3 73 | - libtiff=4.5.1=hffd6297_1 74 | - libuuid=1.41.5=h5eee18b_0 75 | - libvorbis=1.3.7=h7b6447c_0 76 | - libvpx=1.13.1=h6a678d5_0 77 | - libwebp=1.3.2=h11a3e52_0 78 | - libwebp-base=1.3.2=h5eee18b_1 79 | - libxcb=1.15=h7f8727e_0 80 | - libxkbcommon=1.0.1=h097e994_2 81 | - libxml2=2.13.5=hfdd30dd_0 82 | - lz4-c=1.9.4=h6a678d5_1 83 | - matplotlib=3.10.0=py311h06a4308_0 84 | - matplotlib-base=3.10.0=py311hbfdbfaf_0 85 | - mkl=2023.1.0=h213fc3f_46344 86 | - mkl-service=2.4.0=py311h5eee18b_2 87 | - mysql=5.7.24=h721c034_2 88 | - ncurses=6.4=h6a678d5_0 89 | - numpy=1.26.4=py311h24aa872_0 90 | - numpy-base=1.26.4=py311hbfb1bba_0 91 | - opencv=4.10.0=py311hd6ae499_2 92 | - openh264=2.1.1=h4ff587b_0 93 | - openjpeg=2.5.2=he7f1fd0_0 94 | - openldap=2.6.4=h42fbc30_0 95 | - openssl=3.0.15=h5eee18b_0 96 | - packaging=24.2=py311h06a4308_0 97 | - pcre2=10.42=hebb0a14_1 98 | - pillow=11.1.0=py311hcea889d_0 99 | - pip=25.0=py311h06a4308_0 100 | - pixman=0.40.0=h7f8727e_1 101 | - ply=3.11=py311h06a4308_0 102 | - pyparsing=3.2.0=py311h06a4308_0 103 | - pyqt=5.15.10=py311h6a678d5_1 104 | - pyqt5-sip=12.13.0=py311h5eee18b_1 105 | - python=3.11.9=h955ad1f_0 106 | - python-dateutil=2.9.0post0=py311h06a4308_2 107 | - qt-main=5.15.2=h53bd1ea_10 108 | - readline=8.2=h5eee18b_0 109 | - setuptools=75.8.0=py311h06a4308_0 110 | - sip=6.7.12=py311h6a678d5_1 111 | - six=1.16.0=pyhd3eb1b0_1 112 | - sqlite=3.45.3=h5eee18b_0 113 | - tbb=2021.8.0=hdb19cb5_0 114 | - tesseract=5.2.0=h6a678d5_2 115 | - tk=8.6.14=h39e8969_0 116 | - tornado=6.4.2=py311h5eee18b_0 117 | - tzdata=2025a=h04d1e81_0 118 | - unicodedata2=15.1.0=py311h5eee18b_1 119 | - wheel=0.45.1=py311h06a4308_0 120 | - xz=5.4.6=h5eee18b_1 121 | - zlib=1.2.13=h5eee18b_1 122 | - zstd=1.5.6=hc292b87_0 123 | prefix: /home/frank/miniconda3/envs/py311 124 | -------------------------------------------------------------------------------- /Chapter15/setuptools/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup( 3 | name='follower', 4 | version='0.1', 5 | packages=['follower'], 6 | include_package_data=True, 7 | install_requires=['requests', 'sqlalchemy'] 8 | ) 9 | -------------------------------------------------------------------------------- /Chapter16/build-rpi/conf/local.conf: -------------------------------------------------------------------------------- 1 | # 2 | # This file is your local configuration file and is where all local user settings 3 | # are placed. The comments in this file give some guide to the options a new user 4 | # to the system might want to change but pretty much any configuration option can 5 | # be set in this file. More adventurous users can look at 6 | # local.conf.sample.extended which contains other examples of configuration which 7 | # can be placed in this file but new users likely won't need any of them 8 | # initially. There's also site.conf.sample which contains examples of site specific 9 | # information such as proxy server addresses. 10 | # 11 | # Lines starting with the '#' character are commented out and in some cases the 12 | # default values are provided as comments to show people example syntax. Enabling 13 | # the option is a question of removing the # character and making any change to the 14 | # variable as required. 15 | 16 | # 17 | # Machine Selection 18 | # 19 | # You need to select a specific machine to target the build with. There are a selection 20 | # of emulated machines available which can boot and run in the QEMU emulator: 21 | # 22 | #MACHINE ?= "qemuarm" 23 | #MACHINE ?= "qemuarm64" 24 | #MACHINE ?= "qemumips" 25 | #MACHINE ?= "qemumips64" 26 | #MACHINE ?= "qemuppc" 27 | #MACHINE ?= "qemux86" 28 | #MACHINE ?= "qemux86-64" 29 | # 30 | # There are also the following hardware board target machines included for 31 | # demonstration purposes: 32 | # 33 | #MACHINE ?= "beaglebone-yocto" 34 | #MACHINE ?= "genericarm64" 35 | #MACHINE ?= "genericx86" 36 | #MACHINE ?= "genericx86-64" 37 | # 38 | # This sets the default machine to be qemux86-64 if no other machine is selected: 39 | MACHINE ??= "qemux86-64" 40 | 41 | # These are some of the more commonly used values. Looking at the files in the 42 | # meta/conf/machine directory, or the conf/machine directory of any additional layers 43 | # you add in will show all the available machines. 44 | 45 | # 46 | # Where to place downloads 47 | # 48 | # During a first build the system will download many different source code tarballs 49 | # from various upstream projects. This can take a while, particularly if your network 50 | # connection is slow. These are all stored in DL_DIR. When wiping and rebuilding you 51 | # can preserve this directory to speed up this part of subsequent builds. This directory 52 | # is safe to share between multiple builds on the same machine too. 53 | # 54 | # The default is a downloads directory under TOPDIR which is the build directory. 55 | # 56 | #DL_DIR ?= "${TOPDIR}/downloads" 57 | 58 | # 59 | # Where to place shared-state files 60 | # 61 | # BitBake has the capability to accelerate builds based on previously built output. 62 | # This is done using "shared state" files which can be thought of as cache objects 63 | # and this option determines where those files are placed. 64 | # 65 | # You can wipe out TMPDIR leaving this directory intact and the build would regenerate 66 | # from these files if no changes were made to the configuration. If changes were made 67 | # to the configuration, only shared state files where the state was still valid would 68 | # be used (done using checksums). 69 | # 70 | # The default is a sstate-cache directory under TOPDIR. 71 | # 72 | #SSTATE_DIR ?= "${TOPDIR}/sstate-cache" 73 | 74 | # 75 | # Where to place the build output 76 | # 77 | # This option specifies where the bulk of the building work should be done and 78 | # where BitBake should place its temporary files and output. Keep in mind that 79 | # this includes the extraction and compilation of many applications and the toolchain 80 | # which can use Gigabytes of hard disk space. 81 | # 82 | # The default is a tmp directory under TOPDIR. 83 | # 84 | #TMPDIR = "${TOPDIR}/tmp" 85 | 86 | # 87 | # Default policy config 88 | # 89 | # The distribution setting controls which policy settings are used as defaults. 90 | # The default value is fine for general Yocto project use, at least initially. 91 | # Ultimately when creating custom policy, people will likely end up subclassing 92 | # these defaults. 93 | # 94 | DISTRO ?= "poky" 95 | # As an example of a subclass there is a "bleeding" edge policy configuration 96 | # where many versions are set to the absolute latest code from the upstream 97 | # source control systems. This is just mentioned here as an example, its not 98 | # useful to most new users. 99 | # DISTRO ?= "poky-bleeding" 100 | 101 | # 102 | # Package Management configuration 103 | # 104 | # This variable lists which packaging formats to enable. Multiple package backends 105 | # can be enabled at once and the first item listed in the variable will be used 106 | # to generate the root filesystems. 107 | # Options are: 108 | # - 'package_deb' for debian style deb files 109 | # - 'package_ipk' for ipk files are used by opkg (a debian style embedded package manager) 110 | # - 'package_rpm' for rpm style packages 111 | # E.g.: PACKAGE_CLASSES ?= "package_rpm package_deb package_ipk" 112 | # OE-Core defaults to ipkg, whilst Poky defaults to rpm: 113 | # PACKAGE_CLASSES ?= "package_rpm" 114 | 115 | # 116 | # SDK target architecture 117 | # 118 | # This variable specifies the architecture to build SDK items for and means 119 | # you can build the SDK packages for architectures other than the machine you are 120 | # running the build on (i.e. building i686 packages on an x86_64 host). 121 | # Supported values are i686, x86_64, aarch64 122 | #SDKMACHINE ?= "i686" 123 | 124 | # 125 | # Extra image configuration defaults 126 | # 127 | # The EXTRA_IMAGE_FEATURES variable allows extra packages to be added to the generated 128 | # images. Some of these options are added to certain image types automatically. The 129 | # variable can contain the following options: 130 | # "dbg-pkgs" - add -dbg packages for all installed packages 131 | # (adds symbol information for debugging/profiling) 132 | # "src-pkgs" - add -src packages for all installed packages 133 | # (adds source code for debugging) 134 | # "dev-pkgs" - add -dev packages for all installed packages 135 | # (useful if you want to develop against libs in the image) 136 | # "ptest-pkgs" - add -ptest packages for all ptest-enabled packages 137 | # (useful if you want to run the package test suites) 138 | # "tools-sdk" - add development tools (gcc, make, pkgconfig etc.) 139 | # "tools-debug" - add debugging tools (gdb, strace) 140 | # "eclipse-debug" - add Eclipse remote debugging support 141 | # "tools-profile" - add profiling tools (oprofile, lttng, valgrind) 142 | # "tools-testapps" - add useful testing tools (ts_print, aplay, arecord etc.) 143 | # "debug-tweaks" - make an image suitable for development 144 | # e.g. ssh root access has a blank password 145 | # There are other application targets that can be used here too, see 146 | # meta/classes-recipe/image.bbclass and 147 | # meta/classes-recipe/core-image.bbclass for more details. 148 | # We default to enabling the debugging tweaks. 149 | EXTRA_IMAGE_FEATURES ?= "debug-tweaks ssh-server-openssh" 150 | 151 | # 152 | # Additional image features 153 | # 154 | # The following is a list of additional classes to use when building images which 155 | # enable extra features. Some available options which can be included in this variable 156 | # are: 157 | # - 'buildstats' collect build statistics 158 | USER_CLASSES ?= "buildstats" 159 | 160 | # 161 | # Runtime testing of images 162 | # 163 | # The build system can test booting virtual machine images under qemu (an emulator) 164 | # after any root filesystems are created and run tests against those images. It can also 165 | # run tests against any SDK that are built. To enable this uncomment these lines. 166 | # See meta/classes-recipe/test{image,sdk}.bbclass for further details. 167 | #IMAGE_CLASSES += "testimage testsdk" 168 | #TESTIMAGE_AUTO:qemuall = "1" 169 | 170 | # 171 | # Interactive shell configuration 172 | # 173 | # Under certain circumstances the system may need input from you and to do this it 174 | # can launch an interactive shell. It needs to do this since the build is 175 | # multithreaded and needs to be able to handle the case where more than one parallel 176 | # process may require the user's attention. The default is iterate over the available 177 | # terminal types to find one that works. 178 | # 179 | # Examples of the occasions this may happen are when resolving patches which cannot 180 | # be applied, to use the devshell or the kernel menuconfig 181 | # 182 | # Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none 183 | # Note: currently, Konsole support only works for KDE 3.x due to the way 184 | # newer Konsole versions behave 185 | #OE_TERMINAL = "auto" 186 | # By default disable interactive patch resolution (tasks will just fail instead): 187 | PATCHRESOLVE = "noop" 188 | 189 | # 190 | # Disk Space Monitoring during the build 191 | # 192 | # Monitor the disk space during the build. If there is less that 1GB of space or less 193 | # than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully 194 | # shutdown the build. If there is less than 100MB or 1K inodes, perform a hard halt 195 | # of the build. The reason for this is that running completely out of space can corrupt 196 | # files and damages the build in ways which may not be easily recoverable. 197 | # It's necessary to monitor /tmp, if there is no space left the build will fail 198 | # with very exotic errors. 199 | BB_DISKMON_DIRS ??= "\ 200 | STOPTASKS,${TMPDIR},1G,100K \ 201 | STOPTASKS,${DL_DIR},1G,100K \ 202 | STOPTASKS,${SSTATE_DIR},1G,100K \ 203 | STOPTASKS,/tmp,100M,100K \ 204 | HALT,${TMPDIR},100M,1K \ 205 | HALT,${DL_DIR},100M,1K \ 206 | HALT,${SSTATE_DIR},100M,1K \ 207 | HALT,/tmp,10M,1K" 208 | 209 | # 210 | # Shared-state files from other locations 211 | # 212 | # As mentioned above, shared state files are prebuilt cache data objects which can be 213 | # used to accelerate build time. This variable can be used to configure the system 214 | # to search other mirror locations for these objects before it builds the data itself. 215 | # 216 | # This can be a filesystem directory, or a remote url such as https or ftp. These 217 | # would contain the sstate-cache results from previous builds (possibly from other 218 | # machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the 219 | # cache locations to check for the shared objects. 220 | # NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH 221 | # at the end as shown in the examples below. This will be substituted with the 222 | # correct path within the directory structure. 223 | #SSTATE_MIRRORS ?= "\ 224 | #file://.* https://someserver.tld/share/sstate/PATH;downloadfilename=PATH \ 225 | #file://.* file:///some/local/dir/sstate/PATH" 226 | 227 | # 228 | # Yocto Project SState Mirror 229 | # 230 | # The Yocto Project has prebuilt artefacts available for its releases, you can enable 231 | # use of these by uncommenting some of the following lines. This will mean the build uses 232 | # the network to check for artefacts at the start of builds, which does slow it down 233 | # initially but it will then speed up the builds by not having to build things if they are 234 | # present in the cache. It assumes you can download something faster than you can build it 235 | # which will depend on your network. 236 | # Note: For this to work you also need hash-equivalence passthrough to the matching server 237 | # There is a choice between our sstate server directly and a faster content delivery network 238 | # (CDN) kindly provided by JSDelivr, uncomment one of the SSTATE_MIRRORS lines, not both. 239 | # Using the CDN rather than the yoctoproject.org address is suggested/preferred. 240 | # 241 | #BB_HASHSERVE_UPSTREAM = 'wss://hashserv.yoctoproject.org/ws' 242 | #SSTATE_MIRRORS ?= "file://.* http://cdn.jsdelivr.net/yocto/sstate/all/PATH;downloadfilename=PATH" 243 | # 244 | ###SSTATE_MIRRORS ?= "file://.* http://sstate.yoctoproject.org/all/PATH;downloadfilename=PATH" 245 | 246 | 247 | # 248 | # Qemu configuration 249 | # 250 | # By default native qemu will build with a builtin VNC server where graphical output can be 251 | # seen. The line below enables the SDL UI frontend too. 252 | PACKAGECONFIG:append:pn-qemu-system-native = " sdl" 253 | # By default libsdl2-native will be built, if you want to use your host's libSDL instead of 254 | # the minimal libsdl built by libsdl2-native then uncomment the ASSUME_PROVIDED line below. 255 | #ASSUME_PROVIDED += "libsdl2-native" 256 | 257 | # You can also enable the Gtk UI frontend, which takes somewhat longer to build, but adds 258 | # a handy set of menus for controlling the emulator. 259 | #PACKAGECONFIG:append:pn-qemu-system-native = " gtk+" 260 | 261 | # 262 | # Hash Equivalence 263 | # 264 | # Enable support for automatically running a local hash equivalence server and 265 | # instruct bitbake to use a hash equivalence aware signature generator. Hash 266 | # equivalence improves reuse of sstate by detecting when a given sstate 267 | # artifact can be reused as equivalent, even if the current task hash doesn't 268 | # match the one that generated the artifact. 269 | # 270 | # A shared hash equivalent server can be set with ":" format 271 | # 272 | #BB_HASHSERVE = "auto" 273 | #BB_SIGNATURE_HANDLER = "OEEquivHash" 274 | 275 | # 276 | # Memory Resident Bitbake 277 | # 278 | # Bitbake's server component can stay in memory after the UI for the current command 279 | # has completed. This means subsequent commands can run faster since there is no need 280 | # for bitbake to reload cache files and so on. Number is in seconds, after which the 281 | # server will shut down. 282 | # 283 | #BB_SERVER_TIMEOUT = "60" 284 | 285 | # CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to 286 | # track the version of this file when it was generated. This can safely be ignored if 287 | # this doesn't mean anything to you. 288 | CONF_VERSION = "2" 289 | MACHINE = "raspberrypi4-64" 290 | LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch" 291 | 292 | IMAGE_INSTALL:append = " ntp-utils docker" 293 | EXTRA_USERS_PARAMS = "\ 294 | groupadd -r docker; \ 295 | usermod -a -G docker root; \ 296 | " 297 | 298 | -------------------------------------------------------------------------------- /Chapter16/gattd/Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | FROM arm64v8/ubuntu:24.04 3 | LABEL maintainer="fvasquez@gmail.com" 4 | RUN apt-get update && apt-get install -y \ 5 | bluez \ 6 | dbus \ 7 | python3-dbus \ 8 | python3-gi 9 | 10 | # Your app code, binaries, or other instructions 11 | COPY . /app 12 | WORKDIR /app 13 | 14 | # Example app run 15 | CMD ./entrypoint.sh 16 | -------------------------------------------------------------------------------- /Chapter16/gattd/main.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker Image to GHCR 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | 7 | permissions: 8 | contents: read 9 | packages: write 10 | 11 | jobs: 12 | build-and-push: 13 | runs-on: ubuntu-24.04-arm 14 | 15 | steps: 16 | # 1) Check out the code 17 | - name: Check out code 18 | uses: actions/checkout@v4 19 | 20 | # 2) Log in to GitHub Container Registry 21 | - name: Log in to GHCR 22 | uses: docker/login-action@v2 23 | with: 24 | registry: ghcr.io 25 | username: ${{ github.repository_owner }} 26 | password: ${{ secrets.GITHUB_TOKEN }} 27 | 28 | # 3) Build and Push the Docker image 29 | - name: Build and push Docker image 30 | uses: docker/build-push-action@v4 31 | with: 32 | context: . 33 | file: ./Dockerfile 34 | platforms: linux/arm64 35 | push: true 36 | tags: | 37 | ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest 38 | 39 | -------------------------------------------------------------------------------- /Chapter17/condvar-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g -pthread 7 | PROGRAM = condvar-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter17/condvar-demo/condvar-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | char g_data[128]; 10 | pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 11 | pthread_mutex_t mutx = PTHREAD_MUTEX_INITIALIZER; 12 | 13 | void *consumer(void *arg) 14 | { 15 | while (1) { 16 | pthread_mutex_lock(&mutx); 17 | while (strlen(g_data) == 0) 18 | pthread_cond_wait(&cv, &mutx); 19 | 20 | /* Got data */ 21 | printf("%s\n", g_data); 22 | /* Truncate to null string again */ 23 | g_data[0] = 0; 24 | pthread_mutex_unlock(&mutx); 25 | } 26 | 27 | return NULL; 28 | } 29 | 30 | void *producer(void *arg) 31 | { 32 | int i = 0; 33 | 34 | while (1) { 35 | sleep(1); 36 | pthread_mutex_lock(&mutx); 37 | sprintf(g_data, "Data item %d", i); 38 | pthread_mutex_unlock(&mutx); 39 | pthread_cond_signal(&cv); 40 | i++; 41 | } 42 | 43 | return NULL; 44 | } 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | pthread_t producer_thread; 49 | pthread_t consumer_thread; 50 | 51 | pthread_create(&producer_thread, NULL, producer, NULL); 52 | pthread_create(&consumer_thread, NULL, consumer, NULL); 53 | 54 | /* Wait for both threads to finish */ 55 | pthread_join(producer_thread, NULL); 56 | pthread_join(consumer_thread, NULL); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Chapter17/exec-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g 7 | PROGRAM = exec-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter17/exec-demo/exec-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | char command_str[128]; 13 | int pid; 14 | int child_status; 15 | int wait_for = 1; 16 | 17 | while (1) { 18 | printf("sh> "); 19 | scanf("%s", command_str); 20 | pid = fork(); 21 | 22 | if (pid == 0) { 23 | /* child */ 24 | printf("cmd '%s'\n", command_str); 25 | execl(command_str, command_str, (char *)NULL); 26 | /* We should not return from execl, so only get 27 | to this line if it failed */ 28 | perror("exec"); 29 | exit(1); 30 | } 31 | 32 | if (wait_for) { 33 | waitpid(pid, &child_status, 0); 34 | printf("Done, status %d\n", child_status); 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter17/fork-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g 7 | PROGRAM = fork-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter17/fork-demo/fork-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(void) 10 | { 11 | int pid; 12 | int status; 13 | 14 | pid = fork(); 15 | 16 | if (pid == 0) { 17 | printf("I am the child, PID %d\n", getpid()); 18 | sleep(10); 19 | exit(42); 20 | } else if (pid > 0) { 21 | printf("I am the parent, PID %d\n", getpid()); 22 | wait(&status); 23 | printf("Child terminated, status %d\n", WEXITSTATUS(status)); 24 | } else { 25 | perror("fork:"); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter17/shared-mem-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g -lrt -pthread 7 | PROGRAM = shared-mem-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $^ $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter17/shared-mem-demo/shared-mem-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include /* For mode constants */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define SHM_SEGMENT_SIZE 65536 15 | #define SHM_SEGMENT_NAME "/demo-shm" 16 | #define SEMA_NAME "/demo-sem" 17 | 18 | static sem_t *demo_sem; 19 | 20 | /* 21 | * If the shared memory segment does not exist already, create it 22 | * Returns a pointer to the segment or NULL if there is an error 23 | */ 24 | static void *get_shared_memory(void) 25 | { 26 | int shm_fd; 27 | struct shared_data *shm_p; 28 | 29 | /* Attempt to create the shared memory segment */ 30 | shm_fd = shm_open(SHM_SEGMENT_NAME, O_CREAT | O_EXCL | O_RDWR, 0666); 31 | 32 | if (shm_fd > 0) { 33 | /* succeeded: expand it to the desired size (Note: dont't do 34 | this every time because ftruncate fills it with zeros) */ 35 | printf("Creating shared memory and setting size=%d\n", 36 | SHM_SEGMENT_SIZE); 37 | 38 | if (ftruncate(shm_fd, SHM_SEGMENT_SIZE) < 0) { 39 | perror("ftruncate"); 40 | exit(1); 41 | } 42 | 43 | /* Create a semaphore as well */ 44 | demo_sem = sem_open(SEMA_NAME, O_RDWR | O_CREAT, 0666, 1); 45 | 46 | if (demo_sem == SEM_FAILED) { 47 | perror("sem_open failed\n"); 48 | } 49 | } else if (shm_fd == -1 && errno == EEXIST) { 50 | /* Already exists: open again without O_CREAT */ 51 | shm_fd = shm_open(SHM_SEGMENT_NAME, O_RDWR, 0); 52 | demo_sem = sem_open(SEMA_NAME, O_RDWR); 53 | 54 | if (demo_sem == SEM_FAILED) { 55 | perror("sem_open failed\n"); 56 | } 57 | } 58 | 59 | if (shm_fd == -1) { 60 | perror("shm_open " SHM_SEGMENT_NAME); 61 | exit(1); 62 | } 63 | 64 | /* Map the shared memory */ 65 | shm_p = mmap(NULL, SHM_SEGMENT_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); 66 | 67 | if (shm_p == NULL) { 68 | perror("mmap"); 69 | exit(1); 70 | } 71 | 72 | return shm_p; 73 | } 74 | 75 | int main(int argc, char *argv[]) 76 | { 77 | char *shm_p; 78 | printf("%s PID=%d\n", argv[0], getpid()); 79 | shm_p = get_shared_memory(); 80 | 81 | while (1) { 82 | printf("Press enter to see the current contents of shm\n"); 83 | getchar(); 84 | sem_wait(demo_sem); 85 | printf("%s\n", shm_p); 86 | /* Write our signature to the shared memory */ 87 | sprintf(shm_p, "Hello from process %d\n", getpid()); 88 | sem_post(demo_sem); 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /Chapter17/thread-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g -pthread 7 | PROGRAM = thread-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter17/thread-demo/thread-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void *thread_fn(void *arg) 9 | { 10 | printf("New thread started, PID %d TID %d\n", 11 | getpid(), (pid_t)syscall(SYS_gettid)); 12 | sleep(10); 13 | printf("New thread terminating\n"); 14 | return NULL; 15 | } 16 | 17 | int main(int argc, char *argv[]) 18 | { 19 | pthread_t t; 20 | 21 | printf("Main thread, PID %d TID %d\n", 22 | getpid(), (pid_t)syscall(SYS_gettid)); 23 | pthread_create(&t, NULL, thread_fn, NULL); 24 | pthread_join(t, NULL); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /Chapter17/zeromq/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Echo client in Python 5 | # Connects REQ socket to tcp://localhost:5555 6 | # Sends "" to server, expects "Hello " back 7 | # 8 | 9 | import zmq 10 | 11 | def main(who): 12 | context = zmq.Context() 13 | 14 | # Socket to talk to server 15 | print("Connecting to echo server...") 16 | socket = context.socket(zmq.REQ) 17 | socket.connect("tcp://localhost:5555") 18 | 19 | # Do 5 requests, waiting each time for a response 20 | for request in range(5): 21 | print(f"Sending request {request} ...") 22 | socket.send_pyobj(who) 23 | 24 | # Get the reply. 25 | message = socket.recv_pyobj() 26 | print(f"Received reply {request} [ {message} ]") 27 | 28 | if __name__ == '__main__': 29 | import sys 30 | if len(sys.argv) != 2: 31 | print("usage: client.py ") 32 | raise SystemExit 33 | main(sys.argv[1]) 34 | -------------------------------------------------------------------------------- /Chapter17/zeromq/coroutines.py: -------------------------------------------------------------------------------- 1 | """Example using zmq with asyncio coroutines""" 2 | 3 | # Copyright (c) PyZMQ Developers. 4 | # This example is in the public domain (CC-0) 5 | 6 | import asyncio 7 | import time 8 | 9 | import zmq 10 | from zmq.asyncio import Context, Poller 11 | 12 | url = 'inproc://#1' 13 | 14 | ctx = Context.instance() 15 | 16 | 17 | async def ping() -> None: 18 | """print dots to indicate idleness""" 19 | while True: 20 | await asyncio.sleep(0.5) 21 | print('.') 22 | 23 | 24 | async def receiver() -> None: 25 | """receive messages with polling""" 26 | pull = ctx.socket(zmq.PAIR) 27 | pull.connect(url) 28 | poller = Poller() 29 | poller.register(pull, zmq.POLLIN) 30 | while True: 31 | events = await poller.poll() 32 | if pull in dict(events): 33 | print("recving", events) 34 | msg = await pull.recv_multipart() 35 | print('recvd', msg) 36 | 37 | 38 | async def sender() -> None: 39 | """send a message every second""" 40 | tic = time.time() 41 | push = ctx.socket(zmq.PAIR) 42 | push.bind(url) 43 | while True: 44 | print("sending") 45 | await push.send_multipart([str(time.time() - tic).encode('ascii')]) 46 | await asyncio.sleep(1) 47 | 48 | 49 | async def main() -> None: 50 | tasks = [asyncio.create_task(coroutine()) for coroutine in [ping, receiver, sender]] 51 | await asyncio.wait(tasks) 52 | 53 | 54 | if __name__ == "__main__": 55 | asyncio.run(main()) 56 | -------------------------------------------------------------------------------- /Chapter17/zeromq/planets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./server.py & 4 | SERVER_PID=$! 5 | 6 | ./client.py Mars & 7 | ./client.py Jupiter & 8 | ./client.py Venus 9 | 10 | kill $SERVER_PID 11 | -------------------------------------------------------------------------------- /Chapter17/zeromq/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Echo server in Python 5 | # Binds REP socket to tcp://*:5555 6 | # Expects "" from client, replies with "Hello " 7 | # 8 | 9 | import time 10 | import zmq 11 | 12 | context = zmq.Context() 13 | socket = context.socket(zmq.REP) 14 | socket.bind("tcp://*:5555") 15 | 16 | while True: 17 | # Wait for next request from client 18 | message = socket.recv_pyobj() 19 | print(f"Received request: {message}") 20 | 21 | # Do some 'work' 22 | time.sleep(1) 23 | 24 | # Send reply back to client 25 | socket.send_pyobj(f"Hello {message}") 26 | -------------------------------------------------------------------------------- /Chapter18/mtrace-example/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025, Frank Vasquez (frank.vasquez@gmail.com) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=aarch64-buildroot-linux-gnu-gcc 5 | 6 | LOCAL_CFLAGS ?= -O0 -g 7 | PROGRAM = mtrace-example 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter18/mtrace-example/mtrace-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int j; 8 | 9 | mtrace(); 10 | 11 | for (j = 0; j < 2; j++) 12 | malloc(100); /* Never freed:a memory leak */ 13 | 14 | calloc(16, 16); /* Never freed:a memory leak */ 15 | exit(EXIT_SUCCESS); 16 | } 17 | -------------------------------------------------------------------------------- /Chapter18/pagefault-demo/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) 2 | # 3 | # If cross-compiling, CC must point to your cross compiler, for example: 4 | # make CC=arm-linux-gnueabihf-gcc 5 | 6 | LOCAL_CFLAGS ?= -Wall -g 7 | PROGRAM = pagefault-demo 8 | 9 | $(PROGRAM): $(PROGRAM).c 10 | $(CC) $(CFLAGS) $(LOCAL_CFLAGS) $(LDFLAGS) $^ -o $@ 11 | 12 | clean: 13 | rm -f $(PROGRAM) 14 | 15 | -------------------------------------------------------------------------------- /Chapter18/pagefault-demo/pagefault-demo.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BUFFER_SIZE (1024 * 1024) 9 | 10 | void print_pgfaults(void) 11 | { 12 | int ret; 13 | struct rusage usage; 14 | 15 | ret = getrusage(RUSAGE_SELF, &usage); 16 | 17 | if (ret == -1) { 18 | perror("getrusage"); 19 | } else { 20 | printf("Major page faults %ld\n", usage.ru_majflt); 21 | printf("Minor page faults %ld\n", usage.ru_minflt); 22 | } 23 | } 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | unsigned char *p; 28 | 29 | printf("Initial state\n"); 30 | print_pgfaults(); 31 | p = malloc(BUFFER_SIZE); 32 | printf("After malloc\n"); 33 | print_pgfaults(); 34 | memset(p, 0x42, BUFFER_SIZE); 35 | printf("After memset\n"); 36 | print_pgfaults(); 37 | memset(p, 0x42, BUFFER_SIZE); 38 | printf("After 2nd memset\n"); 39 | print_pgfaults(); 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /Chapter19/buildroot/configs/rpi4_64_gdb_defconfig: -------------------------------------------------------------------------------- 1 | BR2_aarch64=y 2 | BR2_cortex_a72=y 3 | BR2_ARM_FPU_VFPV4=y 4 | BR2_TOOLCHAIN_EXTERNAL=y 5 | BR2_TOOLCHAIN_EXTERNAL_LINARO_AARCH64=y 6 | BR2_PACKAGE_HOST_GDB=y 7 | BR2_PACKAGE_HOST_GDB_TUI=y 8 | BR2_PACKAGE_HOST_GDB_PYTHON3=y 9 | BR2_GDB_VERSION_14=y 10 | BR2_ENABLE_DEBUG=y 11 | BR2_TARGET_GENERIC_ROOT_PASSWD="temppwd" 12 | BR2_TARGET_GENERIC_GETTY_PORT="ttyS0" 13 | BR2_TARGET_GENERIC_GETTY_BAUDRATE_115200=y 14 | BR2_SYSTEM_DHCP="eth0" 15 | BR2_ROOTFS_POST_BUILD_SCRIPT="board/raspberrypi4-64/post-build.sh" 16 | BR2_ROOTFS_POST_IMAGE_SCRIPT="board/raspberrypi4-64/post-image.sh" 17 | BR2_LINUX_KERNEL=y 18 | BR2_LINUX_KERNEL_CUSTOM_TARBALL=y 19 | BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,17f135b742c4edb340afb365873c3a574f7e16cb)/linux-17f135b742c4edb340afb365873c3a574f7e16cb.tar.gz" 20 | BR2_LINUX_KERNEL_DEFCONFIG="bcm2711" 21 | BR2_LINUX_KERNEL_DTS_SUPPORT=y 22 | BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2711-rpi-4-b" 23 | BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 24 | BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y 25 | BR2_PACKAGE_XZ=y 26 | BR2_PACKAGE_GDB=y 27 | BR2_PACKAGE_BSDIFF=y 28 | BR2_PACKAGE_RPI_FIRMWARE=y 29 | BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4=y 30 | BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="board/raspberrypi4-64/config_4_64bit.txt" 31 | BR2_PACKAGE_HAVEGED=y 32 | BR2_PACKAGE_DROPBEAR=y 33 | BR2_PACKAGE_KMOD=y 34 | BR2_PACKAGE_KMOD_TOOLS=y 35 | BR2_TARGET_ROOTFS_EXT2=y 36 | BR2_TARGET_ROOTFS_EXT2_4=y 37 | BR2_TARGET_ROOTFS_EXT2_SIZE="120M" 38 | # BR2_TARGET_ROOTFS_TAR is not set 39 | BR2_PACKAGE_HOST_DOSFSTOOLS=y 40 | BR2_PACKAGE_HOST_GENIMAGE=y 41 | BR2_PACKAGE_HOST_KMOD_XZ=y 42 | BR2_PACKAGE_HOST_MTOOLS=y 43 | -------------------------------------------------------------------------------- /Chapter19/buildroot/package/mbx-driver-oops/Config.in: -------------------------------------------------------------------------------- 1 | config BR2_PACKAGE_MBX_DRIVER_OOPS 2 | bool "mbx_driver_oops" 3 | depends on BR2_LINUX_KERNEL 4 | -------------------------------------------------------------------------------- /Chapter19/buildroot/package/mbx-driver-oops/mbx_driver.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # mbx_driver_oops 4 | # 5 | ################################################################################ 6 | 7 | MBX_DRIVER_OOPS_VERSION = 1.0.0 8 | MBX_DRIVER_OOPS_SITE = /home/frank/MELD/Chapter19/mbx-driver-oops 9 | MBX_DRIVER_OOPS_SITE_METHOD = local 10 | 11 | $(eval $(kernel-module)) 12 | $(eval $(generic-package)) 13 | -------------------------------------------------------------------------------- /Chapter19/buildroot/package/mbx-driver/Config.in: -------------------------------------------------------------------------------- 1 | config BR2_PACKAGE_MBX_DRIVER 2 | bool "mbx_driver" 3 | depends on BR2_LINUX_KERNEL 4 | -------------------------------------------------------------------------------- /Chapter19/buildroot/package/mbx-driver/mbx_driver.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # mbx_driver 4 | # 5 | ################################################################################ 6 | 7 | MBX_DRIVER_VERSION = 1.0.0 8 | MBX_DRIVER_SITE = /home/frank/MELD/Chapter19/mbx-driver 9 | MBX_DRIVER_SITE_METHOD = local 10 | 11 | $(eval $(kernel-module)) 12 | $(eval $(generic-package)) 13 | -------------------------------------------------------------------------------- /Chapter19/mbx-driver-oops/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := mbx.o 2 | 3 | SRC := $(shell pwd) 4 | 5 | all: 6 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) 7 | 8 | modules_install: 9 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install 10 | 11 | clean: 12 | rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c 13 | rm -f Module.markers Module.symvers modules.order 14 | rm -rf .tmp_versions Modules.symvers 15 | -------------------------------------------------------------------------------- /Chapter19/mbx-driver-oops/mbx.c: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------- */ 2 | /* */ 3 | /* Mailbox driver */ 4 | /* */ 5 | /* Copyright (C) 2017, Chris Simmonds (chris@2net.co.uk) */ 6 | /* */ 7 | /* This program is free software; you can redistribute it and/or modify */ 8 | /* it under the terms of the GNU General Public License as published by */ 9 | /* the Free Software Foundation; either version 2 of the License, or */ 10 | /* (at your option) any later version. */ 11 | /* */ 12 | /* This program is distributed in the hope that it will be useful, */ 13 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 14 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ 15 | /* General Public License for more details. */ 16 | /* */ 17 | /* You should have received a copy of the GNU General Public License */ 18 | /* along with this program; if not, write to the Free Software */ 19 | /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 20 | /* */ 21 | /* ------------------------------------------------------------------------- */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define DEVICE_NAME "mbx" 34 | #define MAJOR_NUM 42 35 | #define NUM_MAILBOXES 4 36 | #define MBX_LEN 1024 37 | 38 | /* Define this macro to cause an oops on read or write */ 39 | #define GO_OOPS 1 40 | 41 | struct mbx_data { 42 | char *mbx; 43 | int mbx_len; 44 | wait_queue_head_t wq; 45 | }; 46 | 47 | static struct mbx_data mailboxes[NUM_MAILBOXES]; 48 | static struct class *mbx_class; 49 | 50 | static int mbx_open(struct inode *inode, struct file *file) 51 | { 52 | if (MINOR(inode->i_rdev) >= NUM_MAILBOXES) { 53 | printk("Invalid mbx minor number\n"); 54 | return -ENODEV; 55 | } 56 | #ifndef GO_OOPS 57 | file->private_data = &mailboxes[MINOR(inode->i_rdev)]; 58 | #endif 59 | return 0; 60 | } 61 | 62 | static int mbx_release(struct inode *inode, struct file *file) 63 | { 64 | return 0; 65 | } 66 | 67 | static ssize_t mbx_read(struct file *file, 68 | char *buffer, size_t length, loff_t * offset) 69 | { 70 | struct mbx_data *m = (struct mbx_data *)file->private_data; 71 | int len; 72 | int ret; 73 | 74 | if (m->mbx_len == 0) { 75 | if (file->f_flags & O_NONBLOCK) 76 | return -EAGAIN; 77 | ret = wait_event_interruptible(m->wq, m->mbx_len > 0); 78 | if (ret != 0) { 79 | return ret; 80 | } 81 | } 82 | 83 | len = m->mbx_len; 84 | if (len > length) 85 | len = length; 86 | if (copy_to_user(buffer, m->mbx, m->mbx_len) != 0) { 87 | printk("copy_to_user failed\n"); 88 | return -EFAULT; 89 | } 90 | m->mbx_len = 0; 91 | return len; 92 | } 93 | 94 | static ssize_t mbx_write(struct file *file, 95 | const char *buffer, size_t length, loff_t * offset) 96 | { 97 | struct mbx_data *m = (struct mbx_data *)file->private_data; 98 | 99 | if (length > MBX_LEN) 100 | length = MBX_LEN; 101 | m->mbx_len = length; 102 | if (copy_from_user(m->mbx, buffer, length) != 0) { 103 | printk("copy_from_user failed\n"); 104 | return -EFAULT; 105 | } 106 | wake_up_interruptible(&m->wq); 107 | return length; 108 | } 109 | 110 | static unsigned int mbx_poll(struct file *file, poll_table * wait) 111 | { 112 | struct mbx_data *m = (struct mbx_data *)file->private_data; 113 | unsigned int mask = 0; 114 | 115 | poll_wait(file, &m->wq, wait); 116 | 117 | /* See if there is any data to read */ 118 | if (m->mbx_len > 0) 119 | mask |= (POLLIN | POLLRDNORM); 120 | 121 | /* Writing is always possible */ 122 | mask |= (POLLOUT | POLLWRNORM); 123 | 124 | return mask; 125 | } 126 | 127 | static long mbx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 128 | { 129 | int ret = 0; 130 | 131 | return ret; 132 | } 133 | 134 | struct file_operations mbx_fops = { 135 | .owner = THIS_MODULE, 136 | .open = mbx_open, 137 | .release = mbx_release, 138 | .read = mbx_read, 139 | .write = mbx_write, 140 | .poll = mbx_poll, 141 | .unlocked_ioctl = mbx_ioctl 142 | }; 143 | 144 | int __init mbx_init(void) 145 | { 146 | int ret; 147 | int i; 148 | 149 | printk("Mailbox loaded\n"); 150 | ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &mbx_fops); 151 | if (ret != 0) 152 | return ret; 153 | 154 | /* Create a "mbx" class which will show up as /sys/class/mbx. The main 155 | benefit will be to cause udev/mdev to create the appropriate 156 | device node in/dev */ 157 | mbx_class = class_create(THIS_MODULE, DEVICE_NAME); 158 | for (i = 0; i < NUM_MAILBOXES; i++) { 159 | mailboxes[i].mbx_len = 0; 160 | init_waitqueue_head(&mailboxes[i].wq); 161 | device_create(mbx_class, NULL, 162 | MKDEV(MAJOR_NUM, i), NULL, "mbx%d", i); 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | void __exit mbx_exit(void) 169 | { 170 | int i; 171 | 172 | for (i = 0; i < NUM_MAILBOXES; i++) { 173 | device_destroy(mbx_class, MKDEV(MAJOR_NUM, i)); 174 | } 175 | class_destroy(mbx_class); 176 | 177 | unregister_chrdev(MAJOR_NUM, DEVICE_NAME); 178 | printk("Mailbox unloaded\n"); 179 | } 180 | 181 | module_init(mbx_init); 182 | module_exit(mbx_exit); 183 | MODULE_LICENSE("GPL"); 184 | MODULE_AUTHOR("Chris Simmonds"); 185 | MODULE_DESCRIPTION("A sort of mailbox"); 186 | -------------------------------------------------------------------------------- /Chapter19/mbx-driver/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := mbx.o 2 | 3 | SRC := $(shell pwd) 4 | 5 | all: 6 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) 7 | 8 | modules_install: 9 | $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install 10 | 11 | clean: 12 | rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c 13 | rm -f Module.markers Module.symvers modules.order 14 | rm -rf .tmp_versions Modules.symvers 15 | -------------------------------------------------------------------------------- /Chapter19/mbx-driver/mbx.c: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------- */ 2 | /* mbx.c */ 3 | /* */ 4 | /* Mailbox driver */ 5 | /* */ 6 | /* Copyright (C) 2011, 2net Limted */ 7 | /* */ 8 | /* This program is free software; you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation; either version 2 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* This program is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ 16 | /* General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with this program; if not, write to the Free Software */ 20 | /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 21 | /* */ 22 | /* ------------------------------------------------------------------------- */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define DEVICE_NAME "mbx" 35 | #define MAJOR_NUM 42 36 | #define NUM_MAILBOXES 4 37 | #define MBX_LEN 1024 38 | 39 | struct mbx_data { 40 | char mbx[MBX_LEN]; 41 | int mbx_len; 42 | wait_queue_head_t wq; 43 | }; 44 | 45 | static struct mbx_data mailboxes[NUM_MAILBOXES]; 46 | static struct class *mbx_class; 47 | 48 | static int mbx_open(struct inode *inode, struct file *file) 49 | { 50 | if (MINOR(inode->i_rdev) >= NUM_MAILBOXES) { 51 | pr_err("Invalid mbx minor number\n"); 52 | return -ENODEV; 53 | } 54 | file->private_data = &mailboxes[MINOR(inode->i_rdev)]; 55 | return 0; 56 | } 57 | 58 | static int mbx_release(struct inode *inode, struct file *file) 59 | { 60 | return 0; 61 | } 62 | 63 | static ssize_t mbx_read(struct file *file, 64 | char *buffer, size_t length, loff_t *offset) 65 | { 66 | struct mbx_data *m = (struct mbx_data *)file->private_data; 67 | int len; 68 | int ret; 69 | 70 | if (m->mbx_len == 0) { 71 | if (file->f_flags & O_NONBLOCK) 72 | return -EAGAIN; 73 | ret = wait_event_interruptible(m->wq, m->mbx_len > 0); 74 | if (ret != 0) 75 | return ret; 76 | } 77 | 78 | len = m->mbx_len; 79 | if (len > length) 80 | len = length; 81 | if (copy_to_user(buffer, m->mbx, len) != 0) { 82 | pr_err("copy_to_user failed\n"); 83 | return -EFAULT; 84 | } 85 | m->mbx_len = 0; 86 | return len; 87 | } 88 | 89 | static ssize_t mbx_write(struct file *file, 90 | const char *buffer, size_t length, loff_t *offset) 91 | { 92 | struct mbx_data *m = (struct mbx_data *)file->private_data; 93 | 94 | if (length > MBX_LEN) 95 | return -EINVAL; 96 | m->mbx_len = length; 97 | if (copy_from_user(m->mbx, buffer, length) != 0) { 98 | pr_err("copy_from_user failed\n"); 99 | return -EFAULT; 100 | } 101 | wake_up_interruptible(&m->wq); 102 | return length; 103 | } 104 | 105 | static unsigned int mbx_poll(struct file *file, poll_table *wait) 106 | { 107 | struct mbx_data *m = (struct mbx_data *)file->private_data; 108 | unsigned int mask = 0; 109 | 110 | poll_wait(file, &m->wq, wait); 111 | 112 | /* See if there is any data to read */ 113 | if (m->mbx_len > 0) 114 | mask |= (POLLIN | POLLRDNORM); 115 | 116 | /* Writing is always possible */ 117 | mask |= (POLLOUT | POLLWRNORM); 118 | 119 | return mask; 120 | } 121 | 122 | static const struct file_operations mbx_fops = { 123 | .owner = THIS_MODULE, 124 | .open = mbx_open, 125 | .release = mbx_release, 126 | .read = mbx_read, 127 | .write = mbx_write, 128 | .poll = mbx_poll 129 | }; 130 | 131 | int __init mbx_init(void) 132 | { 133 | int ret; 134 | int i; 135 | 136 | pr_info("Mailbox loaded\n"); 137 | ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &mbx_fops); 138 | if (ret != 0) 139 | return ret; 140 | 141 | /* Create a "mbx" class which will show up as /sys/class/mbx. The main 142 | benefit will be to cause udev/mdev to create the appropriate 143 | device node in/dev */ 144 | mbx_class = class_create(THIS_MODULE, DEVICE_NAME); 145 | for (i = 0; i < NUM_MAILBOXES; i++) { 146 | mailboxes[i].mbx_len = 0; 147 | init_waitqueue_head(&mailboxes[i].wq); 148 | device_create(mbx_class, NULL, 149 | MKDEV(MAJOR_NUM, i), NULL, "mbx%d", i); 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | void __exit mbx_exit(void) 156 | { 157 | int i; 158 | 159 | for (i = 0; i < NUM_MAILBOXES; i++) 160 | device_destroy(mbx_class, MKDEV(MAJOR_NUM, i)); 161 | class_destroy(mbx_class); 162 | 163 | unregister_chrdev(MAJOR_NUM, DEVICE_NAME); 164 | pr_info("Mailbox unloaded\n"); 165 | } 166 | 167 | module_init(mbx_init); 168 | module_exit(mbx_exit); 169 | MODULE_LICENSE("GPL"); 170 | MODULE_AUTHOR("Chris Simmonds"); 171 | MODULE_DESCRIPTION("A sort of mailbox"); 172 | -------------------------------------------------------------------------------- /Chapter19/tp.py: -------------------------------------------------------------------------------- 1 | import gdb 2 | 3 | tp = {} 4 | 5 | class Tracepoint(gdb.Breakpoint): 6 | def __init__(self, *args): 7 | super().__init__(*args) 8 | self.silent = True 9 | self.count = 0 10 | 11 | def stop(self): 12 | self.count += 1 13 | frame = gdb.newest_frame() 14 | block = frame.block() 15 | sym_and_line = frame.find_sal() 16 | framename = frame.name() 17 | filename = sym_and_line.symtab.filename 18 | line = sym_and_line.line 19 | # show tracepoint info 20 | print("{0} @ {1}:{2}".format(framename, filename, line)) 21 | # show args and vars 22 | for s in block: 23 | if not s.is_argument and not s.is_variable: 24 | continue 25 | typ = s.type 26 | val = s.value(frame) 27 | size = typ.sizeof 28 | name = s.name 29 | print("\t{0}({1}: {2}) [{3}]".format(name, typ, val, size)) 30 | # do not stop at tracepoint 31 | return False 32 | 33 | class SetTracepoint(gdb.Command): 34 | def __init__(self): 35 | super().__init__("tp", gdb.COMMAND_USER) 36 | 37 | def invoke(self, args, tty): 38 | try: 39 | global tp 40 | tp[args] = Tracepoint(args) 41 | except Exception as e: 42 | print(e) 43 | 44 | def finish(event): 45 | for t,p in tp.items(): 46 | c = p.count 47 | print("Tracepoint '{0}' Count: {1}".format(t, c)) 48 | 49 | gdb.events.exited.connect(finish) 50 | SetTracepoint() 51 | -------------------------------------------------------------------------------- /Chapter20/buildroot/configs/rpi4_64_lttng_defconfig: -------------------------------------------------------------------------------- 1 | BR2_aarch64=y 2 | BR2_cortex_a72=y 3 | BR2_ARM_FPU_VFPV4=y 4 | BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_1=y 5 | BR2_TOOLCHAIN_BUILDROOT_CXX=y 6 | BR2_TARGET_GENERIC_ROOT_PASSWD="temppwd" 7 | BR2_SYSTEM_DHCP="eth0" 8 | BR2_ROOTFS_POST_BUILD_SCRIPT="board/raspberrypi4-64/post-build.sh" 9 | BR2_ROOTFS_POST_IMAGE_SCRIPT="board/raspberrypi4-64/post-image.sh" 10 | BR2_LINUX_KERNEL=y 11 | BR2_LINUX_KERNEL_CUSTOM_TARBALL=y 12 | BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,17f135b742c4edb340afb365873c3a574f7e16cb)/linux-17f135b742c4edb340afb365873c3a574f7e16cb.tar.gz" 13 | BR2_LINUX_KERNEL_DEFCONFIG="bcm2711" 14 | BR2_LINUX_KERNEL_DTS_SUPPORT=y 15 | BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2711-rpi-4-b" 16 | BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 17 | BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y 18 | BR2_PACKAGE_XZ=y 19 | BR2_PACKAGE_LTTNG_MODULES=y 20 | BR2_PACKAGE_LTTNG_TOOLS=y 21 | BR2_PACKAGE_RPI_FIRMWARE=y 22 | BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4=y 23 | BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="board/raspberrypi4-64/config_4_64bit.txt" 24 | BR2_PACKAGE_LTTNG_LIBUST=y 25 | BR2_PACKAGE_HAVEGED=y 26 | BR2_PACKAGE_DROPBEAR=y 27 | BR2_PACKAGE_KMOD=y 28 | BR2_PACKAGE_KMOD_TOOLS=y 29 | BR2_PACKAGE_UTIL_LINUX_UUIDD=y 30 | BR2_TARGET_ROOTFS_EXT2=y 31 | BR2_TARGET_ROOTFS_EXT2_4=y 32 | BR2_TARGET_ROOTFS_EXT2_SIZE="120M" 33 | # BR2_TARGET_ROOTFS_TAR is not set 34 | BR2_PACKAGE_HOST_BABELTRACE2=y 35 | BR2_PACKAGE_HOST_DOSFSTOOLS=y 36 | BR2_PACKAGE_HOST_GENIMAGE=y 37 | BR2_PACKAGE_HOST_KMOD_XZ=y 38 | BR2_PACKAGE_HOST_MTOOLS=y 39 | -------------------------------------------------------------------------------- /Chapter20/buildroot/configs/rpi4_64_ply_defconfig: -------------------------------------------------------------------------------- 1 | BR2_aarch64=y 2 | BR2_cortex_a72=y 3 | BR2_ARM_FPU_VFPV4=y 4 | BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_1=y 5 | BR2_TOOLCHAIN_BUILDROOT_CXX=y 6 | BR2_TARGET_GENERIC_ROOT_PASSWD="temppwd" 7 | BR2_SYSTEM_DHCP="eth0" 8 | BR2_ROOTFS_POST_BUILD_SCRIPT="board/raspberrypi4-64/post-build.sh" 9 | BR2_ROOTFS_POST_IMAGE_SCRIPT="board/raspberrypi4-64/post-image.sh" 10 | BR2_LINUX_KERNEL=y 11 | BR2_LINUX_KERNEL_CUSTOM_TARBALL=y 12 | BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,17f135b742c4edb340afb365873c3a574f7e16cb)/linux-17f135b742c4edb340afb365873c3a574f7e16cb.tar.gz" 13 | BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y 14 | BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/raspberrypi/linux_defconfig_4_64bit" 15 | BR2_LINUX_KERNEL_DTS_SUPPORT=y 16 | BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2711-rpi-4-b" 17 | BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 18 | BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y 19 | BR2_PACKAGE_XZ=y 20 | BR2_PACKAGE_RPI_FIRMWARE=y 21 | BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4=y 22 | BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="board/raspberrypi4-64/config_4_64bit.txt" 23 | BR2_PACKAGE_HAVEGED=y 24 | BR2_PACKAGE_KMOD=y 25 | BR2_PACKAGE_KMOD_TOOLS=y 26 | BR2_PACKAGE_EBPF=y 27 | BR2_TARGET_ROOTFS_EXT2=y 28 | BR2_TARGET_ROOTFS_EXT2_4=y 29 | BR2_TARGET_ROOTFS_EXT2_SIZE="120M" 30 | # BR2_TARGET_ROOTFS_TAR is not set 31 | BR2_PACKAGE_HOST_DOSFSTOOLS=y 32 | BR2_PACKAGE_HOST_GENIMAGE=y 33 | BR2_PACKAGE_HOST_KMOD_XZ=y 34 | BR2_PACKAGE_HOST_MTOOLS=y 35 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/Config.in: -------------------------------------------------------------------------------- 1 | config BR2_PACKAGE_EBPF 2 | bool "ebpf" 3 | select BR2_PACKAGE_DROPBEAR 4 | select BR2_PACKAGE_TMUX 5 | select BR2_PACKAGE_VIM 6 | select BR2_PACKAGE_BPFTOOL 7 | select BR2_PACKAGE_PLY 8 | select BR2_PACKAGE_REDIS 9 | help 10 | An image overlay that includes ply for dynamic tracing 11 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/count-syscalls.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kprobe:__arm64_sys_* 4 | { 5 | @syscalls[caller] = count(); 6 | } 7 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/ebpf.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # ebpf 4 | # 5 | ################################################################################ 6 | 7 | EBPF_VERSION = 0.1 8 | EBPF_SITE = package/ebpf 9 | EBPF_SITE_METHOD = local 10 | EBPF_DEPENDENCIES = ply 11 | 12 | define EBPF_INSTALL_TARGET_CMDS 13 | $(INSTALL) -D -m 0644 $(@D)/fstab $(TARGET_DIR)/etc/ 14 | $(INSTALL) -D -m 0755 $(@D)/self-test.sh $(TARGET_DIR)/root/ 15 | $(INSTALL) -D -m 0755 $(@D)/test.sh $(TARGET_DIR)/root/ 16 | $(INSTALL) -D -m 0755 $(@D)/count-syscalls.ply $(TARGET_DIR)/root/ 17 | $(INSTALL) -D -m 0755 $(@D)/read-dist.ply $(TARGET_DIR)/root/ 18 | $(INSTALL) -D -m 0755 $(@D)/i2c-stack.ply $(TARGET_DIR)/root/ 19 | $(INSTALL) -D -m 0755 $(@D)/opensnoop.ply $(TARGET_DIR)/root/ 20 | $(INSTALL) -D -m 0755 $(@D)/execsnoop.ply $(TARGET_DIR)/root/ 21 | $(INSTALL) -D -m 0755 $(@D)/tcp-send-recv.ply $(TARGET_DIR)/root/ 22 | $(INSTALL) -D -m 0755 $(@D)/heap-allocs.ply $(TARGET_DIR)/root/ 23 | endef 24 | 25 | $(eval $(generic-package)) 26 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/fstab: -------------------------------------------------------------------------------- 1 | # 2 | /dev/root / ext2 rw,noauto 0 1 3 | proc /proc proc defaults 0 0 4 | devpts /dev/pts devpts defaults,gid=5,mode=620,ptmxmode=0666 0 0 5 | tmpfs /dev/shm tmpfs mode=1777 0 0 6 | tmpfs /tmp tmpfs mode=1777 0 0 7 | tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0 8 | sysfs /sys sysfs defaults 0 0 9 | debugfs /sys/kernel/debug debugfs auto 0 0 10 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/heap-allocs.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kprobe:__arm64_sys_brk 4 | { 5 | @heap_allocs[comm, kpid] = count(); 6 | } 7 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/i2c-stack.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kprobe:i2c_transfer 4 | { 5 | print(stack); 6 | } 7 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/opensnoop.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kprobe:do_sys_openat2 4 | { 5 | path[kpid] = str(arg1); 6 | } 7 | 8 | kretprobe:do_sys_openat2 9 | { 10 | printf("%v %v %v\n", pid, comm, path[kpid]); 11 | } 12 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/read-dist.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kretprobe:__arm64_sys_read 4 | { 5 | @["retsize"] = quantize(retval); 6 | } 7 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/self-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ ! "$PLYBIN" ]; then 6 | echo PLYBIN is not set 7 | exit 1 8 | fi 9 | 10 | err=0 11 | 12 | if [ -f /proc/config.gz ]; then 13 | echo -n "Verifying kernel config (/proc/config.gz)... " 14 | kconf="zcat /proc/config.gz" 15 | elif [ -f /boot/config-$(uname -r) ]; then 16 | echo -n "Verifying kernel config (/boot/config-$(uname -r))... " 17 | kconf="cat /boot/config-$(uname -r)" 18 | fi 19 | 20 | if [ "$kconf" ]; then 21 | $kconf | awk ' 22 | /^CONFIG_BPF_SYSCALL=y$/ { bpf=1 } 23 | /^CONFIG_KPROBES=y$/ { kprobes=1 } 24 | /^CONFIG_TRACEPOINTS=y$/ { tracepoints=1 } 25 | /^CONFIG_FTRACE=y$/ { ftrace=1 } 26 | /^CONFIG_DYNAMIC_FTRACE=y$/ { dftrace=1 } 27 | END { 28 | if (bpf && (kprobes || tracepoints) && ftrace) { 29 | print("OK"); 30 | err = 0; 31 | } else { 32 | print("ERROR"); 33 | err = 1; 34 | } 35 | 36 | if (!bpf) 37 | print(" CONFIG_BPF_SYSCALL is not set"); 38 | if (!kprobes) 39 | print(" CONFIG_KPROBES is not set"); 40 | if (!tracepoints) 41 | print(" CONFIG_TRACEPOINTS is not set"); 42 | if (!ftrace) 43 | print(" CONFIG_FTRACE is not set"); 44 | if (!dftrace) 45 | print(" CONFIG_DYNAMIC_FTRACE is not set"); 46 | 47 | exit(err); 48 | }' || err=1 49 | else 50 | echo "WARN: Unable to verify kernel config" 51 | fi 52 | 53 | echo -n "Ensuring that debugfs is mounted... " 54 | if mountpoint -q /sys/kernel/debug; then 55 | echo "OK" 56 | else 57 | echo "ERROR" 58 | err=1 59 | fi 60 | 61 | if [ $(id -u) -ne 0 ]; then 62 | echo "WARN: not running as root, ply requires cap_sys_admin" 63 | fi 64 | 65 | echo -n "Verifying kprobe... " 66 | if $PLYBIN 'kprobe:schedule { exit(0); }' 2>/dev/null; then 67 | echo "OK" 68 | else 69 | echo "ERROR" 70 | err=1 71 | fi 72 | 73 | echo -n "Verifying tracepoint... " 74 | if $PLYBIN 'tracepoint:sched/sched_switch { exit(0); }' 2>/dev/null; then 75 | echo "OK" 76 | else 77 | echo "ERROR" 78 | err=1 79 | fi 80 | 81 | exit $err 82 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/tcp-send-recv.ply: -------------------------------------------------------------------------------- 1 | #!/usr/sbin/ply 2 | 3 | kprobe:tcp_sendmsg 4 | { 5 | @[comm, "send"] = count(); 6 | } 7 | 8 | kprobe:tcp_recvmsg 9 | { 10 | @[comm, "recv"] = count(); 11 | } 12 | -------------------------------------------------------------------------------- /Chapter20/buildroot/package/ebpf/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | total_fails=0 4 | 5 | fail() 6 | { 7 | echo " FAIL $case expected \"$1\", got \"$2\"" 8 | total_fails=$(($total_fails + 1)) 9 | } 10 | 11 | ply_simple() 12 | { 13 | stdout=$(ply -c true "tracepoint:sched/sched_process_exit { ${1} }") 14 | code=$? 15 | } 16 | 17 | case=self-test 18 | PLYBIN=/usr/sbin/ply ./self-test.sh || fail "zero exitcode" "non-zero exitcode" 19 | 20 | case=exit && ply_simple 'exit(42);' && \ 21 | [ $code -eq 42 ] || fail 42 $code 22 | 23 | case=if-stmt && ply_simple 'if (pid > 1) exit(0); else exit(1);' && \ 24 | [ $code -eq 0 ] || fail 0 $code 25 | 26 | case=print && ply_simple 'print("test"); exit(0);' && \ 27 | [ $stdout = test ] || fail test "$stdout" 28 | 29 | 30 | case=wildcard 31 | ply -c \ 32 | "dd if=/dev/zero of=/dev/null bs=1 count=100" \ 33 | "kprobe:vfs_* { @[comm, caller] = count(); }" >/tmp/wildcard \ 34 | && \ 35 | cat /tmp/wildcard | awk ' 36 | /dd.*vfs_read/ { if ($NF > 100) read = 1; } 37 | /dd.*vfs_write/ { if ($NF > 100) write = 1; } 38 | END { exit(!(read && write)); }' \ 39 | || fail "at least 100 reads/writes" "$(cat /tmp/wildcard)" 40 | 41 | 42 | case=quantize 43 | ply -c \ 44 | "dd if=/dev/zero of=/dev/null bs=10240 count=10" \ 45 | 'kr:vfs_read if (!strcmp(comm, "dd")) { 46 | @["rdsz"] = quantize(retval); 47 | }' >/tmp/quantize \ 48 | && \ 49 | grep -qe '8k\s*,\s*16k\s*)\s*10' /tmp/quantize \ 50 | || fail "10 reads in (8k, 16k]" "$(cat /tmp/quantize)" 51 | 52 | exit $total_fails 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mastering Embedded Linux Development – Fourth Edition 2 | 3 | This is the code repository for [Mastering Embedded Linux Development – Fourth Edition](https://www.packtpub.com/product/mastering-embedded-linux-programming-third-edition/9781803232591?utm_source=github&utm_medium=repository&utm_campaign=9781803232591), published by Packt. 4 | 5 | **Create fast and reliable embedded solutions with Linux 6.6 and the Yocto Project 5.0 (Scarthgap)** 6 | 7 | ## What is this book about? 8 | Embedded Linux runs many of the devices we use every day. From smart TVs and Wi-Fi routers to test equipment and industrial controllers, all of them have Linux as their heart. The Linux operating system is one of the foundational technologies that powers the internet. This book starts by breaking down the fundamental elements that underpin all embedded Linux projects: the toolchain, the bootloader, the kernel, and the root filesystem. After that, you will learn how to generate the last three elements from scratch and automate the process using Buildroot and the Yocto Project. 9 | 10 | This book covers the following exciting topics: 11 | * Create embedded Linux systems with Buildroot and the Yocto Project 12 | * Troubleshoot BitBake build failures and streamline your Yocto development workflow 13 | * Update devices securely in the field using Mender or balena 14 | * Prototype peripheral additions by with add-on boards 15 | * Interact with hardware without having to write kernel device drivers 16 | 17 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1803232595) today! 18 | 19 | ## Instructions and navigation 20 | All of the code is organized into folders. For example, `Chapter02`. 21 | 22 | The code will look like the following: 23 | ``` 24 | if (test expression) 25 | { 26 | Statement upon condition is true 27 | } 28 | ``` 29 | 30 | ## What do you need for this book? 31 | If you're a software engineer or system administrator who wants to learn how to run Linux on embedded devices, then this book is for you. Firmware engineers accustomed to programming for low-power microcontrollers can use this book to help make the leap to high-speed systems on chips that can run Linux. Anyone responsible for developing new hardware that needs to run Linux will also find this book useful. Basic working knowledge of the POSIX standard, C programming, Python programming, and shell scripting is assumed. 32 | 33 | With the following software and hardware you can run all of the code examples present in the book (Chapters 1-21). 34 | 35 | ### Software and hardware list 36 | 37 | | Chapters | Software/Hardware Required | OS Required | 38 | | --------------------------- | ----------------------------------- | ------------------------ | 39 | | 3, 4, 5, 6, 9, 11, 12, 14 | BeaglePlay | Debian 12.7 Minimal | 40 | | 4, 6, 7, 10, 16, 19, 20 | Raspberry Pi 4 | Ubuntu Server 24.04 LTS | 41 | | 4, 5, 6, 7, 10 | QEMU (64-bit Arm) | Ubuntu Desktop 24.04 LTS | 42 | | 6, 7, 8, 10, 11, 13, 19, 21 | Yocto Project 5.0 (Scarthgap) | Ubuntu Desktop 24.04 LTS | 43 | | 6, 13, 19, 20 | Buildroot 2024.02 LTS | Ubuntu Desktop 24.04 LTS | 44 | | 2, 3, 4, 5 | Bootlin aarch64 toolchain 2024.02-1 | Ubuntu Desktop 24.04 LTS | 45 | | 3, 4, 5 | Arm GNU AArch32 toolchain 13.2.Rel1 | Ubuntu Desktop 24.04 LTS | 46 | | 3, 4, 5 | U-Boot v2024.04 | Ubuntu Desktop 24.04 LTS | 47 | | 4, 5 | Linux Kernel 6.6 | Ubuntu Desktop 24.04 LTS | 48 | 49 | ## Get to know the authors 50 | **Frank Vasquez** is an independent software consultant specializing in consumer electronics. He has more than a decade of experience designing and building embedded Linux systems. During that time, he has shipped numerous products, including a rackmount DSP audio server, a diver-held sonar camcorder, an IoT hotspot, a home battery, and a grid-scale energy storage system. Since the third edition of this book was published, Frank has also become a frequent speaker at open-source software conferences including The Yocto Project Summit, Embedded Linux Conference, FOSDEM, and All Systems Go! 51 | 52 | **Chris Simmonds** is a software consultant and trainer living in southern England. He has over two decades of experience designing and building open-source embedded systems. He is the founder and chief consultant at 2net Ltd, which provides professional training and mentoring services in embedded Linux, Linux device drivers, and Android platform development. He has trained engineers at many of the biggest companies in the embedded world, including Arm, Qualcomm, Intel, Ericsson, and General Dynamics. He is a frequent presenter at open-source and embedded conferences, including the Embedded Linux Conference and Embedded World. 53 | 54 | ### Download a free PDF 55 | 56 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no extra cost. Simply click on the link to claim your free PDF. 57 |

https://packt.link/free-ebook/9781803232591

58 | -------------------------------------------------------------------------------- /format-sdcard.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Format a microSD card for the BeaglePlay 3 | # Mastering Embedded Linux Development 4 | # Copyright (c) Chris Simmonds, 2024 5 | 6 | if [ $# -ne 1 ]; then 7 | echo "Usage: $0 [drive]" 8 | echo " drive is 'sdb', 'mmcblk0', etc" 9 | exit 1 10 | fi 11 | 12 | function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } 13 | 14 | DRIVE=$1 15 | 16 | # Check the drive exists in /sys/block 17 | if [ ! -e /sys/block/${DRIVE}/size ]; then 18 | echo "Drive does not exist" 19 | exit 1 20 | fi 21 | 22 | # Check it is a flash drive (size < 120 GiB) 23 | NUM_SECTORS=`cat /sys/block/${DRIVE}/size` 24 | if [ $NUM_SECTORS -eq 0 -o $NUM_SECTORS -gt 240000000 ]; then 25 | echo "/dev/$DRIVE does not look like an SD card, bailing out" 26 | exit 1 27 | fi 28 | 29 | # Unmount any partitions that have been automounted 30 | if [ $DRIVE == "mmcblk0" ]; then 31 | sudo umount /dev/${DRIVE}* 32 | BOOT_PART=/dev/${DRIVE}p1 33 | ROOT_PART=/dev/${DRIVE}p2 34 | else 35 | sudo umount /dev/${DRIVE}[1-9] 36 | BOOT_PART=/dev/${DRIVE}1 37 | ROOT_PART=/dev/${DRIVE}2 38 | fi 39 | 40 | # Overwite any existing partiton table with zeros 41 | sudo dd if=/dev/zero of=/dev/${DRIVE} bs=1M count=10 42 | if [ $? -ne 0 ]; then echo "Error: dd"; exit 1; fi 43 | 44 | # Create 2 primary partitons on the sd card 45 | # 1: FAT32, 64 MiB, boot flag 46 | # 2: Linux, 1024 MiB 47 | # Note that the parameters to sfdisk changed slightly v2.26 48 | SFDISK_VERSION=`sfdisk --version | awk '{print $4}'` 49 | if version_gt $SFDISK_VERSION "2.26"; then 50 | sudo sfdisk /dev/${DRIVE} << EOF 51 | ,64M,0x0c,* 52 | ,1024M,L, 53 | EOF 54 | else 55 | sudo sfdisk --unit M /dev/${DRIVE} << EOF 56 | ,64,0x0c,* 57 | ,1024,L, 58 | EOF 59 | fi 60 | if [ $? -ne 0 ]; then echo "Error: sdfisk"; exit 1; fi 61 | 62 | # Format p1 with FAT32 and p2 with ext4 63 | sudo mkfs.vfat -F 16 -n boot ${BOOT_PART} 64 | if [ $? -ne 0 ]; then echo "Error: mkfs.vfat"; exit 1; fi 65 | sudo mkfs.ext4 -L rootfs ${ROOT_PART} 66 | if [ $? -ne 0 ]; then echo "Error: mkfs.ext4"; exit 1; fi 67 | 68 | echo "SUCCESS! Your microSD card has been formatted" 69 | exit 0 70 | -------------------------------------------------------------------------------- /list-libs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # List shared libraries that a program is linked to 3 | # Chris Simmonds, chris@2net.co.uk 4 | 5 | if [ $# != 1 ]; then 6 | echo "Usage: $0 [progam file]" 7 | exit 1 8 | fi 9 | ${CROSS_COMPILE}readelf -a $1 | grep "program interpreter" 10 | ${CROSS_COMPILE}readelf -a $1 | grep "Shared library" 11 | exit 0 12 | --------------------------------------------------------------------------------