diff --git a/config/functions b/config/functions
index e0263de80c..371755f2f0 100644
--- a/config/functions
+++ b/config/functions
@@ -329,7 +329,7 @@ dashes="==========================="
linux_config_dir="$PROJECT_DIR/$PROJECT/linux"
fi
- if [ ! -f $linux_config_dir/linux.$TARGET_ARCH.conf ] &&
+ if [ ! -e $linux_config_dir/linux.$TARGET_ARCH.conf ] &&
! ls $linux_config_dir/*/linux.$TARGET_ARCH.conf &>/dev/null; then
check_arch="$check_arch\n $dashes$dashes$dashes"
check_arch="$check_arch\n ERROR: Architecture not found, use a valid Architecture"
diff --git a/packages/linux/package.mk b/packages/linux/package.mk
index 4cb15c585c..98c1cfcee0 100644
--- a/packages/linux/package.mk
+++ b/packages/linux/package.mk
@@ -139,6 +139,10 @@ post_patch() {
sed -i -e "s|CONFIG_MXC_HDMI_CEC_SR=y||" $PKG_BUILD/.config
fi
fi
+
+ # install extra dts files
+ cp -v projects/$PROJECT/devices/$DEVICE/config/*-overlay.dts $PKG_BUILD/arch/$TARGET_KERNEL_ARCH/boot/dts/overlays/ || :
+ cp -v projects/$PROJECT/devices/$DEVICE/config/dt-blob.dts $PKG_BUILD/arch/$TARGET_KERNEL_ARCH/boot/dts/ || :
}
makeinstall_host() {
diff --git a/packages/mediacenter/kodi/package.mk b/packages/mediacenter/kodi/package.mk
index 49aa9cbb61..51ac987201 100644
--- a/packages/mediacenter/kodi/package.mk
+++ b/packages/mediacenter/kodi/package.mk
@@ -186,6 +186,10 @@ else
KODI_ARCH="-DWITH_ARCH=$TARGET_ARCH"
fi
+if [ "$DEVICE" = "Slice" -o "$DEVICE" = "Slice3" ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET led_tools"
+fi
+
if [ ! "$KODIPLAYER_DRIVER" = default ]; then
PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $KODIPLAYER_DRIVER"
if [ "$KODIPLAYER_DRIVER" = bcm2835-driver ]; then
diff --git a/packages/tools/bcm2835-bootloader/package.mk b/packages/tools/bcm2835-bootloader/package.mk
index 091a080cb9..0e626af741 100644
--- a/packages/tools/bcm2835-bootloader/package.mk
+++ b/packages/tools/bcm2835-bootloader/package.mk
@@ -31,10 +31,7 @@ PKG_IS_ADDON="no"
PKG_AUTORECONF="no"
make_target() {
- if [ -f $DISTRO_DIR/$DISTRO/config/dt-blob.dts ]; then
- echo Compiling device tree blob
- $(kernel_path)/scripts/dtc/dtc -O dtb -o dt-blob.bin $DISTRO_DIR/$DISTRO/config/dt-blob.dts
- fi
+ :
}
makeinstall_target() {
@@ -43,17 +40,28 @@ makeinstall_target() {
cp -PRv bootcode.bin $INSTALL/usr/share/bootloader
cp -PRv fixup_x.dat $INSTALL/usr/share/bootloader/fixup.dat
cp -PRv start_x.elf $INSTALL/usr/share/bootloader/start.elf
- [ -f dt-blob.bin ] && cp -PRv dt-blob.bin $INSTALL/usr/share/bootloader/dt-blob.bin
+
+ if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin ]; then
+ cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin $INSTALL/usr/share/bootloader
+ fi
cp -PRv $PKG_DIR/scripts/update.sh $INSTALL/usr/share/bootloader
- if [ -f $DISTRO_DIR/$DISTRO/config/distroconfig.txt ]; then
+ if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/distroconfig.txt ]; then
+ cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/distroconfig.txt $INSTALL/usr/share/bootloader
+ elif [ -f $PROJECT_DIR/$PROJECT/config/distroconfig.txt ]; then
+ cp -PRv $PROJECT_DIR/$PROJECT/config/distroconfig.txt $INSTALL/usr/share/bootloader
+ elif [ -f $DISTRO_DIR/$DISTRO/config/distroconfig.txt ]; then
cp -PRv $DISTRO_DIR/$DISTRO/config/distroconfig.txt $INSTALL/usr/share/bootloader
else
cp -PRv $PKG_DIR/files/3rdparty/bootloader/distroconfig.txt $INSTALL/usr/share/bootloader
fi
- if [ -f $DISTRO_DIR/$DISTRO/config/config.txt ]; then
+ if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/config.txt ]; then
+ cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/config.txt $INSTALL/usr/share/bootloader
+ elif [ -f $PROJECT_DIR/$PROJECT/config/config.txt ]; then
+ cp -PRv $PROJECT_DIR/$PROJECT/config/config.txt $INSTALL/usr/share/bootloader
+ elif [ -f $DISTRO_DIR/$DISTRO/config/config.txt ]; then
cp -PRv $DISTRO_DIR/$DISTRO/config/config.txt $INSTALL/usr/share/bootloader
else
cp -PRv $PKG_DIR/files/3rdparty/bootloader/config.txt $INSTALL/usr/share/bootloader
diff --git a/packages/tools/bcm2835-bootloader/release b/packages/tools/bcm2835-bootloader/release
index 577d4b473b..5170fa409f 100755
--- a/packages/tools/bcm2835-bootloader/release
+++ b/packages/tools/bcm2835-bootloader/release
@@ -25,8 +25,15 @@ mkdir -p $RELEASE_DIR/3rdparty/bootloader
cp -PR $BUILD/bcm2835-bootloader-*/bootcode.bin $RELEASE_DIR/3rdparty/bootloader/
cp -PR $BUILD/bcm2835-bootloader-*/fixup_x.dat $RELEASE_DIR/3rdparty/bootloader/fixup.dat
cp -PR $BUILD/bcm2835-bootloader-*/start_x.elf $RELEASE_DIR/3rdparty/bootloader/start.elf
- [ -f $BUILD/bcm2835-bootloader-*/dt-blob.bin ] && cp -PR $BUILD/bcm2835-bootloader-*/dt-blob.bin $RELEASE_DIR/3rdparty/bootloader/
+ if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin ]; then
+ cp -PR $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin $RELEASE_DIR/3rdparty/bootloader/
+ fi
cp -PR $INSTALL/usr/share/bootloader/*.dtb $RELEASE_DIR/3rdparty/bootloader/
cp -PR $INSTALL/usr/share/bootloader/overlays $RELEASE_DIR/3rdparty/bootloader/
- cp -PR $INSTALL/usr/share/bootloader/config.txt $RELEASE_DIR/3rdparty/bootloader/
- cp -PR $INSTALL/usr/share/bootloader/distroconfig.txt $RELEASE_DIR/3rdparty/bootloader/
+
+ if [ -f $INSTALL/usr/share/bootloader/config.txt ]; then
+ cp -PR $INSTALL/usr/share/bootloader/config.txt $RELEASE_DIR/3rdparty/bootloader/
+ fi
+ if [ -f $INSTALL/usr/share/bootloader/distroconfig.txt ]; then
+ cp -PR $INSTALL/usr/share/bootloader/distroconfig.txt $RELEASE_DIR/3rdparty/bootloader/
+ fi
diff --git a/packages/tools/led_tools/media/ledpatterns/ffwd.png b/packages/tools/led_tools/media/ledpatterns/ffwd.png
new file mode 100644
index 0000000000..5bee66fb5c
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/ffwd.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/pause.png b/packages/tools/led_tools/media/ledpatterns/pause.png
new file mode 100644
index 0000000000..60a480f104
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/pause.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/play.png b/packages/tools/led_tools/media/ledpatterns/play.png
new file mode 100644
index 0000000000..ae89019328
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/play.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/quit.png b/packages/tools/led_tools/media/ledpatterns/quit.png
new file mode 100644
index 0000000000..667ada77e6
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/quit.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/rew.png b/packages/tools/led_tools/media/ledpatterns/rew.png
new file mode 100644
index 0000000000..0420bee290
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/rew.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/shutdown.png b/packages/tools/led_tools/media/ledpatterns/shutdown.png
new file mode 100644
index 0000000000..d4fde7ee7b
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/shutdown.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/skipf.png b/packages/tools/led_tools/media/ledpatterns/skipf.png
new file mode 100644
index 0000000000..2018e325eb
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/skipf.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/skipr.png b/packages/tools/led_tools/media/ledpatterns/skipr.png
new file mode 100644
index 0000000000..9292082b82
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/skipr.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/sleep.png b/packages/tools/led_tools/media/ledpatterns/sleep.png
new file mode 100644
index 0000000000..3cef539d53
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/sleep.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/startup.png b/packages/tools/led_tools/media/ledpatterns/startup.png
new file mode 100644
index 0000000000..282954b4a8
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/startup.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/stop.png b/packages/tools/led_tools/media/ledpatterns/stop.png
new file mode 100644
index 0000000000..e02589b813
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/stop.png differ
diff --git a/packages/tools/led_tools/media/ledpatterns/wake.png b/packages/tools/led_tools/media/ledpatterns/wake.png
new file mode 100644
index 0000000000..31944073b0
Binary files /dev/null and b/packages/tools/led_tools/media/ledpatterns/wake.png differ
diff --git a/packages/tools/led_tools/package.mk b/packages/tools/led_tools/package.mk
new file mode 100644
index 0000000000..6b786ed52f
--- /dev/null
+++ b/packages/tools/led_tools/package.mk
@@ -0,0 +1,46 @@
+###############################################################################
+# This file is part of LibreELEC - https://LibreELEC.tv
+# Copyright (C) 2014 Gordon Hollingworth (gordon@fiveninjas.com)
+#
+# 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 .
+################################################################################
+
+PKG_NAME="led_tools"
+PKG_VERSION="0.1"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="http://www.fiveninjas.com"
+PKG_URL="http://updates.fiveninjas.com/src/$PKG_NAME-$PKG_VERSION.tar.gz"
+PKG_DEPENDS_TARGET="toolchain zlib libpng"
+PKG_DEPENDS_HOST="toolchain"
+PKG_SECTION="tools"
+PKG_SHORTDESC="led_tools"
+PKG_LONGDESC="LED tools, these are a set of tools to control the LEDs on Slice"
+
+PKG_IS_ADDON="no"
+PKG_AUTORECONF="no"
+
+make_target() {
+ make CC="$CC" \
+ CFLAGS="$CFLAGS" \
+ LDFLAGS="$LDFLAGS"
+}
+
+makeinstall_target() {
+ mkdir -p $INSTALL/usr/bin
+ cp led_png $INSTALL/usr/bin
+
+ mkdir -p $INSTALL/usr/share/kodi/
+ cp -r $PKG_DIR/media $INSTALL/usr/share/kodi/
+}
diff --git a/projects/RPi/devices/RPi/linux/linux.arm.conf b/projects/RPi/devices/RPi/linux/linux.arm.conf
index b614eb0f7b..0aa3c9001c 100644
--- a/projects/RPi/devices/RPi/linux/linux.arm.conf
+++ b/projects/RPi/devices/RPi/linux/linux.arm.conf
@@ -1071,6 +1071,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
@@ -2802,6 +2803,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
@@ -2855,7 +2857,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/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/Slice/config/distroconfig.txt b/projects/RPi/devices/Slice/config/distroconfig.txt
new file mode 100644
index 0000000000..aa3604e820
--- /dev/null
+++ b/projects/RPi/devices/Slice/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
+
diff --git a/projects/RPi/devices/Slice/config/dt-blob.bin b/projects/RPi/devices/Slice/config/dt-blob.bin
new file mode 100644
index 0000000000..f4f373db20
Binary files /dev/null and b/projects/RPi/devices/Slice/config/dt-blob.bin differ
diff --git a/projects/RPi/devices/Slice/config/dt-blob.dts b/projects/RPi/devices/Slice/config/dt-blob.dts
new file mode 100644
index 0000000000..443b31b7c8
--- /dev/null
+++ b/projects/RPi/devices/Slice/config/dt-blob.dts
@@ -0,0 +1,92 @@
+/dts-v1/;
+
+/ {
+ videocore {
+
+ pins_cm {
+
+ 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 = "no_pulling"; drive_strength_mA = <8>; polarity = "active_high"; }; // HPD_N
+ pin@p47 { function = "output"; termination = "no_pulling"; drive_strength_mA = <8>; polarity = "active_low"; startup_state = "active"; }; // EMMC_DISABLE_N CONTROL
+ 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_config
+
+ pin_defines {
+ pin_define@HDMI_CONTROL_ATTACHED { type = "internal"; number = <46>; }; // HPD_N on GPIO46
+ pin_define@LAN_RUN { type = "internal"; number = <41>; }; // LAN_RUN
+ }; // 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/Slice/config/slice-overlay.dts b/projects/RPi/devices/Slice/config/slice-overlay.dts
new file mode 100644
index 0000000000..7f0a4d2f3b
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/config/ws2812-overlay.dts b/projects/RPi/devices/Slice/config/ws2812-overlay.dts
new file mode 100644
index 0000000000..42cde9d73b
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/filesystem/usr/config/autostart.sh b/projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh
new file mode 100644
index 0000000000..0b6166972b
--- /dev/null
+++ b/projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+hdparm -S60 /dev/sda
diff --git a/projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh b/projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh
new file mode 100644
index 0000000000..ebd32374e6
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf b/projects/RPi/devices/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf
new file mode 100644
index 0000000000..298f43d8e7
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/linux/linux.arm.conf b/projects/RPi/devices/Slice/linux/linux.arm.conf
new file mode 120000
index 0000000000..15e9a3933d
--- /dev/null
+++ b/projects/RPi/devices/Slice/linux/linux.arm.conf
@@ -0,0 +1 @@
+../../RPi/linux/linux.arm.conf
\ No newline at end of file
diff --git a/projects/RPi/devices/Slice/options b/projects/RPi/devices/Slice/options
new file mode 100644
index 0000000000..a2566ab649
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/patches/kodi/kodi-002-slice-led.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-002-slice-led.patch
new file mode 100644
index 0000000000..6ba4cfb403
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/patches/kodi/kodi-003-slice-audio.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-003-slice-audio.patch
new file mode 100644
index 0000000000..839cdaeee1
--- /dev/null
+++ b/projects/RPi/devices/Slice/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/Slice/patches/kodi/kodi-004-keyboard.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-004-keyboard.patch
new file mode 100644
index 0000000000..05158c998a
--- /dev/null
+++ b/projects/RPi/devices/Slice/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 @@
+
+ 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/Slice/patches/kodi/kodi-005-cmake.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-005-cmake.patch
new file mode 100644
index 0000000000..81e238bd44
--- /dev/null
+++ b/projects/RPi/devices/Slice/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})
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 0000000000..6958aae394
Binary files /dev/null and b/projects/RPi/devices/Slice3/config/dt-blob.bin differ
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 @@
+
+ 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})
diff --git a/projects/RPi/options b/projects/RPi/options
index a4248b565d..0e2ee8d762 100644
--- a/projects/RPi/options
+++ b/projects/RPi/options
@@ -18,9 +18,9 @@
# arm1176jz-s arm1176jzf-s cortex-a8 cortex-a9 cortex-r4
# cortex-r4f cortex-m3 cortex-m1 xscale iwmmxt iwmmxt2 ep9312.
- if [ "$DEVICE" = "RPi" ]; then
+ if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then
TARGET_CPU="arm1176jzf-s"
- elif [ "$DEVICE" = "RPi2" ]; then
+ elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then
TARGET_CPU="cortex-a7"
fi
@@ -36,9 +36,9 @@
# vfpv3xd vfpv3xd-fp16 neon neon-fp16 vfpv4 vfpv4-d16 fpv4-sp-d16
# neon-vfpv4.
- if [ "$DEVICE" = "RPi" ]; then
+ if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then
TARGET_FPU="vfp"
- elif [ "$DEVICE" = "RPi2" ]; then
+ elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then
TARGET_FPU="neon-vfpv4"
fi
@@ -70,7 +70,7 @@
# default: default mainline kernel
LINUX="default"
-if [ "$DEVICE" = "RPi" ]; then
+if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then
# NOOBS supported hex versions (legacy)
NOOBS_HEX="2,3,4,5,6,7,8,9,d,e,f,10,11,12,14,19,0092,0093"
@@ -78,7 +78,7 @@ if [ "$DEVICE" = "RPi" ]; then
# NOOBS supported model versions
NOOBS_SUPPORTED_MODELS='"Pi Model","Pi Compute Module","Pi Zero"'
-elif [ "$DEVICE" = "RPi2" ]; then
+elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then
# NOOBS supported hex versions (legacy)
NOOBS_HEX="1040,1041,2082"
diff --git a/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch b/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch
new file mode 100644
index 0000000000..e30677018d
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch
@@ -0,0 +1,12 @@
+--- a/drivers/misc/Kconfig 2016-10-01 08:57:18.219952947 +0100
++++ b/drivers/misc/Kconfig 2016-10-01 09:18:14.792293152 +0100
+@@ -4,6 +4,9 @@
+
+ menu "Misc devices"
+
++config BCM2835_WS2812
++ tristate "Support DMA user access to WS2812 LEDs"
++
+ config SENSORS_LIS3LV02D
+ tristate
+ depends on INPUT
diff --git a/projects/RPi/patches/linux/linux-02-misc-Makefile.patch b/projects/RPi/patches/linux/linux-02-misc-Makefile.patch
new file mode 100644
index 0000000000..f4ad6286bd
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-02-misc-Makefile.patch
@@ -0,0 +1,10 @@
+--- a/drivers/misc/Makefile 2016-10-01 09:14:16.810942127 +0100
++++ b/drivers/misc/Makefile 2016-10-01 09:14:05.458686888 +0100
+@@ -2,6 +2,7 @@
+ # Makefile for misc devices that really don't fit anywhere else.
+ #
+
++obj-$(CONFIG_BCM2835_WS2812) += ws2812.o
+ obj-$(CONFIG_IBM_ASM) += ibmasm/
+ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
+ obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
diff --git a/projects/RPi/patches/linux/linux-03-ws2807-c.patch b/projects/RPi/patches/linux/linux-03-ws2807-c.patch
new file mode 100644
index 0000000000..24eedd81ae
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-03-ws2807-c.patch
@@ -0,0 +1,539 @@
+--- a/drivers/misc/ws2812.c 2016-08-17 21:00:22.264000134 +0100
++++ b/drivers/misc/ws2812.c 2016-10-04 14:12:32.512699063 +0100
+@@ -0,0 +1,536 @@
++/*
++ * Raspberry Pi WS2812 PWM driver
++ *
++ * Written by: Gordon Hollingworth
++ * Based on DMA PWM driver from Jonathan Bell
++ *
++ * Copyright (C) 2014 Raspberry Pi Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * To use this driver you need to make sure that the PWM clock is set to 2.4MHz
++ * and the correct PWM0 output is connected. The best way to do this is to
++ * create a dt-blob.bin on your RaspberryPi, start by downloading the default
++ * dt-blob.dts from
++ *
++ * Note, this uses the same PWM hardware as the standard audio output on the Pi
++ * so you cannot use both simultaneously.
++ *
++ * http://www.raspberrypi.org/documentation/configuration/pin-configuration.md
++ *
++ * (Copy the bit from /dts-v1/; through to the end... This will contain the pin
++ * configuration for all the Raspberry Pi versions (since they are different.
++ * You can get rid of the ones you don't care about. Next alter the PWM0 output
++ * you want to use.
++ *
++ * http://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf
++ *
++ * The link above will help understand what the GPIOs can do, check out page 102
++ * You can use: GPIO12, GPIO18 or GPIO40, so for the Slice board we use GPIO40 so
++ * we have the following in the dts file
++ *
++ * pin@p40 {
++ * function = "pwm";
++ * termination = "no_pulling";
++ * };
++ *
++ * And at the bottom of the dts file, although still in the 'videocore' block we
++ * have:
++ *
++ * clock_setup {
++ * clock@PWM { freq = <2400000>; };
++ * };
++ *
++ * To check whether the changes are correct you can use 'vcgencmd measure_clock 25'
++ * This should return the value 2400000
++ *
++ * Also if you use wiringPi then you can do 'gpio readall' to check that the pin
++ * alternate setting is set correctly.
++ *
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++#define DRIVER_NAME "ws2812"
++
++struct ws2812_state {
++ struct device * dev;
++ struct cdev cdev;
++ struct class * cl;
++ struct dma_chan * dma_chan;
++ dma_addr_t dma_addr;
++
++ void __iomem * ioaddr;
++ phys_addr_t phys_addr;
++
++ uint8_t * buffer;
++ uint32_t * pixbuf;
++
++ struct gpio_desc * led_en;
++
++ unsigned char brightness;
++ u32 invert;
++ u32 num_leds;
++};
++
++#ifndef BCM2708_PERI_BASE
++ #define BCM2708_PERI_BASE 0x20000000
++#endif
++
++#define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE)
++
++/* Each LED is controlled with a 24 bit RGB value
++ * each bit is created from a nibble of data either
++ * 1000 or 1110 so to create 24 bits you need 12 bytes
++ * of PWM output
++ */
++#define BYTES_PER_LED 12
++
++// Number of 2.4MHz bits in 50us to create a reset condition
++#define RESET_BYTES ((50 * 24) / 80)
++
++#define PWM_CTL 0x0
++#define PWM_STA 0x4
++#define PWM_DMAC 0x8
++#define PWM_RNG1 0x10
++#define PWM_DAT1 0x14
++#define PWM_FIFO1 0x18
++#define PWM_ID 0x50
++
++#define PWM_DMA_DREQ 5
++
++static dev_t devid = MKDEV(1337, 0);
++
++/*
++** Functions to access the pwm peripheral
++*/
++static void pwm_writel(struct ws2812_state * state, uint32_t val, uint32_t reg)
++{
++ writel(val, state->ioaddr + reg);
++}
++
++#if 0
++static uint32_t pwm_readl(struct ws2812_state * state, uint32_t reg)
++{
++ return readl(state->ioaddr + reg);
++}
++#endif
++
++/* Initialise the PWM module to use serial output
++ * mode
++ */
++static int pwm_init(struct ws2812_state * state)
++{
++ uint32_t reg;
++
++ // serial 32 bits per word
++ pwm_writel(state, 32, PWM_RNG1);
++ // Clear
++ pwm_writel(state, 0, PWM_DAT1);
++
++ reg = (1 << 0) | /* CH1EN */
++ (1 << 1) | /* serialiser */
++ (0 << 2) | /* don't repeat last word */
++ (0 << 3) | /* silence is zero */
++ ((state->invert ? 1 : 0) << 4) | /* polarity */
++ (1 << 5) | /* use fifo */
++ (1 << 6) | /* Clear fifo */
++ (1 << 7) | /* MSEN - Mask space enable */
++ ((state->invert ? 1 : 0) << 11); /* Silence bit = 1 */
++ pwm_writel(state, reg, PWM_CTL);
++ reg = (1 << 31) | /* DMA enabled */
++ (4 << 8) | /* Threshold for panic */
++ (8 << 0); /* Threshold for dreq */
++ pwm_writel(state, reg, PWM_DMAC);
++
++ return 0;
++
++}
++
++/*
++ * DMA callback function, release the mapping and the calling function
++ */
++void ws2812_callback(void * param)
++{
++ struct ws2812_state * state = (struct ws2812_state *) param;
++
++ dma_unmap_single(state->dev, state->dma_addr, state->num_leds * BYTES_PER_LED,
++ DMA_TO_DEVICE);
++
++}
++
++/*
++ * Issue a DMA to the PWM peripheral from the assigned buffer
++ * buffer must be unmapped again before being used
++ */
++int issue_dma(struct ws2812_state * state, uint8_t *buffer, int length)
++{
++ struct dma_async_tx_descriptor *desc;
++
++ state->dma_addr = dma_map_single(state->dev,
++ buffer, length,
++ DMA_TO_DEVICE);
++
++ if(state->dma_addr == 0)
++ {
++ pr_err("Failed to map buffer for DMA\n");
++ return -1;
++ }
++
++ desc = dmaengine_prep_slave_single(state->dma_chan, state->dma_addr,
++ length, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
++ if(desc == NULL)
++ {
++ pr_err("Failed to prep the DMA transfer\n");
++ return -1;
++ }
++
++ desc->callback = ws2812_callback;
++ desc->callback_param = state;
++ dmaengine_submit(desc);
++ dma_async_issue_pending(state->dma_chan);
++
++ return 0;
++}
++
++
++int clear_leds(struct ws2812_state * state)
++{
++ int i;
++
++ for(i = 0; i < state->num_leds * BYTES_PER_LED; i++)
++ state->buffer[i] = 0x88;
++ for(i = 0; i < RESET_BYTES; i++)
++ state->buffer[state->num_leds * BYTES_PER_LED + i] = 0;
++
++ issue_dma(state, state->buffer, state->num_leds * BYTES_PER_LED + RESET_BYTES);
++
++ return 0;
++}
++
++static int ws2812_open(struct inode *inode, struct file *file)
++{
++ struct ws2812_state * state;
++ state = container_of(inode->i_cdev, struct ws2812_state, cdev);
++
++ file->private_data = state;
++
++ return 0;
++}
++
++/* WS2812B gamma correction
++GammaE=255*(res/255).^(1/.45)
++From: http://rgb-123.com/ws2812-color-output/
++*/
++unsigned char gamma_(unsigned char brightness, unsigned char val)
++{
++ int bright = val;
++ unsigned char GammaE[] = {
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
++ 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
++ 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11,
++ 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
++ 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28,
++ 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40,
++ 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54,
++ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
++ 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89,
++ 90, 91, 93, 94, 95, 96, 98, 99,100,102,103,104,106,107,109,110,
++ 111,113,114,116,117,119,120,121,123,124,126,128,129,131,132,134,
++ 135,137,138,140,142,143,145,146,148,150,151,153,155,157,158,160,
++ 162,163,165,167,169,170,172,174,176,178,179,181,183,185,187,189,
++ 191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220,
++ 222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255};
++ bright = (bright * brightness) / 255;
++ return GammaE[bright];
++}
++
++// LED serial output
++// 4 bits make up a single bit of the output
++// 1 1 1 0 -- 1
++// 1 0 0 0 -- 0
++//
++// Plus require a space of 50 microseconds for reset
++// 24 bits per led
++//
++// (24 * 4) / 8 = 12 bytes per led
++//
++// red = 0xff0000 == 0xeeeeeeee 0x88888888 0x88888888
++unsigned char * led_encode(struct ws2812_state * state, int rgb, unsigned char *buf)
++{
++ int i;
++ unsigned char red = gamma_(state->brightness, rgb >> 8);
++ unsigned char blu = gamma_(state->brightness, rgb);
++ unsigned char grn = gamma_(state->brightness, rgb >> 16);
++ int rearrange = red +
++ (blu << 8) +
++ (grn << 16);
++ for(i = 11; i >= 0; i--)
++ {
++ switch(rearrange & 3)
++ {
++ case 0: *buf++ = 0x88; break;
++ case 1: *buf++ = 0x8e; break;
++ case 2: *buf++ = 0xe8; break;
++ case 3: *buf++ = 0xee; break;
++ }
++ rearrange >>= 2;
++ }
++
++ return buf;
++}
++
++
++/* Write to the PWM through DMA
++ * Function to write the RGB buffer to the WS2812 leds, the input buffer
++ * contains a sequence of up to num_leds RGB32 integers, these are then
++ * converted into the nibble per bit sequence required to drive the PWM
++ */
++ssize_t ws2812_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
++{
++ int32_t *p_rgb;
++ int8_t * p_buffer;
++ int i, length, num_leds;
++ struct ws2812_state * state = (struct ws2812_state *) filp->private_data;
++
++ num_leds = min(count/4, state->num_leds);
++
++ if(copy_from_user(state->pixbuf, buf, num_leds * 4))
++ return -EFAULT;
++
++ p_rgb = state->pixbuf;
++ p_buffer = state->buffer;
++ for(i = 0; i < num_leds; i++)
++ p_buffer = led_encode(state, *p_rgb++, p_buffer);
++
++ /* Fill rest with '0' */
++ memset(p_buffer, 0x00, RESET_BYTES);
++
++ length = (int) p_buffer - (int) state->buffer + RESET_BYTES;
++
++ /* Setup DMA engine */
++ issue_dma(state, state->buffer, length);
++
++ return count;
++}
++
++
++struct file_operations ws2812_fops = {
++ .owner = THIS_MODULE,
++ .llseek = NULL,
++ .read = NULL,
++ .write = ws2812_write,
++ .open = ws2812_open,
++ .release = NULL,
++};
++
++/*
++ * Probe function
++ */
++static int ws2812_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node;
++ struct ws2812_state * state;
++ const __be32 *addr;
++ struct resource *res;
++ struct dma_slave_config cfg =
++ {
++ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
++ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
++ .slave_id = PWM_DMA_DREQ,
++ .direction = DMA_MEM_TO_DEV,
++ .src_addr = 0,
++ };
++
++ if(node == NULL)
++ {
++ pr_err("Require device tree entry\n");
++ goto fail;
++ }
++
++ state = kmalloc(sizeof(struct ws2812_state), GFP_KERNEL);
++ if (!state) {
++ pr_err("Can't allocate state\n");
++ goto fail;
++ }
++
++ state->dev = dev;
++ state->brightness = 255;
++
++ // Create character device interface /dev/ws2812
++ if(alloc_chrdev_region(&devid, 0, 1, "ws2812") < 0)
++ {
++ pr_err("Unable to create chrdev region");
++ goto fail_malloc;
++ }
++ if((state->cl = class_create(THIS_MODULE, "ws2812")) == NULL)
++ {
++ unregister_chrdev_region(devid, 1);
++ pr_err("Unable to create class ws2812");
++ goto fail_chrdev;
++ }
++ if(device_create(state->cl, NULL, devid, NULL, "ws2812") == NULL)
++ {
++ class_destroy(state->cl);
++ unregister_chrdev_region(devid, 1);
++ pr_err("Unable to create device ws2812");
++ goto fail_class;
++ }
++
++ state->cdev.owner = THIS_MODULE;
++ cdev_init(&state->cdev, &ws2812_fops);
++
++ if(cdev_add(&state->cdev, devid, 1)) {
++ pr_err("CDEV failed\n");
++ goto fail_device;
++ }
++
++ platform_set_drvdata(pdev, state);
++
++ /* get parameters from device tree */
++ of_property_read_u32(node,
++ "rpi,invert",
++ &state->invert);
++ of_property_read_u32(node,
++ "rpi,num_leds",
++ &state->num_leds);
++
++ state->pixbuf = kmalloc(state->num_leds * sizeof(int), GFP_KERNEL);
++ if(state->pixbuf == NULL)
++ {
++ pr_err("Failed to allocate internal buffer\n");
++ goto fail_cdev;
++ }
++
++ /* base address in dma-space */
++ addr = of_get_address(node, 0, NULL, NULL);
++ if (!addr) {
++ dev_err(dev, "could not get DMA-register address - not using dma mode\n");
++ goto fail_pixbuf;
++ }
++ state->phys_addr = be32_to_cpup(addr);
++ pr_err("bus_addr = 0x%x\n", state->phys_addr);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ state->ioaddr = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(state->ioaddr)) {
++ pr_err("Failed to get register resource\n");
++ goto fail_pixbuf;
++ }
++
++ pr_err("ioaddr = 0x%x\n", (int) state->ioaddr);
++
++ state->buffer = kmalloc(state->num_leds * BYTES_PER_LED + RESET_BYTES, GFP_KERNEL);
++ if(state->buffer == NULL)
++ {
++ pr_err("Failed to allocate internal buffer\n");
++ goto fail_pixbuf;
++ }
++
++ state->dma_chan = dma_request_slave_channel(dev, "pwm_dma");
++ if(state->dma_chan == NULL)
++ {
++ pr_err("Failed to request DMA channel");
++ goto fail_buffer;
++ }
++
++ /* request a DMA channel */
++ cfg.dst_addr = state->phys_addr + PWM_FIFO1;
++ ret = dmaengine_slave_config(state->dma_chan, &cfg);
++ if (state->dma_chan < 0) {
++ pr_err("Can't allocate DMA channel\n");
++ goto fail_dma_init;
++ }
++ pwm_init(state);
++
++ // Enable the LED power
++ state->led_en = devm_gpiod_get(dev, "led-en", GPIOD_OUT_HIGH);
++
++ clear_leds(state);
++
++ return 0;
++fail_dma_init:
++ dma_release_channel(state->dma_chan);
++fail_buffer:
++ kfree(state->buffer);
++fail_pixbuf:
++ kfree(state->pixbuf);
++fail_cdev:
++ cdev_del(&state->cdev);
++fail_device:
++ device_destroy(state->cl, devid);
++fail_class:
++ class_destroy(state->cl);
++fail_chrdev:
++ unregister_chrdev_region(devid, 1);
++fail_malloc:
++ kfree(state);
++fail:
++
++ return -1;
++}
++
++
++static int ws2812_remove(struct platform_device *pdev)
++{
++ struct ws2812_state *state = platform_get_drvdata(pdev);
++
++ platform_set_drvdata(pdev, NULL);
++
++ dma_release_channel(state->dma_chan);
++ kfree(state->buffer);
++ kfree(state->pixbuf);
++ cdev_del(&state->cdev);
++ device_destroy(state->cl, devid);
++ class_destroy(state->cl);
++ unregister_chrdev_region(devid, 1);
++ kfree(state);
++
++ return 0;
++}
++
++static const struct of_device_id ws2812_match[] = {
++ { .compatible = "rpi,ws2812" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ws2812_match);
++
++static struct platform_driver ws2812_driver = {
++ .probe = ws2812_probe,
++ .remove = ws2812_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = ws2812_match,
++ },
++};
++module_platform_driver(ws2812_driver);
++
++MODULE_ALIAS("platform:ws2812");
++MODULE_DESCRIPTION("WS2812 PWM driver");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Gordon Hollingworth");
diff --git a/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch b/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch
new file mode 100644
index 0000000000..da7593ed7e
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch
@@ -0,0 +1,17 @@
+--- a/drivers/rtc/rtc-pcf8523.c 2016-10-01 10:16:30.259771931 +0100
++++ b/drivers/rtc/rtc-pcf8523.c 2016-10-01 10:21:29.762638800 +0100
+@@ -291,7 +291,13 @@ static int pcf8523_probe(struct i2c_clie
+ if (!pcf)
+ return -ENOMEM;
+
+- err = pcf8523_select_capacitance(client, true);
++ if (of_property_read_bool(client->dev.of_node, "nxp,xtalcap-7pf")) {
++ printk(KERN_ERR "PCF8523 - set 7pF crystal load");
++ err = pcf8523_select_capacitance(client, false);
++ } else {
++ printk(KERN_ERR "PCF8523 - set 12pF crystal load");
++ err = pcf8523_select_capacitance(client, true);
++ }
+ if (err < 0)
+ return err;
+
diff --git a/projects/RPi/patches/linux/linux-05-cs4265-c.patch b/projects/RPi/patches/linux/linux-05-cs4265-c.patch
new file mode 100644
index 0000000000..51939528a9
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-05-cs4265-c.patch
@@ -0,0 +1,20 @@
+--- linux-4.4-rc7-old/sound/soc/codecs/cs4265.c 2016-01-13 20:56:05.637652775 +0000
++++ linux-4.4-rc7/sound/soc/codecs/cs4265.c 2016-01-17 11:21:16.977652775 +0000
+@@ -157,7 +157,7 @@
+ SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
+ 3, 1, 0),
+ SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
+- SOC_SINGLE("MMTLR Data Switch", 0,
++ SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
+ 1, 1, 0),
+ SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
+ SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
+@@ -199,8 +199,6 @@
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+- SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0,
+- CS4265_SPDIF_CTL2, 5, 1),
+
+ SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+ SND_SOC_DAPM_OUTPUT("LINEOUTR"),
diff --git a/projects/RPi/patches/linux/linux-06-slice-c.patch b/projects/RPi/patches/linux/linux-06-slice-c.patch
new file mode 100644
index 0000000000..d2263c61bc
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-06-slice-c.patch
@@ -0,0 +1,279 @@
+--- a/sound/soc/bcm/slice.c 1969-12-31 16:00:00.000000000 -0800
++++ b/sound/soc/bcm/slice.c 2017-02-15 14:39:20.402591342 -0800
+@@ -0,0 +1,276 @@
++ /*
++ * ASoC Driver for Slice on-board sound
++ *
++ * Author: James Adams
++ * Based on the HifiBerry DAC driver by Florian Meier
++ * Copyright 2014
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program 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.
++ */
++
++ #include
++ #include
++
++ #include
++ #include
++
++ #include
++ #include
++ #include
++ #include
++ #include
++
++ #include "../codecs/cs4265.h"
++
++struct clk * gp0_clock;
++
++ static int snd_slice_init(struct snd_soc_pcm_runtime *rtd)
++ {
++ return 0;
++ }
++
++ static int snd_slice_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++ {
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ struct snd_soc_codec *codec = rtd->codec;
++ int err;
++ int ret;
++ unsigned int rate = params_rate(params);
++ unsigned int sysclk = 12288000;
++
++ switch (rate) {
++ case 32000:
++ sysclk = 12288000;
++ break;
++ case 44100:
++ sysclk = 11289600;
++ break;
++ case 48000:
++ sysclk = 12288000;
++ break;
++ case 64000:
++ sysclk = 12288000;
++ break;
++ case 88200:
++ sysclk = 11289600;
++ break;
++ case 96000:
++ sysclk = 12288000;
++ break;
++ case 128000:
++ dev_err(codec->dev,
++ "Failed to set CS4265 SYSCLK, sample rate not supported in ALSA: 128000\n");
++ break;
++ case 176400:
++ sysclk = 11289600;
++ break;
++ case 192000:
++ sysclk = 12288000;
++ break;
++ default:
++ dev_err(codec->dev,
++ "Failed to set CS4265 SYSCLK, sample rate not supported\n");
++ break;
++ }
++
++ // Need two frequencies: 12.288 or 11.2896MHz
++ // Source is 1,806,336,000
++ // /4 /40 - 1128960
++ // /7 /21 - 1228800
++ clk_disable_unprepare(gp0_clock);
++
++ err = clk_set_rate(gp0_clock, sysclk);
++ if(err < 0)
++ pr_err("Failed to set clock rate for gp0 clock\n");
++
++ if((ret = clk_prepare_enable(gp0_clock)) < 0)
++ pr_err("Failed to enable clock\n");
++
++ dev_err(codec->dev, "Set sampling frequency %d, using sysclk %d\n", rate, sysclk);
++
++ err = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk,
++ SND_SOC_CLOCK_OUT);
++
++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM);
++
++ if (ret) {
++ dev_err(cpu_dai->dev,
++ "Failed to set the cpu dai format.\n");
++ return ret;
++ }
++
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM);
++ if (ret) {
++ dev_err(cpu_dai->dev,
++ "Failed to set the codec format.\n");
++ return ret;
++ }
++
++ snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++
++ return 0;
++ }
++
++ static int snd_slice_params_fixup(struct snd_soc_pcm_runtime *rtd,
++ struct snd_pcm_hw_params *params)
++ {
++ printk(KERN_ERR "snd_slice_params_fixup called\n");
++ /* force 32 bit */
++ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
++ return 0;
++ }
++
++ /* machine stream operations */
++ static struct snd_soc_ops snd_slice_ops = {
++ .hw_params = snd_slice_hw_params,
++ };
++
++ /* Widgets */
++ static const struct snd_soc_dapm_widget snd_slice_dapm_widgets[] = {
++ SND_SOC_DAPM_SPK("Speaker 1", NULL),
++ SND_SOC_DAPM_SPK("Speaker 2", NULL),
++ SND_SOC_DAPM_MIC("Mic 1", NULL),
++ SND_SOC_DAPM_MIC("Mic 2", NULL),
++ SND_SOC_DAPM_MIC("LineIn 1", NULL),
++ SND_SOC_DAPM_MIC("LineIn 2", NULL),
++ SND_SOC_DAPM_SPK("Spdif", NULL),
++ };
++
++ /* Audio Map */
++ static const struct snd_soc_dapm_route snd_slice_audio_map[] = {
++ {"Speaker 1", NULL, "LINEOUTL"},
++ {"Speaker 2", NULL, "LINEOUTR"},
++ {"MICL", NULL, "Mic 1"},
++ {"MICR", NULL, "Mic 2"},
++ {"LINEINL", NULL, "LineIn 1"},
++ {"LINEINR", NULL, "LineIn 2"},
++ {"Spdif", NULL, "SPDIF"},
++ };
++
++ static const struct snd_soc_pcm_stream snd_slice_params = {
++ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
++ };
++
++ static struct snd_soc_dai_link snd_slice_dai[] = {
++ {
++ .name = "Slice",
++ .stream_name = "Slice HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "cs4265-dai1",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "cs4265.1-004e",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_slice_ops,
++ .init = snd_slice_init,
++ .be_hw_params_fixup = snd_slice_params_fixup,
++ },
++ };
++
++ /* audio machine driver */
++ static struct snd_soc_card snd_slice = {
++ .name = "snd_slice",
++ .dai_link = snd_slice_dai,
++ .num_links = ARRAY_SIZE(snd_slice_dai),
++ .fully_routed = 1,
++ .dapm_widgets = snd_slice_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(snd_slice_dapm_widgets),
++ .dapm_routes = snd_slice_audio_map,
++ .num_dapm_routes = ARRAY_SIZE(snd_slice_audio_map),
++ };
++
++ static int snd_slice_probe(struct platform_device *pdev)
++ {
++ int ret = 0;
++ snd_slice.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_slice_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++ else
++ {
++ printk(KERN_ERR "SLICEAUDIO - ERROR no Device Tree!\n");
++ }
++
++ ret = snd_soc_register_card(&snd_slice);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ goto snd_soc_register_card_failed;
++ }
++
++ gp0_clock = devm_clk_get(&pdev->dev, "gp0");
++ if (IS_ERR(gp0_clock)) {
++ pr_err("Failed to get gp0 clock\n");
++ return PTR_ERR(gp0_clock);
++ }
++
++ ret = clk_set_rate(gp0_clock, 12288000);
++ if (ret) {
++ pr_err("Failed to set the GP0 clock rate\n");
++ return ret;
++ }
++
++ ret = clk_prepare_enable(gp0_clock);
++ if (ret) {
++ pr_err("Failed to turn on gp0 clock: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++
++ snd_soc_register_card_failed:
++
++ return ret;
++ }
++
++ static int snd_slice_remove(struct platform_device *pdev)
++ {
++ return snd_soc_unregister_card(&snd_slice);
++ }
++
++ static const struct of_device_id slice_of_match[] = {
++ { .compatible = "fiveninjas,slice", },
++ {},
++ };
++ MODULE_DEVICE_TABLE(of, slice_of_match);
++
++ static struct platform_driver snd_slice_driver = {
++ .driver = {
++ .name = "snd-slice",
++ .owner = THIS_MODULE,
++ .of_match_table = slice_of_match,
++ },
++ .probe = snd_slice_probe,
++ .remove = snd_slice_remove,
++ };
++
++ module_platform_driver(snd_slice_driver);
++
++ MODULE_AUTHOR("James Adams ");
++ MODULE_DESCRIPTION("ASoC Driver for Slice on-board audio");
++ MODULE_LICENSE("GPL v2");
diff --git a/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch b/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch
new file mode 100644
index 0000000000..a51dfde8ca
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch
@@ -0,0 +1,17 @@
+--- a/sound/soc/bcm/Kconfig 2016-10-24 08:46:19.034757161 +0100
++++ b/sound/soc/bcm/Kconfig 2016-10-24 08:52:36.735342726 +0100
+@@ -131,6 +131,13 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC
+ help
+ Say Y or M if you want to add support for Allo Piano DAC.
+
++config SND_BCM2708_SOC_SLICE
++ tristate "Support for Slice on-board sound"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_CS4265
++ help
++ Say Y or M if you want to add support for Slice on-board sound.
++
+ config SND_PISOUND
+ tristate "Support for Blokas Labs pisound"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+
diff --git a/projects/RPi/patches/linux/linux-08-slice-Makefile.patch b/projects/RPi/patches/linux/linux-08-slice-Makefile.patch
new file mode 100644
index 0000000000..b1395c95a6
--- /dev/null
+++ b/projects/RPi/patches/linux/linux-08-slice-Makefile.patch
@@ -0,0 +1,15 @@
+--- a/sound/soc/bcm/Makefile 2016-10-24 08:57:16.805712924 +0100
++++ b/sound/soc/bcm/Makefile 2016-10-24 08:59:51.541235893 +0100
+@@ -26,6 +26,7 @@ snd-soc-digidac1-soundcard-objs := digid
+ snd-soc-dionaudio-loco-objs := dionaudio_loco.o
+ snd-soc-allo-piano-dac-objs := allo-piano-dac.o
+ snd-soc-pisound-objs := pisound.o
++snd-soc-slice-objs := slice.o
+
+ obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+@@ -44,3 +45,4 @@ obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) +=
+ obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
+ obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o
+ obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o
++obj-$(CONFIG_SND_BCM2708_SOC_SLICE) += snd-soc-slice.o