From b61dbfd9bc8534a9540af07c662dfebcae897115 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH] RPi: add device Slice3 --- .../RPi/devices/RPi2/linux/linux.arm.conf | 4 +- .../devices/Slice3/config/distroconfig.txt | 23 + .../RPi/devices/Slice3/config/dt-blob.bin | Bin 0 -> 4451 bytes .../RPi/devices/Slice3/config/dt-blob.dts | 98 +++ .../devices/Slice3/config/slice-overlay.dts | 172 +++++ .../devices/Slice3/config/ws2812-overlay.dts | 33 + .../Slice3/filesystem/usr/config/autostart.sh | 2 + .../Slice3/filesystem/usr/config/shutdown.sh | 23 + .../usr/share/alsa/cards/snd_slice.conf | 25 + .../RPi/devices/Slice3/linux/linux.arm.conf | 1 + projects/RPi/devices/Slice3/options | 2 + .../patches/kodi/kodi-002-slice-led.patch | 677 ++++++++++++++++++ .../patches/kodi/kodi-003-slice-audio.patch | 18 + .../patches/kodi/kodi-004-keyboard.patch | 22 + .../Slice3/patches/kodi/kodi-005-cmake.patch | 31 + 15 files changed, 1130 insertions(+), 1 deletion(-) create mode 100644 projects/RPi/devices/Slice3/config/distroconfig.txt create mode 100644 projects/RPi/devices/Slice3/config/dt-blob.bin create mode 100644 projects/RPi/devices/Slice3/config/dt-blob.dts create mode 100644 projects/RPi/devices/Slice3/config/slice-overlay.dts create mode 100644 projects/RPi/devices/Slice3/config/ws2812-overlay.dts create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf create mode 120000 projects/RPi/devices/Slice3/linux/linux.arm.conf create mode 100644 projects/RPi/devices/Slice3/options create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch diff --git a/projects/RPi/devices/RPi2/linux/linux.arm.conf b/projects/RPi/devices/RPi2/linux/linux.arm.conf index b8558ec8f7..fd7c596edf 100644 --- a/projects/RPi/devices/RPi2/linux/linux.arm.conf +++ b/projects/RPi/devices/RPi2/linux/linux.arm.conf @@ -1158,6 +1158,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_BCM2835_SMI=m +CONFIG_BCM2835_WS2812=m # CONFIG_AD525X_DPOT is not set # CONFIG_DUMMY_IRQ is not set # CONFIG_ICS932S401 is not set @@ -2893,6 +2894,7 @@ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m CONFIG_SND_BCM2708_SOC_RASPIDAC3=m +CONFIG_SND_BCM2708_SOC_SLICE=m CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m @@ -2946,7 +2948,7 @@ CONFIG_SND_SOC_ADAU7002=m # CONFIG_SND_SOC_CS42L52 is not set # CONFIG_SND_SOC_CS42L56 is not set # CONFIG_SND_SOC_CS42L73 is not set -# CONFIG_SND_SOC_CS4265 is not set +CONFIG_SND_SOC_CS4265=m # CONFIG_SND_SOC_CS4270 is not set # CONFIG_SND_SOC_CS4271_I2C is not set # CONFIG_SND_SOC_CS4271_SPI is not set diff --git a/projects/RPi/devices/Slice3/config/distroconfig.txt b/projects/RPi/devices/Slice3/config/distroconfig.txt new file mode 100644 index 0000000000..6473369b91 --- /dev/null +++ b/projects/RPi/devices/Slice3/config/distroconfig.txt @@ -0,0 +1,23 @@ +################################################################################ +# This file is part of LibreELEC - http://www.libreelec.tv +# Copyright (C) 2016 Team LibreELEC +# +# LibreELEC is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# LibreELEC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LibreELEC. If not, see . +################################################################################ + +# WARNING: DO NOT EDIT THIS FILE - IT WILL BE OVERWRITTEN WHEN UPGRADING! + +dtoverlay=slice +dtoverlay=ws2812 +dtoverlay=mmc diff --git a/projects/RPi/devices/Slice3/config/dt-blob.bin b/projects/RPi/devices/Slice3/config/dt-blob.bin new file mode 100644 index 0000000000000000000000000000000000000000..6958aae3943678be8f617a845b6a62ebfee6bac0 GIT binary patch literal 4451 zcmcJT>u%F96vtie$b6|+EPyESn85dE8kAnvc4Tl-78DoYfBx_30L`Xd27@y<0~`w3YwxiS7;SD zmRbdmrB(rCsZ|hZZ9Ir%5;khw@4-mcML;nexkzF;GgbbLo-*VjYZ!t=wmbUm6B>TpbHH!N(SNJk@EqPvfh2Uw3spSZIxm7ssG$ zQ4DYJ`v!hHU=lg)JIcip%)`AvOOIJa`arr=tgD`(~A-fr(BZ6EYc zjt;uCb#l^b?{#+ZCAiQp#^*bBDOn^2J{sXdJM!1Y0$dAqG`p=nJ^I{N&$JIN3Vl3X z;-k~+wP~l{df)Bj{TSMU=laFA9QO{7>G5t0ovhQA=Y>An-F1DunEAlAsP=e%;GNMa zlgSyqrpnF3FFo`)AJ2XA_y?Bfn&yYYcK1_u&BJluuYJF4&fZJwz`Py?{vhJ=ioj4$ z;7A(xDdVgY|vfO#0bkZX7Dr7{&ldmiyqlkSYe*vdF Bm>B>7 literal 0 HcmV?d00001 diff --git a/projects/RPi/devices/Slice3/config/dt-blob.dts b/projects/RPi/devices/Slice3/config/dt-blob.dts new file mode 100644 index 0000000000..938b72fa2c --- /dev/null +++ b/projects/RPi/devices/Slice3/config/dt-blob.dts @@ -0,0 +1,98 @@ +/dts-v1/; + +/ { + videocore { + + pins_cm3 { + + pin_config { + + pin@default { + polarity = "active_high"; + termination = "pull_down"; + startup_state = "inactive"; + function = "input"; + }; // pin + + // BANK 0 // + pin@p0 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p1 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p2 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p3 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p4 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p5 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p6 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p7 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p8 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p9 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p10 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p11 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p12 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p13 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p14 { function = "uart0"; termination = "no_pulling"; }; // UART0_TX + pin@p15 { function = "uart0"; termination = "pull_up"; }; // UART0_RX + pin@p16 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p17 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p18 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p19 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p20 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p21 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p22 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p23 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p24 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p25 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p26 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p27 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + + // BANK 1 // + pin@p28 { function = "pcm"; termination = "no_pulling"; }; // PCM_CLK + pin@p29 { function = "pcm"; termination = "no_pulling"; }; // PCM_FS + pin@p30 { function = "pcm"; termination = "no_pulling"; }; // PCM_DIN + pin@p31 { function = "pcm"; termination = "no_pulling"; }; // PCM_DOUT + pin@p32 { function = "gp_clk"; termination = "no_pulling"; }; // PCM_MCLK (GPCLK0) + pin@p33 { function = "output"; termination = "no_pulling"; polarity = "active_low"; startup_state = "inactive"; }; // AUD_RST_N + pin@p34 { function = "input"; termination = "pull_up"; }; // NOT USED + pin@p35 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "active"; }; // USB_ON + pin@p36 { function = "input"; termination = "no_pulling"; }; // RTC_IRQ + pin@p37 { function = "input"; termination = "no_pulling"; }; // IR_RX + pin@p38 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // STBY_LED + pin@p39 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // DISK_OFF + pin@p40 { function = "pwm"; termination = "no_pulling"; }; // LED_PWM + pin@p41 { function = "output"; termination = "no_pulling"; }; // LAN_RUN + pin@p42 { function = "gp_clk"; termination = "no_pulling"; }; // ETH_CLK (GPCLK1) + pin@p43 { function = "output"; termination = "pull_down"; polarity = "active_high"; startup_state = "inactive"; }; // LEDS_ON + pin@p44 { function = "i2c1"; termination = "no_pulling"; }; // SDA1 + pin@p45 { function = "i2c1"; termination = "no_pulling"; }; // SCL1 + + // BANK 2 // + pin@p46 { function = "input"; termination = "pull_up"; }; // SMPS_SCL + pin@p47 { function = "input"; termination = "pull_up"; }; // SMPS_SDA + pin@p48 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CLK + pin@p49 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CMD + pin@p50 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D0 + pin@p51 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D1 + pin@p52 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D2 + pin@p53 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D3 + pin@p128 { function = "input"; termination = "no_pulling"; polarity = "active_low"; }; // Hotplug + pin@p129 { function = "output"; termination = "no_pulling"; polarity = "active_low"; }; // EMMC_ENABLE_N + + + }; // pin_config + + pin_defines { + pin_define@HDMI_CONTROL_ATTACHED { type = "external"; number = <0>; }; // HPD_N on external gpio + pin_define@LAN_RUN { type = "internal"; number = <41>; }; // LAN_RUN + pin_define@EMMC_ENABLE { type = "external"; number = <1>; }; + pin_define@SMPS_SDA { type = "internal"; number = <46>; }; + pin_define@SMPS_SCL { type = "internal"; number = <47>; }; + }; // pin_defines + + }; // pins_cm + + clock_setup { + clock@PWM { freq = < 2400000>; }; // LEDS PWM CLOCK + clock@GPCLK1 { freq = <25000000>; }; // ETH_CLK + }; // clock_setup + + }; // videocore +}; diff --git a/projects/RPi/devices/Slice3/config/slice-overlay.dts b/projects/RPi/devices/Slice3/config/slice-overlay.dts new file mode 100644 index 0000000000..7f0a4d2f3b --- /dev/null +++ b/projects/RPi/devices/Slice3/config/slice-overlay.dts @@ -0,0 +1,172 @@ +// Definitions for Slice hardware +/dts-v1/; +/plugin/; + +#include "dt-bindings/clock/bcm2835.h" + +/ { + compatible = "brcm,bcm2708"; + + // + // Set up GPIOs: + // I2C1 on GPIO44,45 + // LIRC input/output on GPIO4 and 37 (NB GPIO4 NC on Slice) + // I2S on GPIO28-31 + // + fragment@0 { + target = <&gpio>; + __overlay__ { + i2c1_pins: i2c1 { + brcm,pins = <44 45>; + brcm,function = <6>; /* alt2 */ + }; + lirc_pins: lirc_pins { + brcm,pins = <4 37>; // + brcm,function = <1 0>; // out in + brcm,pull = <0 1>; // off down + }; + i2s_pins: i2s { + brcm,pins = <28 29 30 31>; + brcm,function = <6>; /* alt2 */ + }; + ws2812_pins: ws2812 { + brcm,pins = <40>; + brcm,function = <4>; /* alt0 */ + }; + }; + }; + + // + // I2C at 100KHz + // + fragment@1 { + target = <&i2c1>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; + }; + }; + + // + // Add devices to I2C1 Bus: + // PCF8523 RTC device + // CS4265 Audio CODEC + // + fragment@2 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + nxp,xtalcap-7pf; /* set crystal load to 7pf */ + status = "okay"; + }; + cs4265@4e { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4265"; + reg = <0x4e>; + cs4265-reset-gpios = <&gpio 33 0>; /* AUD_RST_N on GPIO33 */ + cirrus,no-s16le; /* remove S16LE support to workaround I2S controller issue */ + status = "okay"; + }; + }; + }; + + // + // LIRC + // + fragment@3 { + target-path = "/"; + __overlay__ { + lirc_rpi: lirc_rpi { + compatible = "rpi,lirc-rpi"; + pinctrl-names = "default"; + pinctrl-0 = <&lirc_pins>; + status = "okay"; + + // Override autodetection of IR receiver circuit + // (0 = active high, 1 = active low, -1 = no override ) + rpi,sense = <0xffffffff>; + + // Software carrier + // (0 = off, 1 = on) + rpi,softcarrier = <1>; + + // Invert output + // (0 = off, 1 = on) + rpi,invert = <0>; + + // Enable debugging messages + // (0 = off, 1 = on) + rpi,debug = <0>; + }; + }; + }; + + // + // Audio driver + // + fragment@4 { + #address-cells = <1>; + #size-cells = <1>; + target = <&sound>; + __overlay__ { + compatible = "fiveninjas,slice"; + clocks = <&cprman BCM2835_CLOCK_GP0>; + clock-names = "gp0"; + pinctrl-names = "default"; + i2s-controller = <&i2s>; + status = "okay"; + }; + }; + + // + // Enable I2S + // + fragment@5 { + target = <&i2s>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; + brcm,enable-mmap; + status = "okay"; + }; + }; + + // + // WS2812B LEDs driver + // + fragment@6 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + ws2812: ws2812 { + compatible = "rpi,ws2812"; + pinctrl-names = "default"; + pinctrl-0 = <&ws2812_pins>; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + rpi,invert = <1>; + rpi,num_leds = <25>; + status = "okay"; + }; + }; + }; + + // + // Disable standard audio + // + fragment@7 { + target = <&audio>; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/projects/RPi/devices/Slice3/config/ws2812-overlay.dts b/projects/RPi/devices/Slice3/config/ws2812-overlay.dts new file mode 100644 index 0000000000..42cde9d73b --- /dev/null +++ b/projects/RPi/devices/Slice3/config/ws2812-overlay.dts @@ -0,0 +1,33 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2708"; + + fragment@0 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + ws2812: ws2812 { + compatible = "rpi,ws2812"; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + + rpi,invert = <1>; + rpi,num_leds = <25>; + + status = "okay"; + + }; + }; + }; + + __overrides__ { + invert = <&ws2812>,"rpi,invert:0"; + num_leds = <&ws2812>,"rpi,num_leds:0"; + }; +}; diff --git a/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh b/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh new file mode 100644 index 0000000000..0b6166972b --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh @@ -0,0 +1,2 @@ +#!/bin/bash +hdparm -S60 /dev/sda diff --git a/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh b/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh new file mode 100644 index 0000000000..ebd32374e6 --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -f /storage/.kodi/media/ledpatterns/shutdown.png ]; then + LEDDIR=/storage/.kodi +else + LEDDIR=/usr/share/kodi +fi + +case "$1" in + halt) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + poweroff) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + reboot) + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + *) + ;; +esac diff --git a/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf b/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf new file mode 100644 index 0000000000..298f43d8e7 --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf @@ -0,0 +1,25 @@ + + +snd_slice.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } +} diff --git a/projects/RPi/devices/Slice3/linux/linux.arm.conf b/projects/RPi/devices/Slice3/linux/linux.arm.conf new file mode 120000 index 0000000000..bbe61a7104 --- /dev/null +++ b/projects/RPi/devices/Slice3/linux/linux.arm.conf @@ -0,0 +1 @@ +../../RPi2/linux/linux.arm.conf \ No newline at end of file diff --git a/projects/RPi/devices/Slice3/options b/projects/RPi/devices/Slice3/options new file mode 100644 index 0000000000..a2566ab649 --- /dev/null +++ b/projects/RPi/devices/Slice3/options @@ -0,0 +1,2 @@ + # Additional kernel make parameters + KERNEL_MAKE_EXTRACMD+=" dt-blob.dtb overlays/slice.dtbo overlays/ws2812.dtbo" diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch new file mode 100644 index 0000000000..6ba4cfb403 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch @@ -0,0 +1,677 @@ +--- a/xbmc/windows/GUIWindowHome.cpp 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.cpp 2016-10-01 19:22:20.908566550 +0100 +@@ -30,9 +30,245 @@ + #include "guilib/GUIWindowManager.h" + #include "Application.h" + #include "utils/StringUtils.h" ++extern "C" ++{ ++ #include "readpng.h" ++} + + using namespace ANNOUNCEMENT; + ++int g_pattern = 0; ++int g_halt = 0; ++int g_pattern_playing = 0; ++int g_speed = 30000; ++int g_repeat = 0; ++ ++enum pattern_e { ++ PAT_PLAY, PAT_PAUSE, PAT_STOP, PAT_SLEEP, PAT_WAKE, PAT_FFWD, PAT_REW, PAT_SKIPF, PAT_SKIPR, PAT_STARTUP, PAT_QUIT, PAT_NONE ++}; ++#define NUM_PATTERNS 11 ++const char *patterns[NUM_PATTERNS] = { ++ "play" , "pause", "stop", "sleep", "wake", "ffwd", "rew", "skipf", "skipr", "startup", "quit" ++}; ++ ++void on_speed_changed(const char *message, const CVariant &data) ++{ ++ int speed = data["player"]["speed"].asInteger(); ++ ++ CLog::Log(LOGDEBUG, "speed changed %d", speed); ++ ++ switch(abs(speed)) ++ { ++ case 1: g_speed = 60000; break; ++ case 2: g_speed = 40000; break; ++ case 4: g_speed = 35000; break; ++ case 8: g_speed = 30000; break; ++ case 16: g_speed = 25000; break; ++ case 32: g_speed = 15000; break; ++ } ++ ++ if(speed > 0) ++ g_pattern = PAT_FFWD; ++ else ++ g_pattern = PAT_REW; ++ ++ if(speed != 1) ++ g_repeat = 1; ++ else ++ { ++ g_repeat = 0; ++ g_pattern = PAT_NONE; ++ } ++} ++ ++void on_seek(const char *message, const CVariant &data) ++{ ++ int seek_time = data["player"]["seekoffset"]["seconds"].asInteger() + ++ data["player"]["seekoffset"]["minutes"].asInteger() * 60; ++ ++ CLog::Log(LOGDEBUG, "Seek offset = %d", seek_time); ++ if(seek_time > 0) ++ { ++ g_pattern = PAT_SKIPF; ++ } ++ else ++ { ++ g_pattern = PAT_SKIPR; ++ } ++ ++ g_repeat = 0; ++} ++ ++enum action_e { ++ ACTION_DO, ACTION_REPEAT, ACTION_FN ++ }; ++ ++enum led_state_e { ++ LED_STATE_INVALID = 0, ++ LED_STATE_IDLE, ++ LED_STATE_PLAYING, ++ LED_STATE_PAUSED, ++ LED_STATE_SLEEP ++}; ++ ++struct led_action_s { ++ const char * event_name; ++ enum action_e action; ++ enum pattern_e action_data; ++ void (*action_fn)(const char *, const CVariant &); ++ led_state_e action_state; ++} led_actions[] = { ++ { "OnPlay", ACTION_DO, PAT_PLAY, NULL, LED_STATE_PLAYING }, ++ { "OnPause", ACTION_DO, PAT_PAUSE, NULL, LED_STATE_PAUSED }, ++ { "OnStop", ACTION_DO, PAT_STOP, NULL, LED_STATE_IDLE }, ++ { "OnSpeedChanged", ACTION_FN, PAT_NONE, on_speed_changed, LED_STATE_INVALID }, ++ { "OnSeek", ACTION_FN, PAT_NONE, on_seek, LED_STATE_INVALID }, ++ { "OnScreensaverActivated", ACTION_DO, PAT_SLEEP, NULL, LED_STATE_SLEEP }, ++ { "OnScreensaverDeactivated", ACTION_DO, PAT_WAKE, NULL, LED_STATE_IDLE }, ++ { "OnQuit", ACTION_REPEAT, PAT_QUIT, NULL, LED_STATE_IDLE }, ++}; ++ ++int zeroes[25] = { 0,}; ++ ++class CLedPattern : public IRunnable ++{ ++ int m_going; ++ CEvent *m_ev; ++ struct pattern { ++ unsigned long w; ++ unsigned long h; ++ unsigned long rowbytes; ++ unsigned char * img; ++ } m_pattern[NUM_PATTERNS]; ++ ++ void open_patterns() ++ { ++ unsigned int i; ++ for(i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) ++ { ++ FILE * fp; ++ char filename[256]; ++ int channels; ++ ++ m_pattern[i].img = NULL; ++ sprintf(filename, "/storage/.kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename , "rb"); ++ if(fp == NULL) ++ { ++ sprintf(filename, "/usr/share/kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename, "rb"); ++ if(fp == NULL) ++ { ++ CLog::Log(LOGDEBUG, "Unable to open file %s", filename); ++ goto drop_out; ++ } ++ } ++ ++ if(readpng_init(fp, &m_pattern[i].w, &m_pattern[i].h) != 0) ++ { ++ CLog::Log(LOGERROR, "Unable to parse png files %s", filename); ++ goto drop_out; ++ } ++ ++ m_pattern[i].img = readpng_get_image(1.0, &channels, &m_pattern[i].rowbytes); ++ if(m_pattern[i].img == NULL || channels != 4) ++ { ++ CLog::Log(LOGERROR, "Invalid png %s, width = %lu, height = %lu, channels = %d, rowbytes = %lu", ++ filename, m_pattern[i].w, m_pattern[i].h, channels, m_pattern[i].rowbytes); ++ goto drop_out; ++ } ++ ++ CLog::Log(LOGDEBUG, "Opened %s: (%lu x %lu)", filename, m_pattern[i].w, m_pattern[i].h); ++ ++drop_out: ++ if(fp) ++ fclose(fp); ++ ++ } ++ } ++ ++ void play_pattern(int pat) ++ { ++ int fd = open("/dev/ws2812", O_WRONLY, 0); ++ if(fd < 0) ++ { ++ CLog::Log(LOGERROR, "Unable to open /dev/ws2812"); ++ } ++ else ++ { ++ if(pat < PAT_NONE && m_pattern[pat].img != NULL) ++ { ++ CLog::Log(LOGDEBUG, "playing pattern"); ++ g_pattern_playing = 1; ++ do ++ { ++ unsigned char * p_line = m_pattern[pat].img; ++ unsigned int i; ++ ++ for(i = 0; i < m_pattern[pat].h; i++) ++ { ++ write(fd, p_line, m_pattern[pat].w * 4); ++ if(m_pattern[pat].w == 26) ++ { ++ int *p = (int *) (p_line + (25 * 4)); ++ usleep(*p); ++ } ++ else ++ { ++ usleep(g_speed); ++ } ++ p_line += m_pattern[pat].rowbytes; ++ // If we get the g_halt signal then stop repeating ++ // the pattern ++ if(g_halt) ++ { ++ g_halt = 0; ++ g_repeat = 0; ++ break; ++ } ++ } ++ p_line += m_pattern[pat].rowbytes; ++ } ++ while(g_repeat); ++ g_pattern_playing = 0; ++ ++ if(pat != PAT_QUIT) ++ write(fd, zeroes, sizeof(zeroes)); ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG, "No img for LED pattern %d", pat); ++ } ++ close(fd); ++ } ++ } ++ ++public: ++ CLedPattern(CEvent *ev) ++ { ++ CLog::Log(LOGDEBUG, "Initialising CLedPattern"); ++ open_patterns(); ++ m_ev = ev; ++ } ++ ++ void Run() ++ { ++ m_going = 1; ++ while(m_going) ++ { ++ m_ev->Wait(); ++ CLog::Log(LOGDEBUG, "Led Pattern %d triggered", g_pattern); ++ play_pattern(g_pattern); ++ } ++ } ++ ++ void Stop() ++ { ++ m_going = 0; ++ m_ev->Set(); ++ } ++}; ++ + CGUIWindowHome::CGUIWindowHome(void) : CGUIWindow(WINDOW_HOME, "Home.xml"), + m_recentlyAddedRunning(false), + m_cumulativeUpdateFlag(0) +@@ -40,6 +276,14 @@ CGUIWindowHome::CGUIWindowHome(void) : C + m_updateRA = (Audio | Video | Totals); + m_loadType = KEEP_IN_MEMORY; + ++ m_ledevent = new CEvent(); ++ m_ledthread = new CThread(new CLedPattern(m_ledevent), "LedThread"); ++ m_ledthread->Create(); ++ g_pattern = PAT_STARTUP; ++ g_speed = 30000; ++ g_repeat = 0; ++ m_ledevent->Set(); ++ + CAnnouncementManager::GetInstance().AddAnnouncer(this); + } + +@@ -75,10 +319,49 @@ void CGUIWindowHome::OnInitWindow() + + void CGUIWindowHome::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) + { ++ unsigned int i; + int ra_flag = 0; + + CLog::Log(LOGDEBUG, "GOT ANNOUNCEMENT, type: %i, from %s, message %s",(int)flag, sender, message); + ++ for(i = 0; i < sizeof(led_actions)/sizeof(led_actions[0]); i++) ++ { ++ if(strcmp(message, led_actions[i].event_name) == 0) ++ { ++ switch(led_actions[i].action) { ++ case ACTION_DO: ++ case ACTION_REPEAT: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = (led_actions[i].action == ACTION_DO) ? 0 : 1; ++ g_speed = 30000; ++ g_pattern = (int) led_actions[i].action_data; ++ m_ledevent->Set(); ++ break; ++ } ++ case ACTION_FN: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = 0; ++ g_speed = 30000; ++ led_actions[i].action_fn(message, data); ++ m_ledevent->Set(); ++ break; ++ } ++ default: ++ { ++ CLog::Log(LOGERROR, "Failed to execute LED action %d for event %s\n", i, led_actions[i].event_name); ++ } ++ } ++ } ++ } ++ + // we are only interested in library changes + if ((flag & (VideoLibrary | AudioLibrary)) == 0) + return; +--- a/xbmc/windows/GUIWindowHome.h 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.h 2016-10-01 19:34:18.585113811 +0100 +@@ -23,6 +23,8 @@ + #include "guilib/GUIWindow.h" + #include "interfaces/IAnnouncer.h" + #include "utils/Job.h" ++#include "threads/Thread.h" ++#include "threads/Event.h" + + class CVariant; + +@@ -47,4 +49,7 @@ + + bool m_recentlyAddedRunning; + int m_cumulativeUpdateFlag; ++ ++ CThread *m_ledthread; ++ CEvent *m_ledevent; + }; +--- a/xbmc/windows/readpng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.c 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,274 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.c ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#include ++#include ++ ++#include "png.h" /* libpng header; includes zlib.h */ ++#include "readpng.h" /* typedefs, common macros, public prototypes */ ++ ++ ++static png_structp png_ptr = NULL; ++static png_infop info_ptr = NULL; ++ ++png_uint_32 width, height; ++int bit_depth, color_type; ++uch *image_data = NULL; ++ ++ ++void readpng_version_info(void) ++{ ++ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", ++ PNG_LIBPNG_VER_STRING, png_libpng_ver); ++} ++ ++ ++/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) ++{ ++ uch sig[8]; ++ ++ ++ /* first do a quick check that the file really is a PNG image; could ++ * have used slightly more general png_sig_cmp() function instead */ ++ ++ fread(sig, 1, 8, infile); ++ if(png_sig_cmp(sig, 0, 8)) ++ return 1; /* bad signature */ ++ ++ ++ /* could pass pointers to user-defined error handlers instead of NULLs: */ ++ ++ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ++ if (!png_ptr) ++ return 4; /* out of memory */ ++ ++ info_ptr = png_create_info_struct(png_ptr); ++ if (!info_ptr) { ++ png_destroy_read_struct(&png_ptr, NULL, NULL); ++ return 4; /* out of memory */ ++ } ++ ++ ++ /* we could create a second info struct here (end_info), but it's only ++ * useful if we want to keep pre- and post-IDAT chunk info separated ++ * (mainly for PNG-aware image editors and converters) */ ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ png_init_io(png_ptr, infile); ++ png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ ++ ++ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ ++ ++ ++ /* alternatively, could make separate calls to png_get_image_width(), ++ * etc., but want bit_depth and color_type for later [don't care about ++ * compression_type and filter_type => NULLs] */ ++ ++ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, ++ NULL, NULL, NULL); ++ *pWidth = width; ++ *pHeight = height; ++ ++ ++ /* OK, that's all we need for now; return happy */ ++ ++ return 0; ++} ++ ++ ++ ++ ++/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; ++ * scales values to 8-bit if necessary */ ++ ++int readpng_get_bgcolor(uch *red, uch *green, uch *blue) ++{ ++ png_color_16p pBackground; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) ++ return 1; ++ ++ /* it is not obvious from the libpng documentation, but this function ++ * takes a pointer to a pointer, and it always returns valid red, green ++ * and blue values, regardless of color_type: */ ++ ++ png_get_bKGD(png_ptr, info_ptr, &pBackground); ++ ++ ++ /* however, it always returns the raw bKGD data, regardless of any ++ * bit-depth transformations, so check depth and adjust if necessary */ ++ ++ if (bit_depth == 16) { ++ *red = pBackground->red >> 8; ++ *green = pBackground->green >> 8; ++ *blue = pBackground->blue >> 8; ++ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { ++ if (bit_depth == 1) ++ *red = *green = *blue = pBackground->gray? 255 : 0; ++ else if (bit_depth == 2) ++ *red = *green = *blue = (255/3) * pBackground->gray; ++ else /* bit_depth == 4 */ ++ *red = *green = *blue = (255/15) * pBackground->gray; ++ } else { ++ *red = (uch)pBackground->red; ++ *green = (uch)pBackground->green; ++ *blue = (uch)pBackground->blue; ++ } ++ ++ return 0; ++} ++ ++ ++ ++ ++/* display_exponent == LUT_exponent * CRT_exponent */ ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) ++{ ++ double gamma; ++ png_uint_32 i, rowbytes; ++ png_bytepp row_pointers = NULL; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ ++ ++ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, ++ * transparency chunks to full alpha channel; strip 16-bit-per-sample ++ * images to 8 bits per sample; and convert grayscale to RGB[A] */ ++ ++ if (color_type == PNG_COLOR_TYPE_PALETTE) ++ png_set_expand(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) ++ png_set_expand(png_ptr); ++ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) ++ png_set_expand(png_ptr); ++ if (bit_depth == 16) ++ png_set_strip_16(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY || ++ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ++ png_set_gray_to_rgb(png_ptr); ++ ++ ++ /* unlike the example in the libpng documentation, we have *no* idea where ++ * this file may have come from--so if it doesn't have a file gamma, don't ++ * do any correction ("do no harm") */ ++ ++ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) ++ png_set_gamma(png_ptr, display_exponent, gamma); ++ ++ ++ /* all transformations have been registered; now update info_ptr data, ++ * get rowbytes and channels, and allocate image memory */ ++ ++ png_read_update_info(png_ptr, info_ptr); ++ ++ *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); ++ *pChannels = (int)png_get_channels(png_ptr, info_ptr); ++ ++ if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ free(image_data); ++ image_data = NULL; ++ return NULL; ++ } ++ ++ Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height)); ++ ++ ++ /* set the individual row_pointers to point at the correct offsets */ ++ ++ for (i = 0; i < height; ++i) ++ row_pointers[i] = image_data + i*rowbytes; ++ ++ ++ /* now we can go ahead and just read the whole image */ ++ ++ png_read_image(png_ptr, row_pointers); ++ ++ ++ /* and we're done! (png_read_end() can be omitted if no processing of ++ * post-IDAT text/time/etc. is desired) */ ++ ++ free(row_pointers); ++ row_pointers = NULL; ++ ++ png_read_end(png_ptr, NULL); ++ ++ return image_data; ++} ++ ++ ++void readpng_cleanup(int free_image_data) ++{ ++ if (free_image_data && image_data) { ++ free(image_data); ++ image_data = NULL; ++ } ++ ++ if (png_ptr && info_ptr) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ png_ptr = NULL; ++ info_ptr = NULL; ++ } ++} ++ +--- a/xbmc/windows/readpng.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.h 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,65 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.h ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#ifndef TRUE ++# define TRUE 1 ++# define FALSE 0 ++#endif ++ ++#ifndef MAX ++# define MAX(a,b) ((a) > (b)? (a) : (b)) ++# define MIN(a,b) ((a) < (b)? (a) : (b)) ++#endif ++ ++#ifdef DEBUG ++# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} ++#else ++# define Trace(x) ; ++#endif ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++ ++/* prototypes for public functions in readpng.c */ ++ ++void readpng_version_info(void); ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); ++ ++int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ++ ulg *pRowbytes); ++ ++void readpng_cleanup(int free_image_data); ++ diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch new file mode 100644 index 0000000000..839cdaeee1 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch @@ -0,0 +1,18 @@ +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-09-17 16:35:20.000000000 +0100 ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-10-01 19:26:40.470553260 +0100 +@@ -527,6 +527,7 @@ + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); + ++#if 0 + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); + m_info.m_streamTypes.clear(); +@@ -548,6 +549,7 @@ + + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); ++#endif + + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch new file mode 100644 index 0000000000..05158c998a --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch @@ -0,0 +1,22 @@ +--- a/system/keymaps/keyboard.xml 2016-09-17 16:35:20.000000000 +0100 ++++ b/system/keymaps/keyboard.xml 2016-10-01 19:31:07.928719606 +0100 +@@ -56,7 +56,7 @@ + Menu + ContextMenu + Menu +- Pause ++ PlayPause + Stop + SkipNext + SkipPrevious +@@ -321,8 +321,8 @@ + NextSubtitle + StepBack + StepForward +- ChapterOrBigStepForward +- ChapterOrBigStepBack ++ VolumeUp ++ VolumeDown + AudioNextLanguage + NextSubtitle + AudioDelay diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch new file mode 100644 index 0000000000..81e238bd44 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch @@ -0,0 +1,31 @@ +diff --git a/xbmc/windows/CMakeLists.txt b/xbmc/windows/CMakeLists.txt +index 3700602..c75f78f 100644 +--- a/xbmc/windows/CMakeLists.txt ++++ b/xbmc/windows/CMakeLists.txt +@@ -1,3 +1,5 @@ ++find_package(PNG REQUIRED) ++ + set(SOURCES GUIMediaWindow.cpp + GUIWindowDebugInfo.cpp + GUIWindowFileManager.cpp +@@ -9,7 +11,8 @@ set(SOURCES GUIMediaWindow.cpp + GUIWindowSplash.cpp + GUIWindowStartup.cpp + GUIWindowSystemInfo.cpp +- GUIWindowWeather.cpp) ++ GUIWindowWeather.cpp ++ readpng.c) + + set(HEADERS GUIMediaWindow.h + GUIWindowDebugInfo.h +@@ -22,6 +25,9 @@ set(HEADERS GUIMediaWindow.h + GUIWindowSplash.h + GUIWindowStartup.h + GUIWindowSystemInfo.h +- GUIWindowWeather.h) ++ GUIWindowWeather.h ++ readpng.h) + + core_add_library(windows) ++ ++target_link_libraries(windows PRIVATE ${PNG_LIBRARIES})