Index: npl/kernel/drbd8/drbd8.SlackBuild
===================================================================
--- npl/kernel/drbd8/drbd8.SlackBuild	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drbd8/drbd8.SlackBuild	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -15,5 +15,5 @@
 
 
-VERSION=8.4.8-1
+VERSION=8.4.11-1
 PKGVERSION=`echo $VERSION| sed 's/-/_/'`
 
Index: npl/kernel/drbd8/drbd8.build
===================================================================
--- npl/kernel/drbd8/drbd8.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drbd8/drbd8.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6551
+6554
Index: npl/kernel/drbd8/drbd8.depver
===================================================================
--- npl/kernel/drbd8/drbd8.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drbd8/drbd8.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,3 +1,3 @@
 linux	0
-linux_src	404072000
+linux_src	409149001
 linux_headers	0
Index: npl/kernel/drbd8/drbd8.md5
===================================================================
--- npl/kernel/drbd8/drbd8.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drbd8/drbd8.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,8 +1,9 @@
 8770e6c2ab88f6e50bac9be1926704f2  ./boot.drbd
+827ec7cc186cc55dfd046f9ee0b13fae  ./drbd-8.4.11-1.tar.gz
 aabd6c255cdf11d341c862ed65c64f53  ./drbd-8.4.7-1.tar.gz
 1e55a2659d0ade21f3ec3c31b8669afc  ./drbd-8.4.8-1.tar.gz
-3b8e87823f28f79f0eb702f5412f76fc  ./drbd8.pkg
-4ddc712a6a2ed9f67d1193fd3f952a23  ./drbd8.SlackBuild
-462bd74f68d21bd91573b1c6acdb362d  ./drbd8.SlackBuild.log.gz
+d0778679aa0290dee0551b7323101077  ./drbd8.pkg
+9eb8ea2f59178e4a616392e9d02be3e0  ./drbd8.SlackBuild
+6622c816481407222a4054b1d5c3bedf  ./drbd8.SlackBuild.log.gz
 7aea41ce9a260371e6b6e5d254b7063b  ./post.drbd
 2e44be0727010c5da61039e63c7a2575  ./services.drbd
Index: npl/kernel/drbd8/drbd8.version
===================================================================
--- npl/kernel/drbd8/drbd8.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drbd8/drbd8.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-8.4.8_1
+8.4.11_1
Index: npl/kernel/drv_dahdi/drv_dahdi.build
===================================================================
--- npl/kernel/drv_dahdi/drv_dahdi.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_dahdi/drv_dahdi.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6552
Index: npl/kernel/drv_dahdi/drv_dahdi.depver
===================================================================
--- npl/kernel/drv_dahdi/drv_dahdi.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_dahdi/drv_dahdi.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,4 +1,4 @@
 linux	0
-linux_src	404072000
+linux_src	409149001
 linux_headers	0
 linux	0
Index: npl/kernel/drv_dahdi/drv_dahdi.md5
===================================================================
--- npl/kernel/drv_dahdi/drv_dahdi.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_dahdi/drv_dahdi.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,7 +1,7 @@
 7ab7b781c0eeba1522c56f49222d2627  ./dahdi
 af96917e15eebc36519948133ec7e36b  ./dahdi-linux-2.11.1.tar.gz
-706ec5bc44fed633e781a156532a24ba  ./drv_dahdi_dev.pkg
-58e21268a03f68860ddb7ba5fc99169e  ./drv_dahdi.pkg
+cf52345b4c6a58467ab7d6c4a9321060  ./drv_dahdi_dev.pkg
+b9eb5d69984cdb6680fd2228ec2250f7  ./drv_dahdi.pkg
 8aeaed44b83e1ed8f56a6981afad6898  ./drv_dahdi.SlackBuild
-6b74c7feeb01041443cc565898686740  ./drv_dahdi.SlackBuild.log.gz
+1ba75c214384109033c946f0cf32d57a  ./drv_dahdi.SlackBuild.log.gz
 b5476f7778add5f5e85a4c898da3ba49  ./post.dahdi
Index: npl/kernel/drv_dahdi/drv_dahdi_dev.build
===================================================================
--- npl/kernel/drv_dahdi/drv_dahdi_dev.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_dahdi/drv_dahdi_dev.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6552
Index: npl/kernel/drv_e1000e/drv_e1000e.SlackBuild
===================================================================
--- npl/kernel/drv_e1000e/drv_e1000e.SlackBuild	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_e1000e/drv_e1000e.SlackBuild	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -10,5 +10,5 @@
 mkdir $TMP
 
-VERSION=3.3.4
+VERSION=3.4.2.1
 ARCH=${ARCH:-i486}
 
Index: npl/kernel/drv_e1000e/drv_e1000e.build
===================================================================
--- npl/kernel/drv_e1000e/drv_e1000e.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_e1000e/drv_e1000e.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6553
Index: npl/kernel/drv_e1000e/drv_e1000e.depver
===================================================================
--- npl/kernel/drv_e1000e/drv_e1000e.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_e1000e/drv_e1000e.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,3 +1,3 @@
-linux_src	404072000
+linux_src	409149001
 linux_headers	0
 linux	0
Index: npl/kernel/drv_e1000e/drv_e1000e.md5
===================================================================
--- npl/kernel/drv_e1000e/drv_e1000e.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_e1000e/drv_e1000e.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,4 +1,5 @@
-8dd7a099d41602a7b223d7f8db82c294  ./drv_e1000e.pkg
-9f85b56cb7f5fde9d6ddf879926de4fb  ./drv_e1000e.SlackBuild
-f1ff71a075d36d86819b7b14bba7c991  ./drv_e1000e.SlackBuild.log.gz
+d5282f3a7d01229cc50cc2a4a452d46d  ./drv_e1000e.pkg
+88591d173bd140bdf1501109f16ee4cc  ./drv_e1000e.SlackBuild
+8d7d90df8944ff5ca6432705424aafea  ./drv_e1000e.SlackBuild.log.gz
 5c6d010341868f753cf983cbe4467db5  ./e1000e-3.3.4.tar.gz
+7503911b5cbe0b654406b791dd768874  ./e1000e-3.4.2.1.tar.gz
Index: npl/kernel/drv_e1000e/drv_e1000e.version
===================================================================
--- npl/kernel/drv_e1000e/drv_e1000e.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_e1000e/drv_e1000e.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-3.3.4
+3.4.2.1
Index: npl/kernel/drv_hyperv/drv_hyperv.SlackBuild.dis
===================================================================
--- npl/kernel/drv_hyperv/drv_hyperv.SlackBuild.dis	(revision 6936b8932b048eb73512487926566f8def134e13)
+++ npl/kernel/drv_hyperv/drv_hyperv.SlackBuild.dis	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -0,0 +1,29 @@
+#!/bin/sh
+#DEP:linux_src
+#DEP:linux_headers
+#DEP:linux
+
+CWD=`pwd`
+TMP=/$CWD/tmp
+PKG=/tmp/pkg
+mkdir -p $PKG
+mkdir $TMP
+
+VERSION=4.2.7
+ARCH=${ARCH:-i486}
+
+cd $TMP
+tar -xjf $CWD/*.tar.bz2 || exit 1
+cd lis-next-$VERSION/src || exit 1
+
+make || exit 1
+#make INSTALL_MOD_PATH=/tmp/pkg install || exit 1
+mkdir -p /tmp/pkg/lib/modules/`uname -r`/extra || exit 1
+cp *ko /tmp/pkg/lib/modules/`uname -r`/extra || exit 1
+
+#package maken
+cd $PKG
+NAME=`echo $0|cut -f2 -d'.'`
+makepkg -l y -c n $CWD/$NAME.pkg > /dev/null &&
+echo $VERSION > $CWD/$NAME.version &&
+arch > $CWD/$NAME.arch 
Index: npl/kernel/drv_pf_ring/drv_pf_ring.arch
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring.arch	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring.arch	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-i686
+i586
Index: npl/kernel/drv_pf_ring/drv_pf_ring.build
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-5
+7
Index: npl/kernel/drv_pf_ring/drv_pf_ring.depver
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,2 +1,2 @@
-linux_src	404033004
+linux_src	409149001
 linux	0
Index: npl/kernel/drv_pf_ring/drv_pf_ring.md5
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,5 +1,5 @@
-66b8002a8f28c949e8c2acd4b79fbfdc  ./drv_pf_ring_dev.pkg
-924448bf7dfb0532cd4f78deedec0f95  ./drv_pf_ring.pkg
+058f40d5128a81e42174f850812b4f69  ./drv_pf_ring_dev.pkg
+a46beee5fe77d18ee1b42deea68608fb  ./drv_pf_ring.pkg
 8ab1d083c9ef0fea7a2d5fb2663252e1  ./drv_pf_ring.SlackBuild
-80c69602597e4ab836436772966c55b9  ./drv_pf_ring.SlackBuild.log.gz
+62fd76ce80ad6dfde673c78aec10d0ff  ./drv_pf_ring.SlackBuild.log.gz
 4199f896b822fbe87afc76c31505c371  ./pf-ring-6.6.0.tar.gz
Index: npl/kernel/drv_pf_ring/drv_pf_ring_dev.arch
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring_dev.arch	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring_dev.arch	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-i686
+i586
Index: npl/kernel/drv_pf_ring/drv_pf_ring_dev.build
===================================================================
--- npl/kernel/drv_pf_ring/drv_pf_ring_dev.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/drv_pf_ring/drv_pf_ring_dev.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-5
+7
Index: npl/kernel/initrd/initrd.build
===================================================================
--- npl/kernel/initrd/initrd.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd/initrd.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6553
+6556
Index: npl/kernel/initrd/initrd.depver
===================================================================
--- npl/kernel/initrd/initrd.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd/initrd.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -2,5 +2,5 @@
 xfsprogs	1
 linux	0
-linux_src	404072000
+linux_src	409149001
 lvm2	0
 pciutils	0
Index: npl/kernel/initrd/initrd.md5
===================================================================
--- npl/kernel/initrd/initrd.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd/initrd.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,3 +1,3 @@
-05cafa2a87fd8b7408edfc935e40aebb  ./initrd.pkg
+3ff3ed0490ca2da876e6a3d81221325f  ./initrd.pkg
 3a4c9fa2a61eb4a5e3a79ca0042e9792  ./initrd.SlackBuild
 3c1ba83b906d1fe77db9175aefe6581c  ./post.initrd
Index: npl/kernel/initrd/initrd.version
===================================================================
--- npl/kernel/initrd/initrd.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd/initrd.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-4.4.72_bigmem_syn3
+4.9.149_bigmem_syn3
Index: npl/kernel/initrd_scripts/initrd_scripts.build
===================================================================
--- npl/kernel/initrd_scripts/initrd_scripts.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd_scripts/initrd_scripts.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6545
+6546
Index: npl/kernel/initrd_scripts/initrd_scripts.md5
===================================================================
--- npl/kernel/initrd_scripts/initrd_scripts.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/initrd_scripts/initrd_scripts.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,7 +1,7 @@
-60c026608086ce565cadf2598d5586ec  ./initrd_scripts.pkg
+7633df4b6fa24ad769ded4d373ccee55  ./initrd_scripts.pkg
 f8c838462b443b47b87c93b372753db9  ./initrd_scripts.SlackBuild
-b5d60e619904138471d8277c775a12be  ./initrd_scripts.SlackBuild.log.gz
+59244a53e919308f45521ea3695c41b2  ./initrd_scripts.SlackBuild.log.gz
 a50b10adc68c6af8c9145a88b8f663d3  ./root/bin/sup
-f500a5bbd663874d92cc833d6b15009e  ./root/etc/drbd.boot
+34e1459a44051ecf92cbac2a52ca2386  ./root/etc/drbd.boot
 a9c8802601e03363c060046b5bc96532  ./root/etc/fstab
 540849ef0e979441257330e78ef501a4  ./root/etc/group
Index: npl/kernel/linux/linux.build
===================================================================
--- npl/kernel/linux/linux.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux/linux.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6554
Index: npl/kernel/linux/linux.depver
===================================================================
--- npl/kernel/linux/linux.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux/linux.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-linux_src	404072000
+linux_src	409149001
Index: npl/kernel/linux/linux.md5
===================================================================
--- npl/kernel/linux/linux.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux/linux.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,4 +1,4 @@
-04130325c2e8895bc2233178b08bd197  ./linux.pkg
+e0ca2dd6cfc4b086e006428a678865ac  ./linux.pkg
 67f6acaa0cb7027b29eed0b2e4cbea30  ./linux.SlackBuild
-3958f4a1e45dd37ddf25365225e5210e  ./linux.SlackBuild.log.gz
+cefa1eebf572204bfc0538f1c0c8ee8d  ./linux.SlackBuild.log.gz
 7fe139c0b2be4f799bf8012284fef9ff  ./post.linux
Index: npl/kernel/linux/linux.version
===================================================================
--- npl/kernel/linux/linux.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux/linux.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-4.4.72_bigmem_syn3
+4.9.149_bigmem_syn3
Index: npl/kernel/linux_headers/linux_headers.build
===================================================================
--- npl/kernel/linux_headers/linux_headers.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_headers/linux_headers.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6553
Index: npl/kernel/linux_headers/linux_headers.depver
===================================================================
--- npl/kernel/linux_headers/linux_headers.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_headers/linux_headers.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-linux_src	404072000
+linux_src	409149001
Index: npl/kernel/linux_headers/linux_headers.md5
===================================================================
--- npl/kernel/linux_headers/linux_headers.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_headers/linux_headers.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,3 +1,3 @@
-a6f2631f6d4a951bd63c648890c36488  ./linux_headers.pkg
+1fe8ec3ca9db4b8486bdcc539c85cfb2  ./linux_headers.pkg
 0f51cde2bbc4cbe006abcf63844e28c7  ./linux_headers.SlackBuild
-8282ace2d4be2bae822fdda301ede7f2  ./linux_headers.SlackBuild.log.gz
+0202a16dccf3b42ee4b7ae1850c72dfe  ./linux_headers.SlackBuild.log.gz
Index: npl/kernel/linux_headers/linux_headers.version
===================================================================
--- npl/kernel/linux_headers/linux_headers.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_headers/linux_headers.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-4.4.72_bigmem_syn3
+4.9.149_bigmem_syn3
Index: npl/kernel/linux_src/4200_fbcondecor.patch
===================================================================
--- npl/kernel/linux_src/4200_fbcondecor.patch	(revision 6936b8932b048eb73512487926566f8def134e13)
+++ npl/kernel/linux_src/4200_fbcondecor.patch	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -0,0 +1,2095 @@
+diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX
+index fe85e7c..2230930 100644
+--- a/Documentation/fb/00-INDEX
++++ b/Documentation/fb/00-INDEX
+@@ -23,6 +23,8 @@ ep93xx-fb.txt
+ 	- info on the driver for EP93xx LCD controller.
+ fbcon.txt
+ 	- intro to and usage guide for the framebuffer console (fbcon).
++fbcondecor.txt
++	- info on the Framebuffer Console Decoration
+ framebuffer.txt
+ 	- introduction to frame buffer devices.
+ gxfb.txt
+diff --git a/Documentation/fb/fbcondecor.txt b/Documentation/fb/fbcondecor.txt
+new file mode 100644
+index 0000000..637209e
+--- /dev/null
++++ b/Documentation/fb/fbcondecor.txt
+@@ -0,0 +1,207 @@
++What is it?
++-----------
++
++The framebuffer decorations are a kernel feature which allows displaying a
++background picture on selected consoles.
++
++What do I need to get it to work?
++---------------------------------
++
++To get fbcondecor up-and-running you will have to:
++ 1) get a copy of splashutils [1] or a similar program
++ 2) get some fbcondecor themes
++ 3) build the kernel helper program
++ 4) build your kernel with the FB_CON_DECOR option enabled.
++
++To get fbcondecor operational right after fbcon initialization is finished, you
++will have to include a theme and the kernel helper into your initramfs image.
++Please refer to splashutils documentation for instructions on how to do that.
++
++[1] The splashutils package can be downloaded from:
++    http://github.com/alanhaggai/fbsplash
++
++The userspace helper
++--------------------
++
++The userspace fbcondecor helper (by default: /sbin/fbcondecor_helper) is called by the
++kernel whenever an important event occurs and the kernel needs some kind of
++job to be carried out. Important events include console switches and video
++mode switches (the kernel requests background images and configuration
++parameters for the current console). The fbcondecor helper must be accessible at
++all times. If it's not, fbcondecor will be switched off automatically.
++
++It's possible to set path to the fbcondecor helper by writing it to
++/proc/sys/kernel/fbcondecor.
++
++*****************************************************************************
++
++The information below is mostly technical stuff. There's probably no need to
++read it unless you plan to develop a userspace helper.
++
++The fbcondecor protocol
++-----------------------
++
++The fbcondecor protocol defines a communication interface between the kernel and
++the userspace fbcondecor helper.
++
++The kernel side is responsible for:
++
++ * rendering console text, using an image as a background (instead of a
++   standard solid color fbcon uses),
++ * accepting commands from the user via ioctls on the fbcondecor device,
++ * calling the userspace helper to set things up as soon as the fb subsystem
++   is initialized.
++
++The userspace helper is responsible for everything else, including parsing
++configuration files, decompressing the image files whenever the kernel needs
++it, and communicating with the kernel if necessary.
++
++The fbcondecor protocol specifies how communication is done in both ways:
++kernel->userspace and userspace->helper.
++
++Kernel -> Userspace
++-------------------
++
++The kernel communicates with the userspace helper by calling it and specifying
++the task to be done in a series of arguments.
++
++The arguments follow the pattern:
++<fbcondecor protocol version> <command> <parameters>
++
++All commands defined in fbcondecor protocol v2 have the following parameters:
++ virtual console
++ framebuffer number
++ theme
++
++Fbcondecor protocol v1 specified an additional 'fbcondecor mode' after the
++framebuffer number. Fbcondecor protocol v1 is deprecated and should not be used.
++
++Fbcondecor protocol v2 specifies the following commands:
++
++getpic
++------
++ The kernel issues this command to request image data. It's up to the
++ userspace  helper to find a background image appropriate for the specified
++ theme and the current resolution. The userspace helper should respond by
++ issuing the FBIOCONDECOR_SETPIC ioctl.
++
++init
++----
++ The kernel issues this command after the fbcondecor device is created and
++ the fbcondecor interface is initialized. Upon receiving 'init', the userspace
++ helper should parse the kernel command line (/proc/cmdline) or otherwise
++ decide whether fbcondecor is to be activated.
++
++ To activate fbcondecor on the first console the helper should issue the
++ FBIOCONDECOR_SETCFG, FBIOCONDECOR_SETPIC and FBIOCONDECOR_SETSTATE commands,
++ in the above-mentioned order.
++
++ When the userspace helper is called in an early phase of the boot process
++ (right after the initialization of fbcon), no filesystems will be mounted.
++ The helper program should mount sysfs and then create the appropriate
++ framebuffer, fbcondecor and tty0 devices (if they don't already exist) to get
++ current display settings and to be able to communicate with the kernel side.
++ It should probably also mount the procfs to be able to parse the kernel
++ command line parameters.
++
++ Note that the console sem is not held when the kernel calls fbcondecor_helper
++ with the 'init' command. The fbcondecor helper should perform all ioctls with
++ origin set to FBCON_DECOR_IO_ORIG_USER.
++
++modechange
++----------
++ The kernel issues this command on a mode change. The helper's response should
++ be similar to the response to the 'init' command. Note that this time the
++ console sem is held and all ioctls must be performed with origin set to
++ FBCON_DECOR_IO_ORIG_KERNEL.
++
++
++Userspace -> Kernel
++-------------------
++
++Userspace programs can communicate with fbcondecor via ioctls on the
++fbcondecor device. These ioctls are to be used by both the userspace helper
++(called only by the kernel) and userspace configuration tools (run by the users).
++
++The fbcondecor helper should set the origin field to FBCON_DECOR_IO_ORIG_KERNEL
++when doing the appropriate ioctls. All userspace configuration tools should
++use FBCON_DECOR_IO_ORIG_USER. Failure to set the appropriate value in the origin
++field when performing ioctls from the kernel helper will most likely result
++in a console deadlock.
++
++FBCON_DECOR_IO_ORIG_KERNEL instructs fbcondecor not to try to acquire the console
++semaphore. Not surprisingly, FBCON_DECOR_IO_ORIG_USER instructs it to acquire
++the console sem.
++
++The framebuffer console decoration provides the following ioctls (all defined in
++linux/fb.h):
++
++FBIOCONDECOR_SETPIC
++description: loads a background picture for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct fb_image*
++notes:
++If called for consoles other than the current foreground one, the picture data
++will be ignored.
++
++If the current virtual console is running in a 8-bpp mode, the cmap substruct
++of fb_image has to be filled appropriately: start should be set to 16 (first
++16 colors are reserved for fbcon), len to a value <= 240 and red, green and
++blue should point to valid cmap data. The transp field is ingored. The fields
++dx, dy, bg_color, fg_color in fb_image are ignored as well.
++
++FBIOCONDECOR_SETCFG
++description: sets the fbcondecor config for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct vc_decor*
++notes: The structure has to be filled with valid data.
++
++FBIOCONDECOR_GETCFG
++description: gets the fbcondecor config for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: struct vc_decor*
++
++FBIOCONDECOR_SETSTATE
++description: sets the fbcondecor state for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: unsigned int*
++          values: 0 = disabled, 1 = enabled.
++
++FBIOCONDECOR_GETSTATE
++description: gets the fbcondecor state for a virtual console
++argument: struct fbcon_decor_iowrapper*; data: unsigned int*
++          values: as in FBIOCONDECOR_SETSTATE
++
++Info on used structures:
++
++Definition of struct vc_decor can be found in linux/console_decor.h. It's
++heavily commented. Note that the 'theme' field should point to a string
++no longer than FBCON_DECOR_THEME_LEN. When FBIOCONDECOR_GETCFG call is
++performed, the theme field should point to a char buffer of length
++FBCON_DECOR_THEME_LEN.
++
++Definition of struct fbcon_decor_iowrapper can be found in linux/fb.h.
++The fields in this struct have the following meaning:
++
++vc:
++Virtual console number.
++
++origin:
++Specifies if the ioctl is performed as a response to a kernel request. The
++fbcondecor helper should set this field to FBCON_DECOR_IO_ORIG_KERNEL, userspace
++programs should set it to FBCON_DECOR_IO_ORIG_USER. This field is necessary to
++avoid console semaphore deadlocks.
++
++data:
++Pointer to a data structure appropriate for the performed ioctl. Type of
++the data struct is specified in the ioctls description.
++
++*****************************************************************************
++
++Credit
++------
++
++Original 'bootsplash' project & implementation by:
++  Volker Poplawski <volker@poplawski.de>, Stefan Reinauer <stepan@suse.de>,
++  Steffen Winterfeldt <snwint@suse.de>, Michael Schroeder <mls@suse.de>,
++  Ken Wimer <wimer@suse.de>.
++
++Fbcondecor, fbcondecor protocol design, current implementation & docs by:
++  Michal Januszewski <michalj+fbcondecor@gmail.com>
++
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 53abb4a..1721aee 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -17,6 +17,10 @@ obj-y				+= pwm/
+ obj-$(CONFIG_PCI)		+= pci/
+ obj-$(CONFIG_PARISC)		+= parisc/
+ obj-$(CONFIG_RAPIDIO)		+= rapidio/
++# tty/ comes before char/ so that the VT console is the boot-time
++# default.
++obj-y				+= tty/
++obj-y				+= char/
+ obj-y				+= video/
+ obj-y				+= idle/
+ 
+@@ -45,11 +49,6 @@ obj-$(CONFIG_REGULATOR)		+= regulator/
+ # reset controllers early, since gpu drivers might rely on them to initialize
+ obj-$(CONFIG_RESET_CONTROLLER)	+= reset/
+ 
+-# tty/ comes before char/ so that the VT console is the boot-time
+-# default.
+-obj-y				+= tty/
+-obj-y				+= char/
+-
+ # iommu/ comes before gpu as gpu are using iommu controllers
+ obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
+ 
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index 38da6e2..fe58152 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -130,6 +130,19 @@ config FRAMEBUFFER_CONSOLE_ROTATION
+          such that other users of the framebuffer will remain normally
+          oriented.
+ 
++config FB_CON_DECOR
++	bool "Support for the Framebuffer Console Decorations"
++	depends on FRAMEBUFFER_CONSOLE=y && !FB_TILEBLITTING
++	default n
++	---help---
++	  This option enables support for framebuffer console decorations which
++	  makes it possible to display images in the background of the system
++	  consoles.  Note that userspace utilities are necessary in order to take
++	  advantage of these features. Refer to Documentation/fb/fbcondecor.txt
++	  for more information.
++
++	  If unsure, say N.
++
+ config STI_CONSOLE
+         bool "STI text console"
+         depends on PARISC
+diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
+index 43bfa48..cc104b6 100644
+--- a/drivers/video/console/Makefile
++++ b/drivers/video/console/Makefile
+@@ -16,4 +16,5 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
+                                          fbcon_ccw.o
+ endif
+ 
++obj-$(CONFIG_FB_CON_DECOR)     	  += fbcondecor.o cfbcondecor.o
+ obj-$(CONFIG_FB_STI)              += sticore.o
+diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
+index dbfe4ee..14da307 100644
+--- a/drivers/video/console/bitblit.c
++++ b/drivers/video/console/bitblit.c
+@@ -18,6 +18,7 @@
+ #include <linux/console.h>
+ #include <asm/types.h>
+ #include "fbcon.h"
++#include "fbcondecor.h"
+ 
+ /*
+  * Accelerated handlers.
+@@ -55,6 +56,13 @@ static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ 	area.height = height * vc->vc_font.height;
+ 	area.width = width * vc->vc_font.width;
+ 
++	if (fbcon_decor_active(info, vc)) {
++		area.sx += vc->vc_decor.tx;
++		area.sy += vc->vc_decor.ty;
++		area.dx += vc->vc_decor.tx;
++		area.dy += vc->vc_decor.ty;
++	}
++
+ 	info->fbops->fb_copyarea(info, &area);
+ }
+ 
+@@ -379,11 +387,15 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+-	if (info->fbops->fb_cursor)
+-		err = info->fbops->fb_cursor(info, &cursor);
++	if (fbcon_decor_active(info, vc)) {
++		fbcon_decor_cursor(info, &cursor);
++	} else {
++		if (info->fbops->fb_cursor)
++			err = info->fbops->fb_cursor(info, &cursor);
+ 
+-	if (err)
+-		soft_cursor(info, &cursor);
++		if (err)
++			soft_cursor(info, &cursor);
++	}
+ 
+ 	ops->cursor_reset = 0;
+ }
+diff --git a/drivers/video/console/cfbcondecor.c b/drivers/video/console/cfbcondecor.c
+new file mode 100644
+index 0000000..c262540
+--- /dev/null
++++ b/drivers/video/console/cfbcondecor.c
+@@ -0,0 +1,473 @@
++/*
++ *  linux/drivers/video/cfbcon_decor.c -- Framebuffer decor render functions
++ *
++ *  Copyright (C) 2004 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ *  Code based upon "Bootdecor" (C) 2001-2003
++ *       Volker Poplawski <volker@poplawski.de>,
++ *       Stefan Reinauer <stepan@suse.de>,
++ *       Steffen Winterfeldt <snwint@suse.de>,
++ *       Michael Schroeder <mls@suse.de>,
++ *       Ken Wimer <wimer@suse.de>.
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/selection.h>
++#include <linux/slab.h>
++#include <linux/vt_kern.h>
++#include <asm/irq.h>
++
++#include "fbcon.h"
++#include "fbcondecor.h"
++
++#define parse_pixel(shift, bpp, type)						\
++	do {									\
++		if (d & (0x80 >> (shift)))					\
++			dd2[(shift)] = fgx;					\
++		else								\
++			dd2[(shift)] = transparent ? *(type *)decor_src : bgx;	\
++		decor_src += (bpp);						\
++	} while (0)								\
++
++extern int get_color(struct vc_data *vc, struct fb_info *info,
++		     u16 c, int is_fg);
++
++void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc)
++{
++	int i, j, k;
++	int minlen = min(min(info->var.red.length, info->var.green.length),
++			     info->var.blue.length);
++	u32 col;
++
++	for (j = i = 0; i < 16; i++) {
++		k = color_table[i];
++
++		col = ((vc->vc_palette[j++]  >> (8-minlen))
++			<< info->var.red.offset);
++		col |= ((vc->vc_palette[j++] >> (8-minlen))
++			<< info->var.green.offset);
++		col |= ((vc->vc_palette[j++] >> (8-minlen))
++			<< info->var.blue.offset);
++			((u32 *)info->pseudo_palette)[k] = col;
++	}
++}
++
++void fbcon_decor_renderc(struct fb_info *info, int ypos, int xpos, int height,
++		      int width, u8 *src, u32 fgx, u32 bgx, u8 transparent)
++{
++	unsigned int x, y;
++	u32 dd;
++	int bytespp = ((info->var.bits_per_pixel + 7) >> 3);
++	unsigned int d = ypos * info->fix.line_length + xpos * bytespp;
++	unsigned int ds = (ypos * info->var.xres + xpos) * bytespp;
++	u16 dd2[4];
++
++	u8 *decor_src = (u8 *)(info->bgdecor.data + ds);
++	u8 *dst = (u8 *)(info->screen_base + d);
++
++	if ((ypos + height) > info->var.yres || (xpos + width) > info->var.xres)
++		return;
++
++	for (y = 0; y < height; y++) {
++		switch (info->var.bits_per_pixel) {
++
++		case 32:
++			for (x = 0; x < width; x++) {
++
++				if ((x & 7) == 0)
++					d = *src++;
++				if (d & 0x80)
++					dd = fgx;
++				else
++					dd = transparent ?
++					     *(u32 *)decor_src : bgx;
++
++				d <<= 1;
++				decor_src += 4;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++			break;
++		case 24:
++			for (x = 0; x < width; x++) {
++
++				if ((x & 7) == 0)
++					d = *src++;
++				if (d & 0x80)
++					dd = fgx;
++				else
++					dd = transparent ?
++					     (*(u32 *)decor_src & 0xffffff) : bgx;
++
++				d <<= 1;
++				decor_src += 3;
++#ifdef __LITTLE_ENDIAN
++				fb_writew(dd & 0xffff, dst);
++				dst += 2;
++				fb_writeb((dd >> 16), dst);
++#else
++				fb_writew(dd >> 8, dst);
++				dst += 2;
++				fb_writeb(dd & 0xff, dst);
++#endif
++				dst++;
++			}
++			break;
++		case 16:
++			for (x = 0; x < width; x += 2) {
++				if ((x & 7) == 0)
++					d = *src++;
++
++				parse_pixel(0, 2, u16);
++				parse_pixel(1, 2, u16);
++#ifdef __LITTLE_ENDIAN
++				dd = dd2[0] | (dd2[1] << 16);
++#else
++				dd = dd2[1] | (dd2[0] << 16);
++#endif
++				d <<= 2;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++			break;
++
++		case 8:
++			for (x = 0; x < width; x += 4) {
++				if ((x & 7) == 0)
++					d = *src++;
++
++				parse_pixel(0, 1, u8);
++				parse_pixel(1, 1, u8);
++				parse_pixel(2, 1, u8);
++				parse_pixel(3, 1, u8);
++
++#ifdef __LITTLE_ENDIAN
++				dd = dd2[0] | (dd2[1] << 8) | (dd2[2] << 16) | (dd2[3] << 24);
++#else
++				dd = dd2[3] | (dd2[2] << 8) | (dd2[1] << 16) | (dd2[0] << 24);
++#endif
++				d <<= 4;
++				fb_writel(dd, dst);
++				dst += 4;
++			}
++		}
++
++		dst += info->fix.line_length - width * bytespp;
++		decor_src += (info->var.xres - width) * bytespp;
++	}
++}
++
++#define cc2cx(a)						\
++	((info->fix.visual == FB_VISUAL_TRUECOLOR ||		\
++		info->fix.visual == FB_VISUAL_DIRECTCOLOR) ?	\
++			((u32 *)info->pseudo_palette)[a] : a)
++
++void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info,
++		   const unsigned short *s, int count, int yy, int xx)
++{
++	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
++	struct fbcon_ops *ops = info->fbcon_par;
++	int fg_color, bg_color, transparent;
++	u8 *src;
++	u32 bgx, fgx;
++	u16 c = scr_readw(s);
++
++	fg_color = get_color(vc, info, c, 1);
++	bg_color = get_color(vc, info, c, 0);
++
++	/* Don't paint the background image if console is blanked */
++	transparent = ops->blank_state ? 0 :
++		(vc->vc_decor.bg_color == bg_color);
++
++	xx = xx * vc->vc_font.width + vc->vc_decor.tx;
++	yy = yy * vc->vc_font.height + vc->vc_decor.ty;
++
++	fgx = cc2cx(fg_color);
++	bgx = cc2cx(bg_color);
++
++	while (count--) {
++		c = scr_readw(s++);
++		src = vc->vc_font.data + (c & charmask) * vc->vc_font.height *
++		      ((vc->vc_font.width + 7) >> 3);
++
++		fbcon_decor_renderc(info, yy, xx, vc->vc_font.height,
++			       vc->vc_font.width, src, fgx, bgx, transparent);
++		xx += vc->vc_font.width;
++	}
++}
++
++void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor)
++{
++	int i;
++	unsigned int dsize, s_pitch;
++	struct fbcon_ops *ops = info->fbcon_par;
++	struct vc_data *vc;
++	u8 *src;
++
++	/* we really don't need any cursors while the console is blanked */
++	if (info->state != FBINFO_STATE_RUNNING || ops->blank_state)
++		return;
++
++	vc = vc_cons[ops->currcon].d;
++
++	src = kmalloc(64 + sizeof(struct fb_image), GFP_ATOMIC);
++	if (!src)
++		return;
++
++	s_pitch = (cursor->image.width + 7) >> 3;
++	dsize = s_pitch * cursor->image.height;
++	if (cursor->enable) {
++		switch (cursor->rop) {
++		case ROP_XOR:
++			for (i = 0; i < dsize; i++)
++				src[i] = cursor->image.data[i] ^ cursor->mask[i];
++			break;
++		case ROP_COPY:
++		default:
++			for (i = 0; i < dsize; i++)
++				src[i] = cursor->image.data[i] & cursor->mask[i];
++			break;
++		}
++	} else
++		memcpy(src, cursor->image.data, dsize);
++
++	fbcon_decor_renderc(info,
++			cursor->image.dy + vc->vc_decor.ty,
++			cursor->image.dx + vc->vc_decor.tx,
++			cursor->image.height,
++			cursor->image.width,
++			(u8 *)src,
++			cc2cx(cursor->image.fg_color),
++			cc2cx(cursor->image.bg_color),
++			cursor->image.bg_color == vc->vc_decor.bg_color);
++
++	kfree(src);
++}
++
++static void decorset(u8 *dst, int height, int width, int dstbytes,
++				u32 bgx, int bpp)
++{
++	int i;
++
++	if (bpp == 8)
++		bgx |= bgx << 8;
++	if (bpp == 16 || bpp == 8)
++		bgx |= bgx << 16;
++
++	while (height-- > 0) {
++		u8 *p = dst;
++
++		switch (bpp) {
++
++		case 32:
++			for (i = 0; i < width; i++) {
++				fb_writel(bgx, p); p += 4;
++			}
++			break;
++		case 24:
++			for (i = 0; i < width; i++) {
++#ifdef __LITTLE_ENDIAN
++				fb_writew((bgx & 0xffff), (u16 *)p); p += 2;
++				fb_writeb((bgx >> 16), p++);
++#else
++				fb_writew((bgx >> 8), (u16 *)p); p += 2;
++				fb_writeb((bgx & 0xff), p++);
++#endif
++			}
++			break;
++		case 16:
++			for (i = 0; i < width/4; i++) {
++				fb_writel(bgx, p); p += 4;
++				fb_writel(bgx, p); p += 4;
++			}
++			if (width & 2) {
++				fb_writel(bgx, p); p += 4;
++			}
++			if (width & 1)
++				fb_writew(bgx, (u16 *)p);
++			break;
++		case 8:
++			for (i = 0; i < width/4; i++) {
++				fb_writel(bgx, p); p += 4;
++			}
++
++			if (width & 2) {
++				fb_writew(bgx, p); p += 2;
++			}
++			if (width & 1)
++				fb_writeb(bgx, (u8 *)p);
++			break;
++
++		}
++		dst += dstbytes;
++	}
++}
++
++void fbcon_decor_copy(u8 *dst, u8 *src, int height, int width, int linebytes,
++		   int srclinebytes, int bpp)
++{
++	int i;
++
++	while (height-- > 0) {
++		u32 *p = (u32 *)dst;
++		u32 *q = (u32 *)src;
++
++		switch (bpp) {
++
++		case 32:
++			for (i = 0; i < width; i++)
++				fb_writel(*q++, p++);
++			break;
++		case 24:
++			for (i = 0; i < (width * 3 / 4); i++)
++				fb_writel(*q++, p++);
++			if ((width * 3) % 4) {
++				if (width & 2) {
++					fb_writeb(*(u8 *)q, (u8 *)p);
++				} else if (width & 1) {
++					fb_writew(*(u16 *)q, (u16 *)p);
++					fb_writeb(*(u8 *)((u16 *)q + 1),
++							(u8 *)((u16 *)p + 2));
++				}
++			}
++			break;
++		case 16:
++			for (i = 0; i < width/4; i++) {
++				fb_writel(*q++, p++);
++				fb_writel(*q++, p++);
++			}
++			if (width & 2)
++				fb_writel(*q++, p++);
++			if (width & 1)
++				fb_writew(*(u16 *)q, (u16 *)p);
++			break;
++		case 8:
++			for (i = 0; i < width/4; i++)
++				fb_writel(*q++, p++);
++
++			if (width & 2) {
++				fb_writew(*(u16 *)q, (u16 *)p);
++				q = (u32 *) ((u16 *)q + 1);
++				p = (u32 *) ((u16 *)p + 1);
++			}
++			if (width & 1)
++				fb_writeb(*(u8 *)q, (u8 *)p);
++			break;
++		}
++
++		dst += linebytes;
++		src += srclinebytes;
++	}
++}
++
++static void decorfill(struct fb_info *info, int sy, int sx, int height,
++		       int width)
++{
++	int bytespp = ((info->var.bits_per_pixel + 7) >> 3);
++	int d  = sy * info->fix.line_length + sx * bytespp;
++	int ds = (sy * info->var.xres + sx) * bytespp;
++
++	fbcon_decor_copy((u8 *)(info->screen_base + d), (u8 *)(info->bgdecor.data + ds),
++		    height, width, info->fix.line_length, info->var.xres * bytespp,
++		    info->var.bits_per_pixel);
++}
++
++void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx,
++		    int height, int width)
++{
++	int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
++	struct fbcon_ops *ops = info->fbcon_par;
++	u8 *dst;
++	int transparent, bg_color = attr_bgcol_ec(bgshift, vc, info);
++
++	transparent = (vc->vc_decor.bg_color == bg_color);
++	sy = sy * vc->vc_font.height + vc->vc_decor.ty;
++	sx = sx * vc->vc_font.width + vc->vc_decor.tx;
++	height *= vc->vc_font.height;
++	width *= vc->vc_font.width;
++
++	/* Don't paint the background image if console is blanked */
++	if (transparent && !ops->blank_state) {
++		decorfill(info, sy, sx, height, width);
++	} else {
++		dst = (u8 *)(info->screen_base + sy * info->fix.line_length +
++			     sx * ((info->var.bits_per_pixel + 7) >> 3));
++		decorset(dst, height, width, info->fix.line_length, cc2cx(bg_color),
++			  info->var.bits_per_pixel);
++	}
++}
++
++void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info,
++			    int bottom_only)
++{
++	unsigned int tw = vc->vc_cols*vc->vc_font.width;
++	unsigned int th = vc->vc_rows*vc->vc_font.height;
++
++	if (!bottom_only) {
++		/* top margin */
++		decorfill(info, 0, 0, vc->vc_decor.ty, info->var.xres);
++		/* left margin */
++		decorfill(info, vc->vc_decor.ty, 0, th, vc->vc_decor.tx);
++		/* right margin */
++		decorfill(info, vc->vc_decor.ty, vc->vc_decor.tx + tw, th,
++			   info->var.xres - vc->vc_decor.tx - tw);
++	}
++	decorfill(info, vc->vc_decor.ty + th, 0,
++		   info->var.yres - vc->vc_decor.ty - th, info->var.xres);
++}
++
++void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y,
++			   int sx, int dx, int width)
++{
++	u16 *d = (u16 *) (vc->vc_origin + vc->vc_size_row * y + dx * 2);
++	u16 *s = d + (dx - sx);
++	u16 *start = d;
++	u16 *ls = d;
++	u16 *le = d + width;
++	u16 c;
++	int x = dx;
++	u16 attr = 1;
++
++	do {
++		c = scr_readw(d);
++		if (attr != (c & 0xff00)) {
++			attr = c & 0xff00;
++			if (d > start) {
++				fbcon_decor_putcs(vc, info, start, d - start, y, x);
++				x += d - start;
++				start = d;
++			}
++		}
++		if (s >= ls && s < le && c == scr_readw(s)) {
++			if (d > start) {
++				fbcon_decor_putcs(vc, info, start, d - start, y, x);
++				x += d - start + 1;
++				start = d + 1;
++			} else {
++				x++;
++				start++;
++			}
++		}
++		s++;
++		d++;
++	} while (d < le);
++	if (d > start)
++		fbcon_decor_putcs(vc, info, start, d - start, y, x);
++}
++
++void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank)
++{
++	if (blank) {
++		decorset((u8 *)info->screen_base, info->var.yres, info->var.xres,
++			  info->fix.line_length, 0, info->var.bits_per_pixel);
++	} else {
++		update_screen(vc);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++}
++
+diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
+index b87f5cf..ce44538 100644
+--- a/drivers/video/console/fbcon.c
++++ b/drivers/video/console/fbcon.c
+@@ -79,6 +79,7 @@
+ #include <asm/irq.h>
+ 
+ #include "fbcon.h"
++#include "../console/fbcondecor.h"
+ 
+ #ifdef FBCONDEBUG
+ #  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
+@@ -94,7 +95,7 @@ enum {
+ 
+ static struct display fb_display[MAX_NR_CONSOLES];
+ 
+-static signed char con2fb_map[MAX_NR_CONSOLES];
++signed char con2fb_map[MAX_NR_CONSOLES];
+ static signed char con2fb_map_boot[MAX_NR_CONSOLES];
+ 
+ static int logo_lines;
+@@ -282,7 +283,7 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
+ 		!vt_force_oops_output(vc);
+ }
+ 
+-static int get_color(struct vc_data *vc, struct fb_info *info,
++int get_color(struct vc_data *vc, struct fb_info *info,
+ 	      u16 c, int is_fg)
+ {
+ 	int depth = fb_get_color_depth(&info->var, &info->fix);
+@@ -546,6 +547,9 @@ static int do_fbcon_takeover(int show_logo)
+ 		info_idx = -1;
+ 	} else {
+ 		fbcon_has_console_bind = 1;
++#ifdef CONFIG_FB_CON_DECOR
++		fbcon_decor_init();
++#endif
+ 	}
+ 
+ 	return err;
+@@ -1005,6 +1009,12 @@ static const char *fbcon_startup(void)
+ 	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 	cols /= vc->vc_font.width;
+ 	rows /= vc->vc_font.height;
++
++	if (fbcon_decor_active(info, vc)) {
++		cols = vc->vc_decor.twidth / vc->vc_font.width;
++		rows = vc->vc_decor.theight / vc->vc_font.height;
++	}
++
+ 	vc_resize(vc, cols, rows);
+ 
+ 	DPRINTK("mode:   %s\n", info->fix.id);
+@@ -1034,7 +1044,7 @@ static void fbcon_init(struct vc_data *vc, int init)
+ 	cap = info->flags;
+ 
+ 	if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
+-	    (info->fix.type == FB_TYPE_TEXT))
++	    (info->fix.type == FB_TYPE_TEXT) || fbcon_decor_active(info, vc))
+ 		logo = 0;
+ 
+ 	if (var_to_display(p, &info->var, info))
+@@ -1259,6 +1269,11 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
+ 		fbcon_clear_margins(vc, 0);
+ 	}
+ 
++	if (fbcon_decor_active(info, vc)) {
++		fbcon_decor_clear(vc, info, sy, sx, height, width);
++		return;
++	}
++
+ 	/* Split blits that cross physical y_wrap boundary */
+ 
+ 	y_break = p->vrows - p->yscroll;
+@@ -1278,10 +1293,15 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+ 	struct display *p = &fb_display[vc->vc_num];
+ 	struct fbcon_ops *ops = info->fbcon_par;
+ 
+-	if (!fbcon_is_inactive(vc, info))
+-		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+-			   get_color(vc, info, scr_readw(s), 1),
+-			   get_color(vc, info, scr_readw(s), 0));
++	if (!fbcon_is_inactive(vc, info)) {
++
++		if (fbcon_decor_active(info, vc))
++			fbcon_decor_putcs(vc, info, s, count, ypos, xpos);
++		else
++			ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
++				   get_color(vc, info, scr_readw(s), 1),
++				   get_color(vc, info, scr_readw(s), 0));
++	}
+ }
+ 
+ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+@@ -1297,8 +1317,12 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
+ 	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ 	struct fbcon_ops *ops = info->fbcon_par;
+ 
+-	if (!fbcon_is_inactive(vc, info))
+-		ops->clear_margins(vc, info, bottom_only);
++	if (!fbcon_is_inactive(vc, info)) {
++		if (fbcon_decor_active(info, vc))
++			fbcon_decor_clear_margins(vc, info, bottom_only);
++		else
++			ops->clear_margins(vc, info, bottom_only);
++	}
+ }
+ 
+ static void fbcon_cursor(struct vc_data *vc, int mode)
+@@ -1819,7 +1843,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+ 			count = vc->vc_rows;
+ 		if (softback_top)
+ 			fbcon_softback_note(vc, t, count);
+-		if (logo_shown >= 0)
++		if (logo_shown >= 0 || fbcon_decor_active(info, vc))
+ 			goto redraw_up;
+ 		switch (p->scrollmode) {
+ 		case SCROLL_MOVE:
+@@ -1912,6 +1936,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
+ 			count = vc->vc_rows;
+ 		if (logo_shown >= 0)
+ 			goto redraw_down;
++		if (fbcon_decor_active(info, vc))
++			goto redraw_down;
+ 		switch (p->scrollmode) {
+ 		case SCROLL_MOVE:
+ 			fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+@@ -2060,6 +2086,13 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
+ 		}
+ 		return;
+ 	}
++
++	if (fbcon_decor_active(info, vc) && sy == dy && height == 1) {
++		/* must use slower redraw bmove to keep background pic intact */
++		fbcon_decor_bmove_redraw(vc, info, sy, sx, dx, width);
++		return;
++	}
++
+ 	ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+ 		   height, width);
+ }
+@@ -2130,8 +2163,8 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ 	var.yres = virt_h * virt_fh;
+ 	x_diff = info->var.xres - var.xres;
+ 	y_diff = info->var.yres - var.yres;
+-	if (x_diff < 0 || x_diff > virt_fw ||
+-	    y_diff < 0 || y_diff > virt_fh) {
++	if ((x_diff < 0 || x_diff > virt_fw ||
++		y_diff < 0 || y_diff > virt_fh) && !vc->vc_decor.state) {
+ 		const struct fb_videomode *mode;
+ 
+ 		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
+@@ -2167,6 +2200,22 @@ static int fbcon_switch(struct vc_data *vc)
+ 
+ 	info = registered_fb[con2fb_map[vc->vc_num]];
+ 	ops = info->fbcon_par;
++	prev_console = ops->currcon;
++	if (prev_console != -1)
++		old_info = registered_fb[con2fb_map[prev_console]];
++
++#ifdef CONFIG_FB_CON_DECOR
++	if (!fbcon_decor_active_vc(vc) && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
++		struct vc_data *vc_curr = vc_cons[prev_console].d;
++
++		if (vc_curr && fbcon_decor_active_vc(vc_curr)) {
++			// Clear the screen to avoid displaying funky colors
++			// during palette updates.
++			memset((u8 *)info->screen_base + info->fix.line_length * info->var.yoffset,
++			       0, info->var.yres * info->fix.line_length);
++		}
++	}
++#endif
+ 
+ 	if (softback_top) {
+ 		if (softback_lines)
+@@ -2185,9 +2234,6 @@ static int fbcon_switch(struct vc_data *vc)
+ 		logo_shown = FBCON_LOGO_CANSHOW;
+ 	}
+ 
+-	prev_console = ops->currcon;
+-	if (prev_console != -1)
+-		old_info = registered_fb[con2fb_map[prev_console]];
+ 	/*
+ 	 * FIXME: If we have multiple fbdev's loaded, we need to
+ 	 * update all info->currcon.  Perhaps, we can place this
+@@ -2231,6 +2277,18 @@ static int fbcon_switch(struct vc_data *vc)
+ 			fbcon_del_cursor_timer(old_info);
+ 	}
+ 
++	if (fbcon_decor_active_vc(vc)) {
++		struct vc_data *vc_curr = vc_cons[prev_console].d;
++
++		if (!vc_curr->vc_decor.theme ||
++			strcmp(vc->vc_decor.theme, vc_curr->vc_decor.theme) ||
++			(fbcon_decor_active_nores(info, vc_curr) &&
++			 !fbcon_decor_active(info, vc_curr))) {
++			fbcon_decor_disable(vc, 0);
++			fbcon_decor_call_helper("modechange", vc->vc_num);
++		}
++	}
++
+ 	if (fbcon_is_inactive(vc, info) ||
+ 	    ops->blank_state != FB_BLANK_UNBLANK)
+ 		fbcon_del_cursor_timer(info);
+@@ -2339,15 +2397,20 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ 		}
+ 	}
+ 
+- 	if (!fbcon_is_inactive(vc, info)) {
++	if (!fbcon_is_inactive(vc, info)) {
+ 		if (ops->blank_state != blank) {
+ 			ops->blank_state = blank;
+ 			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+ 			ops->cursor_flash = (!blank);
+ 
+-			if (!(info->flags & FBINFO_MISC_USEREVENT))
+-				if (fb_blank(info, blank))
+-					fbcon_generic_blank(vc, info, blank);
++			if (!(info->flags & FBINFO_MISC_USEREVENT)) {
++				if (fb_blank(info, blank)) {
++					if (fbcon_decor_active(info, vc))
++						fbcon_decor_blank(vc, info, blank);
++					else
++						fbcon_generic_blank(vc, info, blank);
++				}
++			}
+ 		}
+ 
+ 		if (!blank)
+@@ -2522,13 +2585,22 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
+ 	}
+ 
+ 	if (resize) {
++		/* reset wrap/pan */
+ 		int cols, rows;
+ 
+ 		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++
++		if (fbcon_decor_active(info, vc)) {
++			info->var.xoffset = info->var.yoffset = p->yscroll = 0;
++			cols = vc->vc_decor.twidth;
++			rows = vc->vc_decor.theight;
++		}
+ 		cols /= w;
+ 		rows /= h;
++
+ 		vc_resize(vc, cols, rows);
++
+ 		if (con_is_visible(vc) && softback_buf)
+ 			fbcon_update_softback(vc);
+ 	} else if (con_is_visible(vc)
+@@ -2657,7 +2729,11 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
+ 	int i, j, k, depth;
+ 	u8 val;
+ 
+-	if (fbcon_is_inactive(vc, info))
++	if (fbcon_is_inactive(vc, info)
++#ifdef CONFIG_FB_CON_DECOR
++			|| vc->vc_num != fg_console
++#endif
++		)
+ 		return;
+ 
+ 	if (!con_is_visible(vc))
+@@ -2683,7 +2759,47 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
+ 	} else
+ 		fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap);
+ 
+-	fb_set_cmap(&palette_cmap, info);
++	if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
++
++		u16 *red, *green, *blue;
++		int minlen = min(min(info->var.red.length, info->var.green.length),
++				     info->var.blue.length);
++
++		struct fb_cmap cmap = {
++			.start = 0,
++			.len = (1 << minlen),
++			.red = NULL,
++			.green = NULL,
++			.blue = NULL,
++			.transp = NULL
++		};
++
++		red = kmalloc(256 * sizeof(u16) * 3, GFP_KERNEL);
++
++		if (!red)
++			goto out;
++
++		green = red + 256;
++		blue = green + 256;
++		cmap.red = red;
++		cmap.green = green;
++		cmap.blue = blue;
++
++		for (i = 0; i < cmap.len; i++)
++			red[i] = green[i] = blue[i] = (0xffff * i)/(cmap.len-1);
++
++		fb_set_cmap(&cmap, info);
++		fbcon_decor_fix_pseudo_pal(info, vc_cons[fg_console].d);
++		kfree(red);
++
++		return;
++
++	} else if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++		   info->var.bits_per_pixel == 8 && info->bgdecor.cmap.red != NULL)
++		fb_set_cmap(&info->bgdecor.cmap, info);
++
++out:	fb_set_cmap(&palette_cmap, info);
+ }
+ 
+ static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
+@@ -2908,7 +3024,14 @@ static void fbcon_modechanged(struct fb_info *info)
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+-		vc_resize(vc, cols, rows);
++
++		if (!fbcon_decor_active_nores(info, vc)) {
++			vc_resize(vc, cols, rows);
++		} else {
++			fbcon_decor_disable(vc, 0);
++			fbcon_decor_call_helper("modechange", vc->vc_num);
++		}
++
+ 		updatescrollmode(p, info, vc);
+ 		scrollback_max = 0;
+ 		scrollback_current = 0;
+@@ -2953,7 +3076,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
+ 		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+-		vc_resize(vc, cols, rows);
++		if (!fbcon_decor_active_nores(info, vc))
++			vc_resize(vc, cols, rows);
+ 	}
+ 
+ 	if (fg != -1)
+@@ -3594,6 +3718,7 @@ static void fbcon_exit(void)
+ 		}
+ 	}
+ 
++	fbcon_decor_exit();
+ 	fbcon_has_exited = 1;
+ }
+ 
+diff --git a/drivers/video/console/fbcondecor.c b/drivers/video/console/fbcondecor.c
+new file mode 100644
+index 0000000..65cc0d3
+--- /dev/null
++++ b/drivers/video/console/fbcondecor.c
+@@ -0,0 +1,549 @@
++/*
++ *  linux/drivers/video/console/fbcondecor.c -- Framebuffer console decorations
++ *
++ *  Copyright (C) 2004-2009 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ *  Code based upon "Bootsplash" (C) 2001-2003
++ *       Volker Poplawski <volker@poplawski.de>,
++ *       Stefan Reinauer <stepan@suse.de>,
++ *       Steffen Winterfeldt <snwint@suse.de>,
++ *       Michael Schroeder <mls@suse.de>,
++ *       Ken Wimer <wimer@suse.de>.
++ *
++ *  Compat ioctl support by Thorsten Klein <TK@Thorsten-Klein.de>.
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ *
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/vt_kern.h>
++#include <linux/vmalloc.h>
++#include <linux/unistd.h>
++#include <linux/syscalls.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/workqueue.h>
++#include <linux/kmod.h>
++#include <linux/miscdevice.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/compat.h>
++#include <linux/console.h>
++
++#include <linux/uaccess.h>
++#include <asm/irq.h>
++
++#include "fbcon.h"
++#include "fbcondecor.h"
++
++extern signed char con2fb_map[];
++static int fbcon_decor_enable(struct vc_data *vc);
++
++static int initialized;
++
++char fbcon_decor_path[KMOD_PATH_LEN] = "/sbin/fbcondecor_helper";
++EXPORT_SYMBOL(fbcon_decor_path);
++
++int fbcon_decor_call_helper(char *cmd, unsigned short vc)
++{
++	char *envp[] = {
++		"HOME=/",
++		"PATH=/sbin:/bin",
++		NULL
++	};
++
++	char tfb[5];
++	char tcons[5];
++	unsigned char fb = (int) con2fb_map[vc];
++
++	char *argv[] = {
++		fbcon_decor_path,
++		"2",
++		cmd,
++		tcons,
++		tfb,
++		vc_cons[vc].d->vc_decor.theme,
++		NULL
++	};
++
++	snprintf(tfb, 5, "%d", fb);
++	snprintf(tcons, 5, "%d", vc);
++
++	return call_usermodehelper(fbcon_decor_path, argv, envp, UMH_WAIT_EXEC);
++}
++
++/* Disables fbcondecor on a virtual console; called with console sem held. */
++int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw)
++{
++	struct fb_info *info;
++
++	if (!vc->vc_decor.state)
++		return -EINVAL;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL)
++		return -EINVAL;
++
++	vc->vc_decor.state = 0;
++	vc_resize(vc, info->var.xres / vc->vc_font.width,
++		  info->var.yres / vc->vc_font.height);
++
++	if (fg_console == vc->vc_num && redraw) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++	}
++
++	printk(KERN_INFO "fbcondecor: switched decor state to 'off' on console %d\n",
++			 vc->vc_num);
++
++	return 0;
++}
++
++/* Enables fbcondecor on a virtual console; called with console sem held. */
++static int fbcon_decor_enable(struct vc_data *vc)
++{
++	struct fb_info *info;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (vc->vc_decor.twidth == 0 || vc->vc_decor.theight == 0 ||
++	    info == NULL || vc->vc_decor.state || (!info->bgdecor.data &&
++	    vc->vc_num == fg_console))
++		return -EINVAL;
++
++	vc->vc_decor.state = 1;
++	vc_resize(vc, vc->vc_decor.twidth / vc->vc_font.width,
++		  vc->vc_decor.theight / vc->vc_font.height);
++
++	if (fg_console == vc->vc_num) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++
++	printk(KERN_INFO "fbcondecor: switched decor state to 'on' on console %d\n",
++			 vc->vc_num);
++
++	return 0;
++}
++
++static inline int fbcon_decor_ioctl_dosetstate(struct vc_data *vc, unsigned int state, unsigned char origin)
++{
++	int ret;
++
++	console_lock();
++	if (!state)
++		ret = fbcon_decor_disable(vc, 1);
++	else
++		ret = fbcon_decor_enable(vc);
++	console_unlock();
++
++	return ret;
++}
++
++static inline void fbcon_decor_ioctl_dogetstate(struct vc_data *vc, unsigned int *state)
++{
++	*state = vc->vc_decor.state;
++}
++
++static int fbcon_decor_ioctl_dosetcfg(struct vc_data *vc, struct vc_decor *cfg, unsigned char origin)
++{
++	struct fb_info *info;
++	int len;
++	char *tmp;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL || !cfg->twidth || !cfg->theight ||
++	    cfg->tx + cfg->twidth  > info->var.xres ||
++	    cfg->ty + cfg->theight > info->var.yres)
++		return -EINVAL;
++
++	len = strlen_user(cfg->theme);
++	if (!len || len > FBCON_DECOR_THEME_LEN)
++		return -EINVAL;
++	tmp = kmalloc(len, GFP_KERNEL);
++	if (!tmp)
++		return -ENOMEM;
++	if (copy_from_user(tmp, (void __user *)cfg->theme, len))
++		return -EFAULT;
++	cfg->theme = tmp;
++	cfg->state = 0;
++
++	console_lock();
++	if (vc->vc_decor.state)
++		fbcon_decor_disable(vc, 1);
++	kfree(vc->vc_decor.theme);
++	vc->vc_decor = *cfg;
++	console_unlock();
++
++	printk(KERN_INFO "fbcondecor: console %d using theme '%s'\n",
++			 vc->vc_num, vc->vc_decor.theme);
++	return 0;
++}
++
++static int fbcon_decor_ioctl_dogetcfg(struct vc_data *vc,
++					struct vc_decor *decor)
++{
++	char __user *tmp;
++
++	tmp = decor->theme;
++	*decor = vc->vc_decor;
++	decor->theme = tmp;
++
++	if (vc->vc_decor.theme) {
++		if (copy_to_user(tmp, vc->vc_decor.theme,
++					strlen(vc->vc_decor.theme) + 1))
++			return -EFAULT;
++	} else
++		if (put_user(0, tmp))
++			return -EFAULT;
++
++	return 0;
++}
++
++static int fbcon_decor_ioctl_dosetpic(struct vc_data *vc, struct fb_image *img,
++						unsigned char origin)
++{
++	struct fb_info *info;
++	int len;
++	u8 *tmp;
++
++	if (vc->vc_num != fg_console)
++		return -EINVAL;
++
++	info = registered_fb[(int) con2fb_map[vc->vc_num]];
++
++	if (info == NULL)
++		return -EINVAL;
++
++	if (img->width != info->var.xres || img->height != info->var.yres) {
++		printk(KERN_ERR "fbcondecor: picture dimensions mismatch\n");
++		printk(KERN_ERR "%dx%d vs %dx%d\n", img->width, img->height,
++				info->var.xres, info->var.yres);
++		return -EINVAL;
++	}
++
++	if (img->depth != info->var.bits_per_pixel) {
++		printk(KERN_ERR "fbcondecor: picture depth mismatch\n");
++		return -EINVAL;
++	}
++
++	if (img->depth == 8) {
++		if (!img->cmap.len || !img->cmap.red || !img->cmap.green ||
++		    !img->cmap.blue)
++			return -EINVAL;
++
++		tmp = vmalloc(img->cmap.len * 3 * 2);
++		if (!tmp)
++			return -ENOMEM;
++
++		if (copy_from_user(tmp,
++				(void __user *)img->cmap.red,
++						(img->cmap.len << 1)) ||
++			copy_from_user(tmp + (img->cmap.len << 1),
++				(void __user *)img->cmap.green,
++						(img->cmap.len << 1)) ||
++			copy_from_user(tmp + (img->cmap.len << 2),
++				(void __user *)img->cmap.blue,
++						(img->cmap.len << 1))) {
++			vfree(tmp);
++			return -EFAULT;
++		}
++
++		img->cmap.transp = NULL;
++		img->cmap.red = (u16 *)tmp;
++		img->cmap.green = img->cmap.red + img->cmap.len;
++		img->cmap.blue = img->cmap.green + img->cmap.len;
++	} else {
++		img->cmap.red = NULL;
++	}
++
++	len = ((img->depth + 7) >> 3) * img->width * img->height;
++
++	/*
++	 * Allocate an additional byte so that we never go outside of the
++	 * buffer boundaries in the rendering functions in a 24 bpp mode.
++	 */
++	tmp = vmalloc(len + 1);
++
++	if (!tmp)
++		goto out;
++
++	if (copy_from_user(tmp, (void __user *)img->data, len))
++		goto out;
++
++	img->data = tmp;
++
++	console_lock();
++
++	if (info->bgdecor.data)
++		vfree((u8 *)info->bgdecor.data);
++	if (info->bgdecor.cmap.red)
++		vfree(info->bgdecor.cmap.red);
++
++	info->bgdecor = *img;
++
++	if (fbcon_decor_active_vc(vc) && fg_console == vc->vc_num) {
++		redraw_screen(vc, 0);
++		update_region(vc, vc->vc_origin +
++			      vc->vc_size_row * vc->vc_top,
++			      vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2);
++		fbcon_decor_clear_margins(vc, info, 0);
++	}
++
++	console_unlock();
++
++	return 0;
++
++out:
++	if (img->cmap.red)
++		vfree(img->cmap.red);
++
++	if (tmp)
++		vfree(tmp);
++	return -ENOMEM;
++}
++
++static long fbcon_decor_ioctl(struct file *filp, u_int cmd, u_long arg)
++{
++	struct fbcon_decor_iowrapper __user *wrapper = (void __user *) arg;
++	struct vc_data *vc = NULL;
++	unsigned short vc_num = 0;
++	unsigned char origin = 0;
++	void __user *data = NULL;
++
++	if (!access_ok(VERIFY_READ, wrapper,
++			sizeof(struct fbcon_decor_iowrapper)))
++		return -EFAULT;
++
++	__get_user(vc_num, &wrapper->vc);
++	__get_user(origin, &wrapper->origin);
++	__get_user(data, &wrapper->data);
++
++	if (!vc_cons_allocated(vc_num))
++		return -EINVAL;
++
++	vc = vc_cons[vc_num].d;
++
++	switch (cmd) {
++	case FBIOCONDECOR_SETPIC:
++	{
++		struct fb_image img;
++
++		if (copy_from_user(&img, (struct fb_image __user *)data, sizeof(struct fb_image)))
++			return -EFAULT;
++
++		return fbcon_decor_ioctl_dosetpic(vc, &img, origin);
++	}
++	case FBIOCONDECOR_SETCFG:
++	{
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg, (struct vc_decor __user *)data, sizeof(struct vc_decor)))
++			return -EFAULT;
++
++		return fbcon_decor_ioctl_dosetcfg(vc, &cfg, origin);
++	}
++	case FBIOCONDECOR_GETCFG:
++	{
++		int rval;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg, (struct vc_decor __user *)data, sizeof(struct vc_decor)))
++			return -EFAULT;
++
++		rval = fbcon_decor_ioctl_dogetcfg(vc, &cfg);
++
++		if (copy_to_user(data, &cfg, sizeof(struct vc_decor)))
++			return -EFAULT;
++		return rval;
++	}
++	case FBIOCONDECOR_SETSTATE:
++	{
++		unsigned int state = 0;
++
++		if (get_user(state, (unsigned int __user *)data))
++			return -EFAULT;
++		return fbcon_decor_ioctl_dosetstate(vc, state, origin);
++	}
++	case FBIOCONDECOR_GETSTATE:
++	{
++		unsigned int state = 0;
++
++		fbcon_decor_ioctl_dogetstate(vc, &state);
++		return put_user(state, (unsigned int __user *)data);
++	}
++
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++
++#ifdef CONFIG_COMPAT
++
++static long fbcon_decor_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++	struct fbcon_decor_iowrapper32 __user *wrapper = (void __user *)arg;
++	struct vc_data *vc = NULL;
++	unsigned short vc_num = 0;
++	unsigned char origin = 0;
++	compat_uptr_t data_compat = 0;
++	void __user *data = NULL;
++
++	if (!access_ok(VERIFY_READ, wrapper,
++			sizeof(struct fbcon_decor_iowrapper32)))
++		return -EFAULT;
++
++	__get_user(vc_num, &wrapper->vc);
++	__get_user(origin, &wrapper->origin);
++	__get_user(data_compat, &wrapper->data);
++	data = compat_ptr(data_compat);
++
++	if (!vc_cons_allocated(vc_num))
++		return -EINVAL;
++
++	vc = vc_cons[vc_num].d;
++
++	switch (cmd) {
++	case FBIOCONDECOR_SETPIC32:
++	{
++		struct fb_image32 img_compat;
++		struct fb_image img;
++
++		if (copy_from_user(&img_compat, (struct fb_image32 __user *)data, sizeof(struct fb_image32)))
++			return -EFAULT;
++
++		fb_image_from_compat(img, img_compat);
++
++		return fbcon_decor_ioctl_dosetpic(vc, &img, origin);
++	}
++
++	case FBIOCONDECOR_SETCFG32:
++	{
++		struct vc_decor32 cfg_compat;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg_compat, (struct vc_decor32 __user *)data, sizeof(struct vc_decor32)))
++			return -EFAULT;
++
++		vc_decor_from_compat(cfg, cfg_compat);
++
++		return fbcon_decor_ioctl_dosetcfg(vc, &cfg, origin);
++	}
++
++	case FBIOCONDECOR_GETCFG32:
++	{
++		int rval;
++		struct vc_decor32 cfg_compat;
++		struct vc_decor cfg;
++
++		if (copy_from_user(&cfg_compat, (struct vc_decor32 __user *)data, sizeof(struct vc_decor32)))
++			return -EFAULT;
++		cfg.theme = compat_ptr(cfg_compat.theme);
++
++		rval = fbcon_decor_ioctl_dogetcfg(vc, &cfg);
++
++		vc_decor_to_compat(cfg_compat, cfg);
++
++		if (copy_to_user((struct vc_decor32 __user *)data, &cfg_compat, sizeof(struct vc_decor32)))
++			return -EFAULT;
++		return rval;
++	}
++
++	case FBIOCONDECOR_SETSTATE32:
++	{
++		compat_uint_t state_compat = 0;
++		unsigned int state = 0;
++
++		if (get_user(state_compat, (compat_uint_t __user *)data))
++			return -EFAULT;
++
++		state = (unsigned int)state_compat;
++
++		return fbcon_decor_ioctl_dosetstate(vc, state, origin);
++	}
++
++	case FBIOCONDECOR_GETSTATE32:
++	{
++		compat_uint_t state_compat = 0;
++		unsigned int state = 0;
++
++		fbcon_decor_ioctl_dogetstate(vc, &state);
++		state_compat = (compat_uint_t)state;
++
++		return put_user(state_compat, (compat_uint_t __user *)data);
++	}
++
++	default:
++		return -ENOIOCTLCMD;
++	}
++}
++#else
++  #define fbcon_decor_compat_ioctl NULL
++#endif
++
++static struct file_operations fbcon_decor_ops = {
++	.owner = THIS_MODULE,
++	.unlocked_ioctl = fbcon_decor_ioctl,
++	.compat_ioctl = fbcon_decor_compat_ioctl
++};
++
++static struct miscdevice fbcon_decor_dev = {
++	.minor = MISC_DYNAMIC_MINOR,
++	.name = "fbcondecor",
++	.fops = &fbcon_decor_ops
++};
++
++void fbcon_decor_reset(void)
++{
++	int i;
++
++	for (i = 0; i < num_registered_fb; i++) {
++		registered_fb[i]->bgdecor.data = NULL;
++		registered_fb[i]->bgdecor.cmap.red = NULL;
++	}
++
++	for (i = 0; i < MAX_NR_CONSOLES && vc_cons[i].d; i++) {
++		vc_cons[i].d->vc_decor.state = vc_cons[i].d->vc_decor.twidth =
++						vc_cons[i].d->vc_decor.theight = 0;
++		vc_cons[i].d->vc_decor.theme = NULL;
++	}
++}
++
++int fbcon_decor_init(void)
++{
++	int i;
++
++	fbcon_decor_reset();
++
++	if (initialized)
++		return 0;
++
++	i = misc_register(&fbcon_decor_dev);
++	if (i) {
++		printk(KERN_ERR "fbcondecor: failed to register device\n");
++		return i;
++	}
++
++	fbcon_decor_call_helper("init", 0);
++	initialized = 1;
++	return 0;
++}
++
++int fbcon_decor_exit(void)
++{
++	fbcon_decor_reset();
++	return 0;
++}
+diff --git a/drivers/video/console/fbcondecor.h b/drivers/video/console/fbcondecor.h
+new file mode 100644
+index 0000000..c49386c
+--- /dev/null
++++ b/drivers/video/console/fbcondecor.h
+@@ -0,0 +1,77 @@
++/*
++ *  linux/drivers/video/console/fbcondecor.h -- Framebuffer Console Decoration headers
++ *
++ *  Copyright (C) 2004 Michal Januszewski <michalj+fbcondecor@gmail.com>
++ *
++ */
++
++#ifndef __FBCON_DECOR_H
++#define __FBCON_DECOR_H
++
++#ifndef _LINUX_FB_H
++#include <linux/fb.h>
++#endif
++
++/* This is needed for vc_cons in fbcmap.c */
++#include <linux/vt_kern.h>
++
++struct fb_cursor;
++struct fb_info;
++struct vc_data;
++
++#ifdef CONFIG_FB_CON_DECOR
++/* fbcondecor.c */
++int fbcon_decor_init(void);
++int fbcon_decor_exit(void);
++int fbcon_decor_call_helper(char *cmd, unsigned short cons);
++int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw);
++
++/* cfbcondecor.c */
++void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx);
++void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor);
++void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width);
++void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only);
++void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank);
++void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width);
++void fbcon_decor_copy(u8 *dst, u8 *src, int height, int width, int linebytes, int srclinesbytes, int bpp);
++void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc);
++
++/* vt.c */
++void acquire_console_sem(void);
++void release_console_sem(void);
++void do_unblank_screen(int entering_gfx);
++
++/* struct vc_data *y */
++#define fbcon_decor_active_vc(y) (y->vc_decor.state && y->vc_decor.theme)
++
++/* struct fb_info *x, struct vc_data *y */
++#define fbcon_decor_active_nores(x, y) (x->bgdecor.data && fbcon_decor_active_vc(y))
++
++/* struct fb_info *x, struct vc_data *y */
++#define fbcon_decor_active(x, y) (fbcon_decor_active_nores(x, y) &&	\
++				x->bgdecor.width == x->var.xres &&	\
++				x->bgdecor.height == x->var.yres &&	\
++				x->bgdecor.depth == x->var.bits_per_pixel)
++
++#else /* CONFIG_FB_CON_DECOR */
++
++static inline void fbcon_decor_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx) {}
++static inline void fbcon_decor_putc(struct vc_data *vc, struct fb_info *info, int c, int ypos, int xpos) {}
++static inline void fbcon_decor_cursor(struct fb_info *info, struct fb_cursor *cursor) {}
++static inline void fbcon_decor_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) {}
++static inline void fbcon_decor_clear_margins(struct vc_data *vc, struct fb_info *info, int bottom_only) {}
++static inline void fbcon_decor_blank(struct vc_data *vc, struct fb_info *info, int blank) {}
++static inline void fbcon_decor_bmove_redraw(struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width) {}
++static inline void fbcon_decor_fix_pseudo_pal(struct fb_info *info, struct vc_data *vc) {}
++static inline int fbcon_decor_call_helper(char *cmd, unsigned short cons) { return 0; }
++static inline int fbcon_decor_init(void) { return 0; }
++static inline int fbcon_decor_exit(void) { return 0; }
++static inline int fbcon_decor_disable(struct vc_data *vc, unsigned char redraw) { return 0; }
++
++#define fbcon_decor_active_vc(y) (0)
++#define fbcon_decor_active_nores(x, y) (0)
++#define fbcon_decor_active(x, y) (0)
++
++#endif /* CONFIG_FB_CON_DECOR */
++
++#endif /* __FBCON_DECOR_H */
+diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
+index 88b008f..c84113d 100644
+--- a/drivers/video/fbdev/Kconfig
++++ b/drivers/video/fbdev/Kconfig
+@@ -1216,7 +1216,6 @@ config FB_MATROX
+ 	select FB_CFB_FILLRECT
+ 	select FB_CFB_COPYAREA
+ 	select FB_CFB_IMAGEBLIT
+-	select FB_TILEBLITTING
+ 	select FB_MACMODES if PPC_PMAC
+ 	---help---
+ 	  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
+diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c
+index f89245b..c2c12ce 100644
+--- a/drivers/video/fbdev/core/fbcmap.c
++++ b/drivers/video/fbdev/core/fbcmap.c
+@@ -17,6 +17,8 @@
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
+ 
++#include "../../console/fbcondecor.h"
++
+ static u16 red2[] __read_mostly = {
+     0x0000, 0xaaaa
+ };
+@@ -254,9 +256,12 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
+ 				break;
+ 		}
+ 	}
+-	if (rc == 0)
++	if (rc == 0) {
+ 		fb_copy_cmap(cmap, &info->cmap);
+-
++		if (fbcon_decor_active(info, vc_cons[fg_console].d) &&
++		    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
++			fbcon_decor_fix_pseudo_pal(info, vc_cons[fg_console].d);
++	}
+ 	return rc;
+ }
+ 
+diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
+index 76c1ad9..fafc0af 100644
+--- a/drivers/video/fbdev/core/fbmem.c
++++ b/drivers/video/fbdev/core/fbmem.c
+@@ -1251,15 +1251,6 @@ struct fb_fix_screeninfo32 {
+ 	u16			reserved[3];
+ };
+ 
+-struct fb_cmap32 {
+-	u32			start;
+-	u32			len;
+-	compat_caddr_t	red;
+-	compat_caddr_t	green;
+-	compat_caddr_t	blue;
+-	compat_caddr_t	transp;
+-};
+-
+ static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
+ 			  unsigned long arg)
+ {
+diff --git a/include/linux/console_decor.h b/include/linux/console_decor.h
+new file mode 100644
+index 0000000..1514355
+--- /dev/null
++++ b/include/linux/console_decor.h
+@@ -0,0 +1,46 @@
++#ifndef _LINUX_CONSOLE_DECOR_H_
++#define _LINUX_CONSOLE_DECOR_H_ 1
++
++/* A structure used by the framebuffer console decorations (drivers/video/console/fbcondecor.c) */
++struct vc_decor {
++	__u8 bg_color;				/* The color that is to be treated as transparent */
++	__u8 state;				/* Current decor state: 0 = off, 1 = on */
++	__u16 tx, ty;				/* Top left corner coordinates of the text field */
++	__u16 twidth, theight;			/* Width and height of the text field */
++	char *theme;
++};
++
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++
++struct vc_decor32 {
++	__u8 bg_color;				/* The color that is to be treated as transparent */
++	__u8 state;				/* Current decor state: 0 = off, 1 = on */
++	__u16 tx, ty;				/* Top left corner coordinates of the text field */
++	__u16 twidth, theight;			/* Width and height of the text field */
++	compat_uptr_t theme;
++};
++
++#define vc_decor_from_compat(to, from) \
++	(to).bg_color = (from).bg_color; \
++	(to).state    = (from).state; \
++	(to).tx       = (from).tx; \
++	(to).ty       = (from).ty; \
++	(to).twidth   = (from).twidth; \
++	(to).theight  = (from).theight; \
++	(to).theme    = compat_ptr((from).theme)
++
++#define vc_decor_to_compat(to, from) \
++	(to).bg_color = (from).bg_color; \
++	(to).state    = (from).state; \
++	(to).tx       = (from).tx; \
++	(to).ty       = (from).ty; \
++	(to).twidth   = (from).twidth; \
++	(to).theight  = (from).theight; \
++	(to).theme    = ptr_to_compat((from).theme)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++#endif
+diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
+index 6fd3c90..c649555 100644
+--- a/include/linux/console_struct.h
++++ b/include/linux/console_struct.h
+@@ -20,6 +20,7 @@ struct vt_struct;
+ struct uni_pagedir;
+ 
+ #define NPAR 16
++#include <linux/console_decor.h>
+ 
+ /*
+  * Example: vc_data of a console that was scrolled 3 lines down.
+@@ -140,6 +141,8 @@ struct vc_data {
+ 	struct uni_pagedir *vc_uni_pagedir;
+ 	struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
+ 	bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
++
++	struct vc_decor vc_decor;
+ 	/* additional information is in vt_kern.h */
+ };
+ 
+diff --git a/include/linux/fb.h b/include/linux/fb.h
+index a964d07..672cc64 100644
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -238,6 +238,34 @@ struct fb_deferred_io {
+ };
+ #endif
+ 
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++struct fb_image32 {
++	__u32 dx;			/* Where to place image */
++	__u32 dy;
++	__u32 width;			/* Size of image */
++	__u32 height;
++	__u32 fg_color;			/* Only used when a mono bitmap */
++	__u32 bg_color;
++	__u8  depth;			/* Depth of the image */
++	const compat_uptr_t data;	/* Pointer to image data */
++	struct fb_cmap32 cmap;		/* color map info */
++};
++
++#define fb_image_from_compat(to, from) \
++	(to).dx       = (from).dx; \
++	(to).dy       = (from).dy; \
++	(to).width    = (from).width; \
++	(to).height   = (from).height; \
++	(to).fg_color = (from).fg_color; \
++	(to).bg_color = (from).bg_color; \
++	(to).depth    = (from).depth; \
++	(to).data     = compat_ptr((from).data); \
++	fb_cmap_from_compat((to).cmap, (from).cmap)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
+ /*
+  * Frame buffer operations
+  *
+@@ -508,6 +536,9 @@ struct fb_info {
+ #define FBINFO_STATE_SUSPENDED	1
+ 	u32 state;			/* Hardware state i.e suspend */
+ 	void *fbcon_par;                /* fbcon use-only private area */
++
++	struct fb_image bgdecor;
++
+ 	/* From here on everything is device dependent */
+ 	void *par;
+ 	/* we need the PCI or similar aperture base/size not
+diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
+index fb795c3..4b57c67 100644
+--- a/include/uapi/linux/fb.h
++++ b/include/uapi/linux/fb.h
+@@ -8,6 +8,23 @@
+ 
+ #define FB_MAX			32	/* sufficient for now */
+ 
++struct fbcon_decor_iowrapper {
++	unsigned short vc;		/* Virtual console */
++	unsigned char origin;		/* Point of origin of the request */
++	void *data;
++};
++
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++struct fbcon_decor_iowrapper32 {
++	unsigned short vc;		/* Virtual console */
++	unsigned char origin;		/* Point of origin of the request */
++	compat_uptr_t data;
++};
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
+ /* ioctls
+    0x46 is 'F'								*/
+ #define FBIOGET_VSCREENINFO	0x4600
+@@ -35,6 +52,25 @@
+ #define FBIOGET_DISPINFO        0x4618
+ #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
+ 
++#define FBIOCONDECOR_SETCFG	_IOWR('F', 0x19, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_GETCFG	_IOR('F', 0x1A, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_SETSTATE	_IOWR('F', 0x1B, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_GETSTATE	_IOR('F', 0x1C, struct fbcon_decor_iowrapper)
++#define FBIOCONDECOR_SETPIC	_IOWR('F', 0x1D, struct fbcon_decor_iowrapper)
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++#define FBIOCONDECOR_SETCFG32	_IOWR('F', 0x19, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_GETCFG32	_IOR('F', 0x1A, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_SETSTATE32	_IOWR('F', 0x1B, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_GETSTATE32	_IOR('F', 0x1C, struct fbcon_decor_iowrapper32)
++#define FBIOCONDECOR_SETPIC32	_IOWR('F', 0x1D, struct fbcon_decor_iowrapper32)
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++#define FBCON_DECOR_THEME_LEN		128	/* Maximum length of a theme name */
++#define FBCON_DECOR_IO_ORIG_KERNEL	0	/* Kernel ioctl origin */
++#define FBCON_DECOR_IO_ORIG_USER	1	/* User ioctl origin */
++
+ #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
+ #define FB_TYPE_PLANES			1	/* Non interleaved planes */
+ #define FB_TYPE_INTERLEAVED_PLANES	2	/* Interleaved planes	*/
+@@ -277,6 +313,29 @@ struct fb_var_screeninfo {
+ 	__u32 reserved[4];		/* Reserved for future compatibility */
+ };
+ 
++#ifdef __KERNEL__
++#ifdef CONFIG_COMPAT
++struct fb_cmap32 {
++	__u32 start;
++	__u32 len;			/* Number of entries */
++	compat_uptr_t red;		/* Red values	*/
++	compat_uptr_t green;
++	compat_uptr_t blue;
++	compat_uptr_t transp;		/* transparency, can be NULL */
++};
++
++#define fb_cmap_from_compat(to, from) \
++	(to).start  = (from).start; \
++	(to).len    = (from).len; \
++	(to).red    = compat_ptr((from).red); \
++	(to).green  = compat_ptr((from).green); \
++	(to).blue   = compat_ptr((from).blue); \
++	(to).transp = compat_ptr((from).transp)
++
++#endif /* CONFIG_COMPAT */
++#endif /* __KERNEL__ */
++
++
+ struct fb_cmap {
+ 	__u32 start;			/* First entry	*/
+ 	__u32 len;			/* Number of entries */
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 6ee416e..d2c2425 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -149,6 +149,10 @@ static const int cap_last_cap = CAP_LAST_CAP;
+ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
+ #endif
+ 
++#ifdef CONFIG_FB_CON_DECOR
++extern char fbcon_decor_path[];
++#endif
++
+ #ifdef CONFIG_INOTIFY_USER
+ #include <linux/inotify.h>
+ #endif
+@@ -266,6 +270,15 @@ static struct ctl_table sysctl_base_table[] = {
+ 		.mode		= 0555,
+ 		.child		= dev_table,
+ 	},
++#ifdef CONFIG_FB_CON_DECOR
++	{
++		.procname	= "fbcondecor",
++		.data		= &fbcon_decor_path,
++		.maxlen		= KMOD_PATH_LEN,
++		.mode		= 0644,
++		.proc_handler	= &proc_dostring,
++	},
++#endif
+ 	{ }
+ };
+ 
Index: npl/kernel/linux_src/config
===================================================================
--- npl/kernel/linux_src/config	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/config	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,5 +1,5 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 4.4.27 Kernel Configuration
+# Linux/x86 4.9.149 Kernel Configuration
 #
 # CONFIG_64BIT is not set
@@ -7,11 +7,13 @@
 CONFIG_X86=y
 CONFIG_INSTRUCTION_DECODER=y
-CONFIG_PERF_EVENTS_INTEL_UNCORE=y
 CONFIG_OUTPUT_FORMAT="elf32-i386"
 CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 CONFIG_MMU=y
+CONFIG_ARCH_MMAP_RND_BITS_MIN=8
+CONFIG_ARCH_MMAP_RND_BITS_MAX=16
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
 CONFIG_NEED_DMA_MAP_STATE=y
 CONFIG_NEED_SG_DMA_LENGTH=y
@@ -36,11 +38,12 @@
 CONFIG_X86_32_SMP=y
 CONFIG_X86_32_LAZY_GS=y
-CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
 CONFIG_ARCH_SUPPORTS_UPROBES=y
 CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_DEBUG_RODATA=y
 CONFIG_PGTABLE_LEVELS=3
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 CONFIG_IRQ_WORK=y
 CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_THREAD_INFO_IN_TASK=y
 
 #
@@ -71,5 +74,5 @@
 CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_CROSS_MEMORY_ATTACH=y
-# CONFIG_FHANDLE is not set
+CONFIG_FHANDLE=y
 CONFIG_USELIB=y
 # CONFIG_AUDIT is not set
@@ -134,22 +137,23 @@
 CONFIG_LOG_BUF_SHIFT=17
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+CONFIG_NMI_LOG_BUF_SHIFT=13
 CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
 CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
 CONFIG_CGROUPS=y
-# CONFIG_CGROUP_DEBUG is not set
-# CONFIG_CGROUP_FREEZER is not set
-# CONFIG_CGROUP_PIDS is not set
-CONFIG_CGROUP_DEVICE=y
-CONFIG_CPUSETS=y
-CONFIG_PROC_PID_CPUSET=y
-CONFIG_CGROUP_CPUACCT=y
 # CONFIG_MEMCG is not set
-# CONFIG_CGROUP_HUGETLB is not set
-# CONFIG_CGROUP_PERF is not set
+# CONFIG_BLK_CGROUP is not set
 CONFIG_CGROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_CFS_BANDWIDTH is not set
 CONFIG_RT_GROUP_SCHED=y
-# CONFIG_BLK_CGROUP is not set
+# CONFIG_CGROUP_PIDS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_HUGETLB is not set
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_DEBUG is not set
 # CONFIG_CHECKPOINT_RESTORE is not set
 CONFIG_NAMESPACES=y
@@ -170,4 +174,5 @@
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
@@ -184,5 +189,8 @@
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
+CONFIG_KALLSYMS_BASE_RELATIVE=y
 CONFIG_PRINTK=y
+CONFIG_PRINTK_NMI=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
@@ -212,7 +220,9 @@
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
+# CONFIG_SLAB_FREELIST_RANDOM is not set
 # CONFIG_SYSTEM_DATA_VERIFICATION is not set
 # CONFIG_PROFILING is not set
 CONFIG_KEXEC_CORE=y
+CONFIG_HOTPLUG_SMT=y
 CONFIG_HAVE_OPROFILE=y
 CONFIG_OPROFILE_NMI_TIMER=y
@@ -229,6 +239,6 @@
 CONFIG_HAVE_OPTPROBES=y
 CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_HAVE_NMI=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
-CONFIG_HAVE_DMA_ATTRS=y
 CONFIG_HAVE_DMA_CONTIGUOUS=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
@@ -250,4 +260,6 @@
 CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
 CONFIG_SECCOMP_FILTER=y
+CONFIG_HAVE_GCC_PLUGINS=y
+# CONFIG_GCC_PLUGINS is not set
 CONFIG_HAVE_CC_STACKPROTECTOR=y
 # CONFIG_CC_STACKPROTECTOR is not set
@@ -255,4 +267,5 @@
 # CONFIG_CC_STACKPROTECTOR_REGULAR is not set
 # CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
 CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
 CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
@@ -260,8 +273,15 @@
 CONFIG_MODULES_USE_ELF_REL=y
 CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+CONFIG_HAVE_EXIT_THREAD=y
+CONFIG_ARCH_MMAP_RND_BITS=8
 CONFIG_HAVE_COPY_THREAD_TLS=y
+# CONFIG_HAVE_ARCH_HASH is not set
+# CONFIG_ISA_BUS_API is not set
 CONFIG_CLONE_BACKWARDS=y
 CONFIG_OLD_SIGSUSPEND3=y
 CONFIG_OLD_SIGACTION=y
+# CONFIG_CPU_NO_EFFICIENT_FFS is not set
+# CONFIG_HAVE_ARCH_VMAP_STACK is not set
 
 #
@@ -281,4 +301,5 @@
 # CONFIG_MODULE_SIG is not set
 # CONFIG_MODULE_COMPRESS is not set
+# CONFIG_TRIM_UNUSED_KSYMS is not set
 CONFIG_MODULES_TREE_LOOKUP=y
 CONFIG_BLOCK=y
@@ -312,4 +333,5 @@
 # CONFIG_SYSV68_PARTITION is not set
 # CONFIG_CMDLINE_PARTITION is not set
+CONFIG_BLK_MQ_PCI=y
 
 #
@@ -346,10 +368,13 @@
 CONFIG_SMP=y
 CONFIG_X86_FEATURE_NAMES=y
+CONFIG_X86_FAST_FEATURE_TESTS=y
 CONFIG_X86_MPPARSE=y
 CONFIG_X86_BIGSMP=y
+# CONFIG_GOLDFISH is not set
+CONFIG_RETPOLINE=y
 # CONFIG_X86_EXTENDED_PLATFORM is not set
 CONFIG_X86_INTEL_LPSS=y
 # CONFIG_X86_AMD_PLATFORM_DEVICE is not set
-CONFIG_IOSF_MBI=m
+CONFIG_IOSF_MBI=y
 CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
 # CONFIG_X86_32_IRIS is not set
@@ -423,4 +448,12 @@
 # CONFIG_X86_MCE_INJECT is not set
 CONFIG_X86_THERMAL_VECTOR=y
+
+#
+# Performance monitoring
+#
+CONFIG_PERF_EVENTS_INTEL_UNCORE=y
+CONFIG_PERF_EVENTS_INTEL_RAPL=y
+CONFIG_PERF_EVENTS_INTEL_CSTATE=y
+# CONFIG_PERF_EVENTS_AMD_POWER is not set
 # CONFIG_X86_LEGACY_VM86 is not set
 # CONFIG_VM86 is not set
@@ -467,5 +500,4 @@
 CONFIG_MIGRATION=y
 CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
@@ -478,4 +510,5 @@
 CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
 # CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
+CONFIG_TRANSPARENT_HUGE_PAGECACHE=y
 CONFIG_CLEANCACHE=y
 CONFIG_FRONTSWAP=y
@@ -484,4 +517,5 @@
 CONFIG_ZPOOL=m
 CONFIG_ZBUD=m
+# CONFIG_Z3FOLD is not set
 CONFIG_ZSMALLOC=m
 # CONFIG_PGTABLE_MAPPING is not set
@@ -554,6 +588,7 @@
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_CPU_FREQ_PSS=y
+CONFIG_ACPI_PROCESSOR_CSTATE=y
 CONFIG_ACPI_PROCESSOR_IDLE=y
-CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_PROCESSOR=y
 CONFIG_ACPI_IPMI=m
 CONFIG_ACPI_HOTPLUG_CPU=y
@@ -561,5 +596,6 @@
 CONFIG_ACPI_THERMAL=m
 # CONFIG_ACPI_CUSTOM_DSDT is not set
-# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
+CONFIG_ACPI_TABLE_UPGRADE=y
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_PCI_SLOT=y
@@ -575,6 +611,8 @@
 CONFIG_HAVE_ACPI_APEI_NMI=y
 # CONFIG_ACPI_APEI is not set
+# CONFIG_DPTF_POWER is not set
 # CONFIG_ACPI_EXTLOG is not set
 # CONFIG_PMIC_OPREGION is not set
+# CONFIG_ACPI_CONFIGFS is not set
 # CONFIG_SFI is not set
 # CONFIG_APM is not set
@@ -584,7 +622,7 @@
 #
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
 CONFIG_CPU_FREQ_GOV_COMMON=y
-CONFIG_CPU_FREQ_STAT=m
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_STAT is not set
 # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
 # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
@@ -592,4 +630,5 @@
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
@@ -597,4 +636,5 @@
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
 
 #
@@ -658,4 +698,6 @@
 # CONFIG_PCIEASPM_PERFORMANCE is not set
 CONFIG_PCIE_PME=y
+# CONFIG_PCIE_DPC is not set
+# CONFIG_PCIE_PTM is not set
 CONFIG_PCI_BUS_ADDR_T_64BIT=y
 CONFIG_PCI_MSI=y
@@ -669,8 +711,10 @@
 CONFIG_PCI_PASID=y
 CONFIG_PCI_LABEL=y
+# CONFIG_HOTPLUG_PCI is not set
 
 #
 # PCI host controller drivers
 #
+# CONFIG_PCIE_DW_PLAT is not set
 CONFIG_ISA_DMA_API=y
 # CONFIG_ISA is not set
@@ -681,5 +725,4 @@
 CONFIG_AMD_NB=y
 # CONFIG_PCCARD is not set
-# CONFIG_HOTPLUG_PCI is not set
 # CONFIG_RAPIDIO is not set
 # CONFIG_X86_SYSFB is not set
@@ -689,4 +732,5 @@
 #
 CONFIG_BINFMT_ELF=y
+CONFIG_ELFCORE=y
 CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
 CONFIG_BINFMT_SCRIPT=y
@@ -699,4 +743,5 @@
 CONFIG_NET=y
 CONFIG_NET_INGRESS=y
+CONFIG_NET_EGRESS=y
 
 #
@@ -747,8 +792,8 @@
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_LRO=y
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_DIAG_DESTROY is not set
 CONFIG_TCP_CONG_ADVANCED=y
 CONFIG_TCP_CONG_BIC=y
@@ -759,4 +804,5 @@
 CONFIG_TCP_CONG_HYBLA=y
 CONFIG_TCP_CONG_VEGAS=y
+# CONFIG_TCP_CONG_NV is not set
 CONFIG_TCP_CONG_SCALABLE=y
 CONFIG_TCP_CONG_LP=y
@@ -766,4 +812,5 @@
 # CONFIG_TCP_CONG_DCTCP is not set
 # CONFIG_TCP_CONG_CDG is not set
+# CONFIG_TCP_CONG_BBR is not set
 # CONFIG_DEFAULT_BIC is not set
 CONFIG_DEFAULT_CUBIC=y
@@ -797,4 +844,6 @@
 CONFIG_IPV6_TUNNEL=m
 # CONFIG_IPV6_GRE is not set
+# CONFIG_IPV6_FOU is not set
+# CONFIG_IPV6_FOU_TUNNEL is not set
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
@@ -865,4 +914,5 @@
 CONFIG_NETFILTER_XT_MARK=m
 CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_SET=m
 
 #
@@ -943,5 +993,21 @@
 CONFIG_NETFILTER_XT_MATCH_TIME=m
 CONFIG_NETFILTER_XT_MATCH_U32=m
-# CONFIG_IP_SET is not set
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
 # CONFIG_IP_VS is not set
 
@@ -951,5 +1017,4 @@
 CONFIG_NF_DEFRAG_IPV4=m
 CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_CONNTRACK_PROC_COMPAT=y
 CONFIG_NF_DUP_IPV4=m
 # CONFIG_NF_LOG_ARP is not set
@@ -1045,4 +1110,5 @@
 CONFIG_BRIDGE_VLAN_FILTERING=y
 CONFIG_HAVE_NET_DSA=y
+# CONFIG_NET_DSA is not set
 CONFIG_VLAN_8021Q=m
 # CONFIG_VLAN_8021Q_GVRP is not set
@@ -1105,4 +1171,5 @@
 CONFIG_NET_CLS_BPF=m
 # CONFIG_NET_CLS_FLOWER is not set
+# CONFIG_NET_CLS_MATCHALL is not set
 CONFIG_NET_EMATCH=y
 CONFIG_NET_EMATCH_STACK=32
@@ -1112,4 +1179,5 @@
 CONFIG_NET_EMATCH_META=m
 CONFIG_NET_EMATCH_TEXT=m
+# CONFIG_NET_EMATCH_IPSET is not set
 CONFIG_NET_CLS_ACT=y
 CONFIG_NET_ACT_POLICE=m
@@ -1126,4 +1194,7 @@
 # CONFIG_NET_ACT_BPF is not set
 CONFIG_NET_ACT_CONNMARK=m
+# CONFIG_NET_ACT_SKBMOD is not set
+# CONFIG_NET_ACT_IFE is not set
+# CONFIG_NET_ACT_TUNNEL_KEY is not set
 CONFIG_NET_CLS_IND=y
 CONFIG_NET_SCH_FIFO=y
@@ -1136,5 +1207,5 @@
 CONFIG_VSOCKETS=m
 CONFIG_VMWARE_VMCI_VSOCKETS=m
-CONFIG_NETLINK_MMAP=y
+# CONFIG_VIRTIO_VSOCKETS is not set
 # CONFIG_NETLINK_DIAG is not set
 CONFIG_MPLS=y
@@ -1144,7 +1215,9 @@
 # CONFIG_NET_SWITCHDEV is not set
 # CONFIG_NET_L3_MASTER_DEV is not set
+# CONFIG_NET_NCSI is not set
 CONFIG_RPS=y
 CONFIG_RFS_ACCEL=y
 CONFIG_XPS=y
+CONFIG_SOCK_CGROUP_DATA=y
 # CONFIG_CGROUP_NET_PRIO is not set
 CONFIG_CGROUP_NET_CLASSID=y
@@ -1162,4 +1235,6 @@
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
+# CONFIG_AF_KCM is not set
+# CONFIG_STREAM_PARSER is not set
 CONFIG_FIB_RULES=y
 CONFIG_WIRELESS=y
@@ -1178,4 +1253,7 @@
 # CONFIG_NFC is not set
 # CONFIG_LWTUNNEL is not set
+CONFIG_DST_CACHE=y
+# CONFIG_NET_DEVLINK is not set
+CONFIG_MAY_USE_DEVLINK=y
 
 #
@@ -1200,4 +1278,5 @@
 # CONFIG_GENERIC_CPU_DEVICES is not set
 CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
 CONFIG_REGMAP=y
 CONFIG_REGMAP_I2C=m
@@ -1299,5 +1378,4 @@
 # CONFIG_MTD_SM_COMMON is not set
 # CONFIG_MTD_NAND_DENALI_PCI is not set
-# CONFIG_MTD_NAND_DENALI_DT is not set
 # CONFIG_MTD_NAND_GPIO is not set
 # CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
@@ -1311,4 +1389,5 @@
 # CONFIG_MTD_NAND_PLATFORM is not set
 # CONFIG_MTD_NAND_HISI504 is not set
+# CONFIG_MTD_NAND_MTK is not set
 CONFIG_MTD_ONENAND=m
 # CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
@@ -1323,4 +1402,5 @@
 CONFIG_MTD_QINFO_PROBE=m
 CONFIG_MTD_SPI_NOR=m
+# CONFIG_MTD_MT81xx_NOR is not set
 CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
 CONFIG_MTD_UBI=m
@@ -1345,5 +1425,4 @@
 CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
 CONFIG_ZRAM=m
-CONFIG_ZRAM_LZ4_COMPRESS=y
 CONFIG_BLK_CPQ_CISS_DA=m
 CONFIG_CISS_SCSI_TAPE=y
@@ -1366,5 +1445,8 @@
 # CONFIG_BLK_DEV_RBD is not set
 CONFIG_BLK_DEV_RSXX=m
+CONFIG_NVME_CORE=m
 CONFIG_BLK_DEV_NVME=m
+# CONFIG_BLK_DEV_NVME_SCSI is not set
+# CONFIG_NVME_TARGET is not set
 
 #
@@ -1385,5 +1467,4 @@
 # CONFIG_ISL29020 is not set
 # CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_SENSORS_BH1780 is not set
 # CONFIG_SENSORS_BH1770 is not set
 # CONFIG_SENSORS_APDS990X is not set
@@ -1391,5 +1472,4 @@
 # CONFIG_DS1682 is not set
 CONFIG_VMWARE_BALLOON=m
-# CONFIG_BMP085_I2C is not set
 # CONFIG_PCH_PHUB is not set
 # CONFIG_USB_SWITCH_FSA9480 is not set
@@ -1416,4 +1496,7 @@
 #
 # CONFIG_ALTERA_STAPL is not set
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
 CONFIG_VMWARE_VMCI=m
 
@@ -1427,4 +1510,8 @@
 
 #
+# VOP Bus Driver
+#
+
+#
 # Intel MIC Host Driver
 #
@@ -1440,77 +1527,14 @@
 #
 # Intel MIC Coprocessor State Management (COSM) Drivers
+#
+
+#
+# VOP Driver
 #
 # CONFIG_ECHO is not set
 # CONFIG_CXL_BASE is not set
-# CONFIG_CXL_KERNEL_API is not set
-# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_AFU_DRIVER_OPS is not set
 CONFIG_HAVE_IDE=y
-CONFIG_IDE=y
-
-#
-# Please see Documentation/ide/ide.txt for help/info on IDE drives
-#
-CONFIG_IDE_XFER_MODE=y
-CONFIG_IDE_TIMINGS=y
-CONFIG_IDE_ATAPI=y
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_IDE_GD=y
-CONFIG_IDE_GD_ATA=y
-# CONFIG_IDE_GD_ATAPI is not set
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEACPI=y
-CONFIG_IDE_TASK_IOCTL=y
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=m
-CONFIG_BLK_DEV_PLATFORM=m
-CONFIG_BLK_DEV_CMD640=y
-CONFIG_BLK_DEV_CMD640_ENHANCED=y
-CONFIG_BLK_DEV_IDEPNP=y
-CONFIG_BLK_DEV_IDEDMA_SFF=y
-
-#
-# PCI IDE chipsets support
-#
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=m
-CONFIG_BLK_DEV_OPTI621=m
-CONFIG_BLK_DEV_RZ1000=m
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_AEC62XX=m
-CONFIG_BLK_DEV_ALI15X3=m
-CONFIG_BLK_DEV_AMD74XX=m
-CONFIG_BLK_DEV_ATIIXP=m
-CONFIG_BLK_DEV_CMD64X=m
-CONFIG_BLK_DEV_TRIFLEX=m
-# CONFIG_BLK_DEV_CS5520 is not set
-CONFIG_BLK_DEV_CS5530=m
-CONFIG_BLK_DEV_CS5535=m
-CONFIG_BLK_DEV_CS5536=m
-CONFIG_BLK_DEV_HPT366=m
-CONFIG_BLK_DEV_JMICRON=m
-CONFIG_BLK_DEV_SC1200=m
-CONFIG_BLK_DEV_PIIX=m
-CONFIG_BLK_DEV_IT8172=m
-CONFIG_BLK_DEV_IT8213=m
-CONFIG_BLK_DEV_IT821X=m
-CONFIG_BLK_DEV_NS87415=m
-CONFIG_BLK_DEV_PDC202XX_OLD=m
-CONFIG_BLK_DEV_PDC202XX_NEW=m
-CONFIG_BLK_DEV_SVWKS=m
-CONFIG_BLK_DEV_SIIMAGE=m
-CONFIG_BLK_DEV_SIS5513=m
-CONFIG_BLK_DEV_SLC90E66=m
-CONFIG_BLK_DEV_TRM290=m
-CONFIG_BLK_DEV_VIA82CXXX=m
-CONFIG_BLK_DEV_TC86C001=m
-CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDE is not set
 
 #
@@ -1595,7 +1619,10 @@
 CONFIG_SCSI_MPT3SAS_MAX_SGE=128
 CONFIG_SCSI_MPT2SAS=m
+# CONFIG_SCSI_SMARTPQI is not set
 CONFIG_SCSI_UFSHCD=m
 CONFIG_SCSI_UFSHCD_PCI=m
+# CONFIG_SCSI_UFS_DWC_TC_PCI is not set
 CONFIG_SCSI_UFSHCD_PLATFORM=m
+# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set
 CONFIG_SCSI_HPTIOP=m
 CONFIG_SCSI_BUSLOGIC=m
@@ -1673,4 +1700,7 @@
 #
 CONFIG_ATA_PIIX=m
+CONFIG_SATA_DWC=m
+# CONFIG_SATA_DWC_OLD_DMA is not set
+# CONFIG_SATA_DWC_DEBUG is not set
 CONFIG_SATA_MV=m
 CONFIG_SATA_NV=m
@@ -1758,12 +1788,11 @@
 # CONFIG_DM_DEBUG is not set
 CONFIG_DM_BUFIO=m
+# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set
 CONFIG_DM_BIO_PRISON=m
 CONFIG_DM_PERSISTENT_DATA=m
-# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set
 CONFIG_DM_CRYPT=m
 CONFIG_DM_SNAPSHOT=m
 # CONFIG_DM_THIN_PROVISIONING is not set
 CONFIG_DM_CACHE=m
-CONFIG_DM_CACHE_MQ=m
 CONFIG_DM_CACHE_SMQ=m
 CONFIG_DM_CACHE_CLEANER=m
@@ -1809,7 +1838,8 @@
 CONFIG_MACVLAN=m
 # CONFIG_MACVTAP is not set
-# CONFIG_IPVLAN is not set
 CONFIG_VXLAN=m
 # CONFIG_GENEVE is not set
+# CONFIG_GTP is not set
+# CONFIG_MACSEC is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
@@ -1832,14 +1862,8 @@
 # CAIF transport drivers
 #
-CONFIG_VHOST_NET=m
-CONFIG_VHOST_RING=m
-CONFIG_VHOST=m
-# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
 
 #
 # Distributed Switch Architecture drivers
 #
-# CONFIG_NET_DSA_MV88E6XXX is not set
-# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
 CONFIG_ETHERNET=y
 CONFIG_MDIO=m
@@ -1855,4 +1879,6 @@
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
 CONFIG_ALTERA_TSE=m
+CONFIG_NET_VENDOR_AMAZON=y
+# CONFIG_ENA_ETHERNET is not set
 CONFIG_NET_VENDOR_AMD=y
 CONFIG_AMD8111_ETH=m
@@ -1879,5 +1905,4 @@
 CONFIG_TIGON3=m
 CONFIG_BNX2X=m
-# CONFIG_BNX2X_VXLAN is not set
 CONFIG_BNXT=m
 CONFIG_NET_VENDOR_BROCADE=y
@@ -1890,4 +1915,5 @@
 CONFIG_CHELSIO_T4=m
 # CONFIG_CHELSIO_T4VF is not set
+CONFIG_CHELSIO_LIB=m
 CONFIG_NET_VENDOR_CISCO=y
 CONFIG_ENIC=m
@@ -1914,5 +1940,4 @@
 CONFIG_BE2NET=m
 CONFIG_BE2NET_HWMON=y
-CONFIG_BE2NET_VXLAN=y
 CONFIG_NET_VENDOR_EZCHIP=y
 CONFIG_NET_VENDOR_EXAR=y
@@ -1925,4 +1950,5 @@
 CONFIG_E1000=m
 CONFIG_E1000E=m
+CONFIG_E1000E_HWTS=y
 CONFIG_IGB=m
 CONFIG_IGB_HWMON=y
@@ -1930,16 +1956,14 @@
 CONFIG_IXGB=m
 CONFIG_IXGBE=m
-CONFIG_IXGBE_VXLAN=y
 CONFIG_IXGBE_HWMON=y
 CONFIG_IXGBEVF=m
 CONFIG_I40E=m
-CONFIG_I40E_VXLAN=y
 CONFIG_I40EVF=m
 CONFIG_FM10K=m
-CONFIG_FM10K_VXLAN=y
 CONFIG_NET_VENDOR_I825XX=y
 CONFIG_JME=m
 CONFIG_NET_VENDOR_MARVELL=y
 CONFIG_MVMDIO=m
+# CONFIG_MVNETA_BM is not set
 CONFIG_SKGE=m
 # CONFIG_SKGE_GENESIS is not set
@@ -1947,5 +1971,4 @@
 CONFIG_NET_VENDOR_MELLANOX=y
 CONFIG_MLX4_EN=m
-CONFIG_MLX4_EN_VXLAN=y
 CONFIG_MLX4_CORE=m
 CONFIG_MLX4_DEBUG=y
@@ -1953,4 +1976,5 @@
 # CONFIG_MLX5_CORE_EN is not set
 CONFIG_MLXSW_CORE=m
+CONFIG_MLXSW_CORE_HWMON=y
 CONFIG_MLXSW_PCI=m
 CONFIG_NET_VENDOR_MICREL=y
@@ -1964,4 +1988,6 @@
 CONFIG_NATSEMI=m
 CONFIG_NS83820=m
+CONFIG_NET_VENDOR_NETRONOME=y
+# CONFIG_NFP_NETVF is not set
 CONFIG_NET_VENDOR_8390=y
 CONFIG_NE2K_PCI=m
@@ -1977,5 +2003,4 @@
 CONFIG_QLA3XXX=m
 CONFIG_QLCNIC=m
-# CONFIG_QLCNIC_VXLAN is not set
 CONFIG_QLCNIC_HWMON=y
 CONFIG_QLGE=m
@@ -1984,4 +2009,5 @@
 # CONFIG_QEDE is not set
 CONFIG_NET_VENDOR_QUALCOMM=y
+# CONFIG_QCOM_EMAC is not set
 CONFIG_NET_VENDOR_REALTEK=y
 CONFIG_8139CP=m
@@ -2043,36 +2069,44 @@
 # CONFIG_NET_SB1000 is not set
 CONFIG_PHYLIB=m
+CONFIG_SWPHY=y
+
+#
+# MDIO bus device drivers
+#
+# CONFIG_MDIO_BCM_UNIMAC is not set
+CONFIG_MDIO_BITBANG=m
+CONFIG_MDIO_GPIO=m
 
 #
 # MII PHY device drivers
 #
+CONFIG_AMD_PHY=m
 # CONFIG_AQUANTIA_PHY is not set
 # CONFIG_AT803X_PHY is not set
-CONFIG_AMD_PHY=m
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-# CONFIG_TERANETICS_PHY is not set
-CONFIG_SMSC_PHY=m
+CONFIG_BCM7XXX_PHY=m
+# CONFIG_BCM87XX_PHY is not set
 CONFIG_BCM_NET_PHYLIB=m
 CONFIG_BROADCOM_PHY=m
-CONFIG_BCM7XXX_PHY=m
-# CONFIG_BCM87XX_PHY is not set
-CONFIG_ICPLUS_PHY=m
-CONFIG_REALTEK_PHY=m
-CONFIG_NATIONAL_PHY=m
-CONFIG_STE10XP=m
-CONFIG_LSI_ET1011C_PHY=m
-CONFIG_MICREL_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_DAVICOM_PHY=m
 # CONFIG_DP83848_PHY is not set
 # CONFIG_DP83867_PHY is not set
+CONFIG_FIXED_PHY=m
+CONFIG_ICPLUS_PHY=m
+# CONFIG_INTEL_XWAY_PHY is not set
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_MICREL_PHY=m
 # CONFIG_MICROCHIP_PHY is not set
-CONFIG_FIXED_PHY=m
-CONFIG_MDIO_BITBANG=m
-CONFIG_MDIO_GPIO=m
-# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MICROSEMI_PHY is not set
+CONFIG_NATIONAL_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_STE10XP=m
+# CONFIG_TERANETICS_PHY is not set
+CONFIG_VITESSE_PHY=m
+# CONFIG_XILINX_GMII2RGMII is not set
 CONFIG_PPP=m
 CONFIG_PPP_BSDCOMP=m
@@ -2155,4 +2189,5 @@
 CONFIG_MOUSE_PS2=y
 CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_BYD=y
 CONFIG_MOUSE_PS2_LOGIPS2PP=y
 CONFIG_MOUSE_PS2_SYNAPTICS=y
@@ -2188,4 +2223,5 @@
 # CONFIG_INPUT_GPIO_BEEPER is not set
 # CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_GPIO_DECODER is not set
 # CONFIG_INPUT_WISTRON_BTNS is not set
 # CONFIG_INPUT_ATLAS_BTNS is not set
@@ -2207,4 +2243,5 @@
 # CONFIG_INPUT_DRV2665_HAPTICS is not set
 # CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_RMI4_CORE is not set
 
 #
@@ -2237,5 +2274,4 @@
 CONFIG_VT_HW_CONSOLE_BINDING=y
 CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -2254,4 +2290,5 @@
 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_PNP=y
+# CONFIG_SERIAL_8250_FINTEK is not set
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DMA=y
@@ -2267,6 +2304,7 @@
 # CONFIG_SERIAL_8250_DW is not set
 # CONFIG_SERIAL_8250_RT288X is not set
-# CONFIG_SERIAL_8250_FINTEK is not set
-# CONFIG_SERIAL_8250_MID is not set
+CONFIG_SERIAL_8250_LPSS=y
+CONFIG_SERIAL_8250_MID=y
+# CONFIG_SERIAL_8250_MOXA is not set
 
 #
@@ -2294,5 +2332,4 @@
 CONFIG_IPMI_DEVICE_INTERFACE=m
 CONFIG_IPMI_SI=m
-# CONFIG_IPMI_SI_PROBE_DEFAULTS is not set
 CONFIG_IPMI_SSIF=m
 CONFIG_IPMI_WATCHDOG=m
@@ -2372,4 +2409,5 @@
 CONFIG_I2C_DESIGNWARE_PLATFORM=m
 CONFIG_I2C_DESIGNWARE_PCI=m
+# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set
 CONFIG_I2C_EG20T=m
 CONFIG_I2C_EMEV2=m
@@ -2395,5 +2433,6 @@
 CONFIG_SCx200_ACB=m
 # CONFIG_I2C_STUB is not set
-# CONFIG_I2C_SLAVE is not set
+CONFIG_I2C_SLAVE=y
+# CONFIG_I2C_SLAVE_EEPROM is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
@@ -2408,5 +2447,4 @@
 CONFIG_PPS=m
 # CONFIG_PPS_DEBUG is not set
-# CONFIG_NTP_PPS is not set
 
 #
@@ -2440,7 +2478,5 @@
 # CONFIG_PINCTRL_BROXTON is not set
 # CONFIG_PINCTRL_SUNRISEPOINT is not set
-CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 CONFIG_GPIOLIB=y
-CONFIG_GPIO_DEVRES=y
 CONFIG_GPIO_ACPI=y
 # CONFIG_GPIO_SYSFS is not set
@@ -2454,4 +2490,5 @@
 # CONFIG_GPIO_ICH is not set
 # CONFIG_GPIO_LYNXPOINT is not set
+# CONFIG_GPIO_MOCKUP is not set
 # CONFIG_GPIO_VX855 is not set
 # CONFIG_GPIO_ZX is not set
@@ -2460,5 +2497,4 @@
 # Port-mapped I/O GPIO drivers
 #
-# CONFIG_GPIO_104_IDIO_16 is not set
 # CONFIG_GPIO_F7188X is not set
 # CONFIG_GPIO_IT87 is not set
@@ -2474,4 +2510,6 @@
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_TPIC2810 is not set
+# CONFIG_GPIO_TS4900 is not set
 
 #
@@ -2484,5 +2522,4 @@
 # CONFIG_GPIO_AMD8111 is not set
 # CONFIG_GPIO_BT8XX is not set
-# CONFIG_GPIO_INTEL_MID is not set
 # CONFIG_GPIO_ML_IOH is not set
 # CONFIG_GPIO_PCH is not set
@@ -2492,5 +2529,4 @@
 # SPI or I2C GPIO expanders
 #
-# CONFIG_GPIO_MCP23S08 is not set
 
 #
@@ -2498,4 +2534,7 @@
 #
 # CONFIG_W1 is not set
+# CONFIG_POWER_AVS is not set
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_RESTART is not set
 CONFIG_POWER_SUPPLY=y
 # CONFIG_POWER_SUPPLY_DEBUG is not set
@@ -2520,7 +2559,4 @@
 # CONFIG_BATTERY_GAUGE_LTC2941 is not set
 # CONFIG_CHARGER_RT9455 is not set
-CONFIG_POWER_RESET=y
-# CONFIG_POWER_RESET_RESTART is not set
-# CONFIG_POWER_AVS is not set
 CONFIG_HWMON=m
 CONFIG_HWMON_VID=m
@@ -2576,4 +2612,5 @@
 CONFIG_SENSORS_LINEAGE=m
 CONFIG_SENSORS_LTC2945=m
+# CONFIG_SENSORS_LTC2990 is not set
 CONFIG_SENSORS_LTC4151=m
 CONFIG_SENSORS_LTC4215=m
@@ -2591,5 +2628,4 @@
 CONFIG_SENSORS_MAX6697=m
 CONFIG_SENSORS_MAX31790=m
-CONFIG_SENSORS_HTU21=m
 CONFIG_SENSORS_MCP3021=m
 CONFIG_SENSORS_LM63=m
@@ -2621,4 +2657,5 @@
 CONFIG_SENSORS_LM25066=m
 CONFIG_SENSORS_LTC2978=m
+# CONFIG_SENSORS_LTC3815 is not set
 CONFIG_SENSORS_MAX16064=m
 # CONFIG_SENSORS_MAX20751 is not set
@@ -2631,4 +2668,5 @@
 CONFIG_SENSORS_SHT15=m
 CONFIG_SENSORS_SHT21=m
+# CONFIG_SENSORS_SHT3x is not set
 CONFIG_SENSORS_SHTC1=m
 CONFIG_SENSORS_SIS5595=m
@@ -2648,4 +2686,5 @@
 CONFIG_SENSORS_INA209=m
 CONFIG_SENSORS_INA2XX=m
+# CONFIG_SENSORS_INA3221 is not set
 CONFIG_SENSORS_TC74=m
 CONFIG_SENSORS_THMC50=m
@@ -2689,4 +2728,8 @@
 CONFIG_X86_PKG_TEMP_THERMAL=m
 # CONFIG_INTEL_SOC_DTS_THERMAL is not set
+
+#
+# ACPI INT340X thermal drivers
+#
 # CONFIG_INT340X_THERMAL is not set
 CONFIG_INTEL_PCH_THERMAL=m
@@ -2702,5 +2745,4 @@
 CONFIG_SSB_PCIHOST=y
 # CONFIG_SSB_B43_PCI_BRIDGE is not set
-# CONFIG_SSB_HOST_SOC is not set
 # CONFIG_SSB_DEBUG is not set
 CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
@@ -2720,6 +2762,11 @@
 # CONFIG_MFD_CS5535 is not set
 # CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_AXP20X_I2C is not set
 # CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
 # CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_EXYNOS_LPASS is not set
 # CONFIG_MFD_MC13XXX_I2C is not set
 # CONFIG_HTC_PASIC3 is not set
@@ -2731,4 +2778,9 @@
 # CONFIG_MFD_JANZ_CMODIO is not set
 # CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX8907 is not set
 # CONFIG_MFD_MT6397 is not set
 # CONFIG_MFD_MENF21BMC is not set
@@ -2738,6 +2790,6 @@
 # CONFIG_MFD_RDC321X is not set
 # CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RT5033 is not set
 # CONFIG_MFD_RTSX_USB is not set
-# CONFIG_MFD_RN5T618 is not set
 # CONFIG_MFD_SI476X_CORE is not set
 # CONFIG_MFD_SM501 is not set
@@ -2750,7 +2802,9 @@
 # CONFIG_TPS65010 is not set
 # CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65086 is not set
 # CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TI_LP873X is not set
 # CONFIG_MFD_TPS65218 is not set
-# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
 # CONFIG_MFD_WL1273_CORE is not set
 # CONFIG_MFD_LM3533 is not set
@@ -2773,4 +2827,8 @@
 
 #
+# ACP (Audio CoProcessor) Configuration
+#
+
+#
 # Frame buffer Devices
 #
@@ -2778,4 +2836,5 @@
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_CMDLINE=y
+CONFIG_FB_NOTIFY=y
 # CONFIG_FB_DDC is not set
 CONFIG_FB_BOOT_VESA_SUPPORT=y
@@ -2886,4 +2945,5 @@
 # CONFIG_HID_CHICONY is not set
 # CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_CMEDIA is not set
 # CONFIG_HID_CP2112 is not set
 # CONFIG_HID_CYPRESS is not set
@@ -2906,4 +2966,5 @@
 # CONFIG_HID_KENSINGTON is not set
 # CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LED is not set
 # CONFIG_HID_LENOVO is not set
 # CONFIG_HID_LOGITECH is not set
@@ -2941,4 +3002,5 @@
 # CONFIG_HID_ZYDACRON is not set
 # CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_ALPS is not set
 
 #
@@ -2967,5 +3029,4 @@
 # CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_ULPI_BUS is not set
 CONFIG_USB_MON=m
 # CONFIG_USB_WUSB_CBAF is not set
@@ -3121,5 +3182,4 @@
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -3137,6 +3197,8 @@
 CONFIG_USB_EZUSB_FX2=m
 # CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSIC_USB4604 is not set
 # CONFIG_USB_LINK_LAYER_TEST is not set
 # CONFIG_USB_CHAOSKEY is not set
+# CONFIG_UCSI is not set
 
 #
@@ -3148,4 +3210,5 @@
 # CONFIG_USB_ISP1301 is not set
 # CONFIG_USB_GADGET is not set
+# CONFIG_USB_ULPI_BUS is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
@@ -3163,4 +3226,5 @@
 # CONFIG_LEDS_GPIO is not set
 # CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP3952 is not set
 # CONFIG_LEDS_LP5521 is not set
 # CONFIG_LEDS_LP5523 is not set
@@ -3216,4 +3280,5 @@
 CONFIG_EDAC_I7300=m
 CONFIG_RTC_LIB=y
+CONFIG_RTC_MC146818_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -3240,15 +3305,12 @@
 # CONFIG_RTC_DRV_DS1374 is not set
 # CONFIG_RTC_DRV_DS1672 is not set
-# CONFIG_RTC_DRV_DS3232 is not set
 # CONFIG_RTC_DRV_MAX6900 is not set
 # CONFIG_RTC_DRV_RS5C372 is not set
 # CONFIG_RTC_DRV_ISL1208 is not set
 # CONFIG_RTC_DRV_ISL12022 is not set
-# CONFIG_RTC_DRV_ISL12057 is not set
 # CONFIG_RTC_DRV_X1205 is not set
-# CONFIG_RTC_DRV_PCF2127 is not set
 # CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
 # CONFIG_RTC_DRV_PCF8563 is not set
-# CONFIG_RTC_DRV_PCF85063 is not set
 # CONFIG_RTC_DRV_PCF8583 is not set
 # CONFIG_RTC_DRV_M41T80 is not set
@@ -3256,13 +3318,21 @@
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8010 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
 # CONFIG_RTC_DRV_RX8025 is not set
 # CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+
+#
+# SPI RTC drivers
+#
+CONFIG_RTC_I2C_AND_SPI=m
+
+#
+# SPI and I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
 # CONFIG_RTC_DRV_RV3029C2 is not set
-# CONFIG_RTC_DRV_RV8803 is not set
-
-#
-# SPI RTC drivers
-#
 
 #
@@ -3300,11 +3370,14 @@
 #
 CONFIG_DMA_ENGINE=y
-CONFIG_DMA_VIRTUAL_CHANNELS=m
+CONFIG_DMA_VIRTUAL_CHANNELS=y
 CONFIG_DMA_ACPI=y
 CONFIG_INTEL_IDMA64=m
 CONFIG_PCH_DMA=m
-CONFIG_DW_DMAC_CORE=m
+# CONFIG_QCOM_HIDMA_MGMT is not set
+# CONFIG_QCOM_HIDMA is not set
+CONFIG_DW_DMAC_CORE=y
 CONFIG_DW_DMAC=m
-CONFIG_DW_DMAC_PCI=m
+CONFIG_DW_DMAC_PCI=y
+CONFIG_HSU_DMA=y
 
 #
@@ -3313,4 +3386,9 @@
 # CONFIG_ASYNC_TX_DMA is not set
 # CONFIG_DMATEST is not set
+
+#
+# DMABUF options
+#
+# CONFIG_SYNC_FILE is not set
 # CONFIG_AUXDISPLAY is not set
 CONFIG_UIO=m
@@ -3356,6 +3434,9 @@
 #
 # CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_CS2000_CP is not set
+# CONFIG_COMMON_CLK_NXP is not set
 # CONFIG_COMMON_CLK_PXA is not set
-# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_PIC32 is not set
 
 #
@@ -3401,4 +3482,8 @@
 # SOC (System On Chip) specific Drivers
 #
+
+#
+# Broadcom SoC drivers
+#
 # CONFIG_SUNXI_SRAM is not set
 # CONFIG_SOC_TI is not set
@@ -3412,4 +3497,5 @@
 CONFIG_DEVFREQ_GOV_POWERSAVE=y
 CONFIG_DEVFREQ_GOV_USERSPACE=y
+# CONFIG_DEVFREQ_GOV_PASSIVE is not set
 
 #
@@ -3423,6 +3509,17 @@
 # CONFIG_VME_BUS is not set
 # CONFIG_PWM is not set
+CONFIG_ARM_GIC_MAX_NR=1
 # CONFIG_IPACK_BUS is not set
 CONFIG_RESET_CONTROLLER=y
+# CONFIG_RESET_ATH79 is not set
+# CONFIG_RESET_BERLIN is not set
+# CONFIG_RESET_LPC18XX is not set
+# CONFIG_RESET_MESON is not set
+# CONFIG_RESET_PISTACHIO is not set
+# CONFIG_RESET_SOCFPGA is not set
+# CONFIG_RESET_STM32 is not set
+# CONFIG_RESET_SUNXI is not set
+# CONFIG_TI_SYSCON_RESET is not set
+# CONFIG_RESET_ZYNQ is not set
 # CONFIG_FMC is not set
 
@@ -3448,8 +3545,7 @@
 # CONFIG_ANDROID is not set
 # CONFIG_LIBNVDIMM is not set
+# CONFIG_DEV_DAX is not set
 # CONFIG_NVMEM is not set
 # CONFIG_STM is not set
-# CONFIG_STM_DUMMY is not set
-# CONFIG_STM_SOURCE_CONSOLE is not set
 # CONFIG_INTEL_TH is not set
 
@@ -3470,4 +3566,5 @@
 CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
 # CONFIG_ISCSI_IBFT_FIND is not set
+# CONFIG_FW_CFG_SYSFS is not set
 # CONFIG_GOOGLE_FIRMWARE is not set
 
@@ -3480,4 +3577,6 @@
 # CONFIG_EFI_FAKE_MEMMAP is not set
 CONFIG_EFI_RUNTIME_WRAPPERS=y
+# CONFIG_EFI_CAPSULE_LOADER is not set
+# CONFIG_EFI_TEST is not set
 
 #
@@ -3485,4 +3584,5 @@
 #
 CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_FS_IOMAP=y
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
@@ -3512,5 +3612,8 @@
 CONFIG_FS_POSIX_ACL=y
 CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
 CONFIG_FILE_LOCKING=y
+CONFIG_MANDATORY_FILE_LOCKING=y
+# CONFIG_FS_ENCRYPTION is not set
 CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
@@ -3554,4 +3657,5 @@
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_FAT_DEFAULT_UTF8 is not set
 CONFIG_NTFS_FS=m
 # CONFIG_NTFS_DEBUG is not set
@@ -3576,4 +3680,5 @@
 CONFIG_EFIVAR_FS=m
 CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ORANGEFS_FS is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
@@ -3636,5 +3741,7 @@
 CONFIG_NFSD_V3_ACL=y
 CONFIG_NFSD_V4=y
-# CONFIG_NFSD_PNFS is not set
+# CONFIG_NFSD_BLOCKLAYOUT is not set
+# CONFIG_NFSD_SCSILAYOUT is not set
+# CONFIG_NFSD_FLEXFILELAYOUT is not set
 CONFIG_GRACE_PERIOD=m
 CONFIG_LOCKD=m
@@ -3653,5 +3760,4 @@
 # CONFIG_CIFS_UPCALL is not set
 CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
 CONFIG_CIFS_ACL=y
 CONFIG_CIFS_DEBUG=y
@@ -3750,4 +3856,5 @@
 #
 # CONFIG_PAGE_EXTENSION is not set
+# CONFIG_PAGE_POISONING is not set
 CONFIG_HAVE_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_MEMORY_INIT=y
@@ -3777,9 +3884,7 @@
 # CONFIG_TORTURE_TEST is not set
 CONFIG_RCU_CPU_STALL_TIMEOUT=60
-CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
 CONFIG_USER_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
@@ -3799,5 +3904,8 @@
 # CONFIG_TEST_KSTRTOX is not set
 # CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_BITMAP is not set
+# CONFIG_TEST_UUID is not set
 # CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_HASH is not set
 # CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
 # CONFIG_DMA_API_DEBUG is not set
@@ -3811,5 +3919,10 @@
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set
+# CONFIG_UBSAN is not set
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
 CONFIG_STRICT_DEVMEM=y
+# CONFIG_IO_STRICT_DEVMEM is not set
 # CONFIG_X86_VERBOSE_BOOTUP is not set
 CONFIG_EARLY_PRINTK=y
@@ -3818,4 +3931,6 @@
 # CONFIG_X86_PTDUMP_CORE is not set
 # CONFIG_EFI_PGT_DUMP is not set
+CONFIG_DEBUG_RODATA_TEST=y
+# CONFIG_DEBUG_WX is not set
 # CONFIG_DEBUG_SET_MODULE_RONX is not set
 CONFIG_DOUBLEFAULT=y
@@ -3841,8 +3956,12 @@
 # CONFIG_BIG_KEYS is not set
 # CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_KEY_DH_OPERATIONS is not set
 # CONFIG_SECURITY_DMESG_RESTRICT is not set
 # CONFIG_SECURITY is not set
 # CONFIG_SECURITYFS is not set
 # CONFIG_INTEL_TXT is not set
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
+CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
+# CONFIG_HARDENED_USERCOPY is not set
 CONFIG_DEFAULT_SECURITY_DAC=y
 CONFIG_DEFAULT_SECURITY=""
@@ -3869,9 +3988,10 @@
 CONFIG_CRYPTO_RNG2=y
 CONFIG_CRYPTO_RNG_DEFAULT=m
-CONFIG_CRYPTO_PCOMP=m
-CONFIG_CRYPTO_PCOMP2=y
 CONFIG_CRYPTO_AKCIPHER2=y
 CONFIG_CRYPTO_AKCIPHER=m
+CONFIG_CRYPTO_KPP2=y
 CONFIG_CRYPTO_RSA=m
+# CONFIG_CRYPTO_DH is not set
+# CONFIG_CRYPTO_ECDH is not set
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
@@ -3939,4 +4059,5 @@
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_SHA3 is not set
 CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
@@ -3974,5 +4095,4 @@
 #
 CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_842 is not set
@@ -3995,5 +4115,4 @@
 # CONFIG_CRYPTO_USER_API_RNG is not set
 # CONFIG_CRYPTO_USER_API_AEAD is not set
-CONFIG_CRYPTO_HASH_INFO=y
 CONFIG_CRYPTO_HW=y
 CONFIG_CRYPTO_DEV_PADLOCK=m
@@ -4005,15 +4124,15 @@
 CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
 # CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_C62X is not set
 # CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
-CONFIG_ASYMMETRIC_KEY_TYPE=m
-CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
-CONFIG_X509_CERTIFICATE_PARSER=m
-# CONFIG_PKCS7_MESSAGE_PARSER is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
+# CONFIG_CRYPTO_DEV_CHELSIO is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
 
 #
 # Certificates for signature checking
 #
-# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
 CONFIG_HAVE_KVM=y
 CONFIG_HAVE_KVM_IRQCHIP=y
@@ -4021,5 +4140,4 @@
 CONFIG_HAVE_KVM_IRQ_ROUTING=y
 CONFIG_HAVE_KVM_EVENTFD=y
-CONFIG_KVM_APIC_ARCHITECTURE=y
 CONFIG_KVM_MMIO=y
 CONFIG_KVM_ASYNC_PF=y
@@ -4034,4 +4152,8 @@
 CONFIG_KVM_AMD=m
 # CONFIG_KVM_DEVICE_ASSIGNMENT is not set
+CONFIG_VHOST_NET=m
+# CONFIG_VHOST_VSOCK is not set
+CONFIG_VHOST=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
 # CONFIG_LGUEST is not set
 # CONFIG_BINARY_PRINTF is not set
@@ -4092,4 +4214,5 @@
 CONFIG_TEXTSEARCH_BM=m
 CONFIG_TEXTSEARCH_FSM=m
+CONFIG_RADIX_TREE_MULTIORDER=y
 CONFIG_ASSOCIATIVE_ARRAY=y
 CONFIG_HAS_IOMEM=y
@@ -4102,8 +4225,8 @@
 # CONFIG_GLOB_SELFTEST is not set
 CONFIG_NLATTR=y
-CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
 CONFIG_CLZ_TAB=y
 CONFIG_CORDIC=m
 # CONFIG_DDR is not set
+CONFIG_IRQ_POLL=y
 CONFIG_MPILIB=m
 CONFIG_OID_REGISTRY=m
@@ -4114,4 +4237,6 @@
 CONFIG_FONT_8x16=y
 # CONFIG_SG_SPLIT is not set
+CONFIG_SG_POOL=y
 CONFIG_ARCH_HAS_SG_CHAIN=y
 CONFIG_ARCH_HAS_MMIO_FLUSH=y
+CONFIG_SBITMAP=y
Index: npl/kernel/linux_src/linux-4.9-imq.diff
===================================================================
--- npl/kernel/linux_src/linux-4.9-imq.diff	(revision 6936b8932b048eb73512487926566f8def134e13)
+++ npl/kernel/linux_src/linux-4.9-imq.diff	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -0,0 +1,1718 @@
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 95c32f2..93fada5 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -260,6 +260,125 @@ config RIONET_RX_SIZE
+ 	depends on RIONET
+ 	default "128"
+ 
++config IMQ
++	tristate "IMQ (intermediate queueing device) support"
++	depends on NETDEVICES && NETFILTER
++	---help---
++	  The IMQ device(s) is used as placeholder for QoS queueing
++	  disciplines. Every packet entering/leaving the IP stack can be
++	  directed through the IMQ device where it's enqueued/dequeued to the
++	  attached qdisc. This allows you to treat network devices as classes
++	  and distribute bandwidth among them. Iptables is used to specify
++	  through which IMQ device, if any, packets travel.
++
++	  More information at: https://github.com/imq/linuximq
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called imq.  If unsure, say N.
++
++choice
++	prompt "IMQ behavior (PRE/POSTROUTING)"
++	depends on IMQ
++	default IMQ_BEHAVIOR_AB
++	help
++	  This setting defines how IMQ behaves in respect to its
++	  hooking in PREROUTING and POSTROUTING.
++
++	  IMQ can work in any of the following ways:
++
++	      PREROUTING   |      POSTROUTING
++	  -----------------|-------------------
++	  #1  After NAT    |      After NAT
++	  #2  After NAT    |      Before NAT
++	  #3  Before NAT   |      After NAT
++	  #4  Before NAT   |      Before NAT
++
++	  The default behavior is to hook before NAT on PREROUTING
++	  and after NAT on POSTROUTING (#3).
++
++	  This settings are specially usefull when trying to use IMQ
++	  to shape NATed clients.
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_AA
++	bool "IMQ AA"
++	help
++	  This setting defines how IMQ behaves in respect to its
++	  hooking in PREROUTING and POSTROUTING.
++
++	  Choosing this option will make IMQ hook like this:
++
++	  PREROUTING:   After NAT
++	  POSTROUTING:  After NAT
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_AB
++	bool "IMQ AB"
++	help
++	  This setting defines how IMQ behaves in respect to its
++	  hooking in PREROUTING and POSTROUTING.
++
++	  Choosing this option will make IMQ hook like this:
++
++	  PREROUTING:   After NAT
++	  POSTROUTING:  Before NAT
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_BA
++	bool "IMQ BA"
++	help
++	  This setting defines how IMQ behaves in respect to its
++	  hooking in PREROUTING and POSTROUTING.
++
++	  Choosing this option will make IMQ hook like this:
++
++	  PREROUTING:   Before NAT
++	  POSTROUTING:  After NAT
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_BB
++	bool "IMQ BB"
++	help
++	  This setting defines how IMQ behaves in respect to its
++	  hooking in PREROUTING and POSTROUTING.
++
++	  Choosing this option will make IMQ hook like this:
++
++	  PREROUTING:   Before NAT
++	  POSTROUTING:  Before NAT
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
++endchoice
++
++config IMQ_NUM_DEVS
++	int "Number of IMQ devices"
++	range 2 16
++	depends on IMQ
++	default "16"
++	help
++	  This setting defines how many IMQ devices will be created.
++
++	  The default value is 16.
++
++	  More information can be found at: https://github.com/imq/linuximq
++
++	  If not sure leave the default settings alone.
++
+ config TUN
+ 	tristate "Universal TUN/TAP device driver support"
+ 	depends on INET
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 7336cbd..d6d7ad4 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -11,6 +11,7 @@ obj-$(CONFIG_DUMMY) += dummy.o
+ obj-$(CONFIG_EQUALIZER) += eql.o
+ obj-$(CONFIG_IFB) += ifb.o
+ obj-$(CONFIG_MACSEC) += macsec.o
++obj-$(CONFIG_IMQ) += imq.o
+ obj-$(CONFIG_MACVLAN) += macvlan.o
+ obj-$(CONFIG_MACVTAP) += macvtap.o
+ obj-$(CONFIG_MII) += mii.o
+diff --git a/drivers/net/imq.c b/drivers/net/imq.c
+new file mode 100644
+index 0000000..bc3b997
+--- /dev/null
++++ b/drivers/net/imq.c
+@@ -0,0 +1,907 @@
++/*
++ *             Pseudo-driver for the intermediate queue device.
++ *
++ *             This program 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.
++ *
++ * Authors:    Patrick McHardy, <kaber@trash.net>
++ *
++ *            The first version was written by Martin Devera, <devik@cdi.cz>
++ *
++ *			   See Creditis.txt
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/list.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_arp.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++	#include <linux/netfilter_ipv6.h>
++#endif
++#include <linux/imq.h>
++#include <net/pkt_sched.h>
++#include <net/netfilter/nf_queue.h>
++#include <net/sock.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/if_vlan.h>
++#include <linux/if_pppox.h>
++#include <net/ip.h>
++#include <net/ipv6.h>
++
++static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num);
++
++static nf_hookfn imq_nf_hook;
++
++static struct nf_hook_ops imq_ops[] = {
++	{
++	/* imq_ingress_ipv4 */
++		.hook		= imq_nf_hook,
++		.pf		= PF_INET,
++		.hooknum	= NF_INET_PRE_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++		.priority	= NF_IP_PRI_MANGLE + 1,
++#else
++		.priority	= NF_IP_PRI_NAT_DST + 1,
++#endif
++	},
++	{
++	/* imq_egress_ipv4 */
++		.hook		= imq_nf_hook,
++		.pf		= PF_INET,
++		.hooknum	= NF_INET_POST_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
++		.priority	= NF_IP_PRI_LAST,
++#else
++		.priority	= NF_IP_PRI_NAT_SRC - 1,
++#endif
++	},
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++	{
++	/* imq_ingress_ipv6 */
++		.hook		= imq_nf_hook,
++		.pf		= PF_INET6,
++		.hooknum	= NF_INET_PRE_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++		.priority	= NF_IP6_PRI_MANGLE + 1,
++#else
++		.priority	= NF_IP6_PRI_NAT_DST + 1,
++#endif
++	},
++	{
++	/* imq_egress_ipv6 */
++		.hook		= imq_nf_hook,
++		.pf		= PF_INET6,
++		.hooknum	= NF_INET_POST_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
++		.priority	= NF_IP6_PRI_LAST,
++#else
++		.priority	= NF_IP6_PRI_NAT_SRC - 1,
++#endif
++	},
++#endif
++};
++
++#if defined(CONFIG_IMQ_NUM_DEVS)
++static int numdevs = CONFIG_IMQ_NUM_DEVS;
++#else
++static int numdevs = IMQ_MAX_DEVS;
++#endif
++
++static struct net_device *imq_devs_cache[IMQ_MAX_DEVS];
++
++#define IMQ_MAX_QUEUES 32
++static int numqueues = 1;
++static u32 imq_hashrnd;
++static int imq_dev_accurate_stats = 1;
++
++static inline __be16 pppoe_proto(const struct sk_buff *skb)
++{
++	return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
++			sizeof(struct pppoe_hdr)));
++}
++
++static u16 imq_hash(struct net_device *dev, struct sk_buff *skb)
++{
++	unsigned int pull_len;
++	u16 protocol = skb->protocol;
++	u32 addr1, addr2;
++	u32 hash, ihl = 0;
++	union {
++		u16 in16[2];
++		u32 in32;
++	} ports;
++	u8 ip_proto;
++
++	pull_len = 0;
++
++recheck:
++	switch (protocol) {
++	case htons(ETH_P_8021Q): {
++		if (unlikely(skb_pull(skb, VLAN_HLEN) == NULL))
++			goto other;
++
++		pull_len += VLAN_HLEN;
++		skb->network_header += VLAN_HLEN;
++
++		protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
++		goto recheck;
++	}
++
++	case htons(ETH_P_PPP_SES): {
++		if (unlikely(skb_pull(skb, PPPOE_SES_HLEN) == NULL))
++			goto other;
++
++		pull_len += PPPOE_SES_HLEN;
++		skb->network_header += PPPOE_SES_HLEN;
++
++		protocol = pppoe_proto(skb);
++		goto recheck;
++	}
++
++	case htons(ETH_P_IP): {
++		const struct iphdr *iph = ip_hdr(skb);
++
++		if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr))))
++			goto other;
++
++		addr1 = iph->daddr;
++		addr2 = iph->saddr;
++
++		ip_proto = !(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) ?
++				 iph->protocol : 0;
++		ihl = ip_hdrlen(skb);
++
++		break;
++	}
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++	case htons(ETH_P_IPV6): {
++		const struct ipv6hdr *iph = ipv6_hdr(skb);
++		__be16 fo = 0;
++
++		if (unlikely(!pskb_may_pull(skb, sizeof(struct ipv6hdr))))
++			goto other;
++
++		addr1 = iph->daddr.s6_addr32[3];
++		addr2 = iph->saddr.s6_addr32[3];
++		ihl = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &ip_proto,
++				       &fo);
++		if (unlikely(ihl < 0))
++			goto other;
++
++		break;
++	}
++#endif
++	default:
++other:
++		if (pull_len != 0) {
++			skb_push(skb, pull_len);
++			skb->network_header -= pull_len;
++		}
++
++		return (u16)(ntohs(protocol) % dev->real_num_tx_queues);
++	}
++
++	if (addr1 > addr2)
++		swap(addr1, addr2);
++
++	switch (ip_proto) {
++	case IPPROTO_TCP:
++	case IPPROTO_UDP:
++	case IPPROTO_DCCP:
++	case IPPROTO_ESP:
++	case IPPROTO_AH:
++	case IPPROTO_SCTP:
++	case IPPROTO_UDPLITE: {
++		if (likely(skb_copy_bits(skb, ihl, &ports.in32, 4) >= 0)) {
++			if (ports.in16[0] > ports.in16[1])
++				swap(ports.in16[0], ports.in16[1]);
++			break;
++		}
++		/* fall-through */
++	}
++	default:
++		ports.in32 = 0;
++		break;
++	}
++
++	if (pull_len != 0) {
++		skb_push(skb, pull_len);
++		skb->network_header -= pull_len;
++	}
++
++	hash = jhash_3words(addr1, addr2, ports.in32, imq_hashrnd ^ ip_proto);
++
++	return (u16)(((u64)hash * dev->real_num_tx_queues) >> 32);
++}
++
++static inline bool sk_tx_queue_recorded(struct sock *sk)
++{
++	return (sk_tx_queue_get(sk) >= 0);
++}
++
++static struct netdev_queue *imq_select_queue(struct net_device *dev,
++						struct sk_buff *skb)
++{
++	u16 queue_index = 0;
++	u32 hash;
++
++	if (likely(dev->real_num_tx_queues == 1))
++		goto out;
++
++	/* IMQ can be receiving ingress or engress packets. */
++
++	/* Check first for if rx_queue is set */
++	if (skb_rx_queue_recorded(skb)) {
++		queue_index = skb_get_rx_queue(skb);
++		goto out;
++	}
++
++	/* Check if socket has tx_queue set */
++	if (sk_tx_queue_recorded(skb->sk)) {
++		queue_index = sk_tx_queue_get(skb->sk);
++		goto out;
++	}
++
++	/* Try use socket hash */
++	if (skb->sk && skb->sk->sk_hash) {
++		hash = skb->sk->sk_hash;
++		queue_index =
++			(u16)(((u64)hash * dev->real_num_tx_queues) >> 32);
++		goto out;
++	}
++
++	/* Generate hash from packet data */
++	queue_index = imq_hash(dev, skb);
++
++out:
++	if (unlikely(queue_index >= dev->real_num_tx_queues))
++		queue_index = (u16)((u32)queue_index % dev->real_num_tx_queues);
++
++	skb_set_queue_mapping(skb, queue_index);
++	return netdev_get_tx_queue(dev, queue_index);
++}
++
++static struct net_device_stats *imq_get_stats(struct net_device *dev)
++{
++	return &dev->stats;
++}
++
++/* called for packets kfree'd in qdiscs at places other than enqueue */
++static void imq_skb_destructor(struct sk_buff *skb)
++{
++	struct nf_queue_entry *entry = skb->nf_queue_entry;
++
++	skb->nf_queue_entry = NULL;
++
++	if (entry) {
++		nf_queue_entry_release_refs(entry);
++		kfree(entry);
++	}
++
++	skb_restore_cb(skb); /* kfree backup */
++}
++
++static void imq_done_check_queue_mapping(struct sk_buff *skb,
++					 struct net_device *dev)
++{
++	unsigned int queue_index;
++
++	/* Don't let queue_mapping be left too large after exiting IMQ */
++	if (likely(skb->dev != dev && skb->dev != NULL)) {
++		queue_index = skb_get_queue_mapping(skb);
++		if (unlikely(queue_index >= skb->dev->real_num_tx_queues)) {
++			queue_index = (u16)((u32)queue_index %
++						skb->dev->real_num_tx_queues);
++			skb_set_queue_mapping(skb, queue_index);
++		}
++	} else {
++		/* skb->dev was IMQ device itself or NULL, be on safe side and
++		 * just clear queue mapping.
++		 */
++		skb_set_queue_mapping(skb, 0);
++	}
++}
++
++static netdev_tx_t imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct nf_queue_entry *entry = skb->nf_queue_entry;
++
++	skb->nf_queue_entry = NULL;
++	netif_trans_update(dev);
++
++	dev->stats.tx_bytes += skb->len;
++	dev->stats.tx_packets++;
++
++	if (unlikely(entry == NULL)) {
++		/* We don't know what is going on here.. packet is queued for
++		 * imq device, but (probably) not by us.
++		 *
++		 * If this packet was not send here by imq_nf_queue(), then
++		 * skb_save_cb() was not used and skb_free() should not show:
++		 *   WARNING: IMQ: kfree_skb: skb->cb_next:..
++		 * and/or
++		 *   WARNING: IMQ: kfree_skb: skb->nf_queue_entry...
++		 *
++		 * However if this message is shown, then IMQ is somehow broken
++		 * and you should report this to linuximq.net.
++		 */
++
++		/* imq_dev_xmit is black hole that eats all packets, report that
++		 * we eat this packet happily and increase dropped counters.
++		 */
++
++		dev->stats.tx_dropped++;
++		dev_kfree_skb(skb);
++
++		return NETDEV_TX_OK;
++	}
++
++	skb_restore_cb(skb); /* restore skb->cb */
++
++	skb->imq_flags = 0;
++	skb->destructor = NULL;
++
++	imq_done_check_queue_mapping(skb, dev);
++
++	nf_reinject(entry, NF_ACCEPT);
++
++	return NETDEV_TX_OK;
++}
++
++static struct net_device *get_imq_device_by_index(int index)
++{
++	struct net_device *dev = NULL;
++	struct net *net;
++	char buf[8];
++
++	/* get device by name and cache result */
++	snprintf(buf, sizeof(buf), "imq%d", index);
++
++	/* Search device from all namespaces. */
++	for_each_net(net) {
++		dev = dev_get_by_name(net, buf);
++		if (dev)
++			break;
++	}
++
++	if (WARN_ON_ONCE(dev == NULL)) {
++		/* IMQ device not found. Exotic config? */
++		return ERR_PTR(-ENODEV);
++	}
++
++	imq_devs_cache[index] = dev;
++	dev_put(dev);
++
++	return dev;
++}
++
++static struct nf_queue_entry *nf_queue_entry_dup(struct nf_queue_entry *e)
++{
++	struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
++	if (entry) {
++		nf_queue_entry_get_refs(entry);
++			return entry;
++	}
++	return NULL;
++}
++
++#ifdef CONFIG_BRIDGE_NETFILTER
++/* When called from bridge netfilter, skb->data must point to MAC header
++ * before calling skb_gso_segment(). Else, original MAC header is lost
++ * and segmented skbs will be sent to wrong destination.
++ */
++static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
++{
++	if (skb->nf_bridge)
++		__skb_push(skb, skb->network_header - skb->mac_header);
++}
++
++static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
++{
++	if (skb->nf_bridge)
++		__skb_pull(skb, skb->network_header - skb->mac_header);
++}
++#else
++#define nf_bridge_adjust_skb_data(s) do {} while (0)
++#define nf_bridge_adjust_segmented_data(s) do {} while (0)
++#endif
++
++static void free_entry(struct nf_queue_entry *entry)
++{
++	nf_queue_entry_release_refs(entry);
++	kfree(entry);
++}
++
++static int __imq_nf_queue(struct nf_queue_entry *entry, struct net_device *dev);
++
++static int __imq_nf_queue_gso(struct nf_queue_entry *entry,
++			      struct net_device *dev, struct sk_buff *skb)
++{
++	int ret = -ENOMEM;
++	struct nf_queue_entry *entry_seg;
++
++	nf_bridge_adjust_segmented_data(skb);
++
++	if (skb->next == NULL) { /* last packet, no need to copy entry */
++		struct sk_buff *gso_skb = entry->skb;
++		entry->skb = skb;
++		ret = __imq_nf_queue(entry, dev);
++		if (ret)
++			entry->skb = gso_skb;
++		return ret;
++	}
++
++	skb->next = NULL;
++
++	entry_seg = nf_queue_entry_dup(entry);
++	if (entry_seg) {
++		entry_seg->skb = skb;
++		ret = __imq_nf_queue(entry_seg, dev);
++		if (ret)
++			free_entry(entry_seg);
++	}
++	return ret;
++}
++
++static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num)
++{
++	struct sk_buff *skb, *segs;
++	struct net_device *dev;
++	unsigned int queued;
++	int index, retval, err;
++
++	index = entry->skb->imq_flags & IMQ_F_IFMASK;
++	if (unlikely(index > numdevs - 1)) {
++		if (net_ratelimit())
++			pr_warn("IMQ: invalid device specified, highest is %u\n",
++				numdevs - 1);
++		retval = -EINVAL;
++		goto out_no_dev;
++	}
++
++	/* check for imq device by index from cache */
++	dev = imq_devs_cache[index];
++	if (unlikely(!dev)) {
++		dev = get_imq_device_by_index(index);
++		if (IS_ERR(dev)) {
++			retval = PTR_ERR(dev);
++			goto out_no_dev;
++		}
++	}
++
++	if (unlikely(!(dev->flags & IFF_UP))) {
++		entry->skb->imq_flags = 0;
++		retval = -ECANCELED;
++		goto out_no_dev;
++	}
++
++	/* Since 3.10.x, GSO handling moved here as result of upstream commit
++	 * a5fedd43d5f6c94c71053a66e4c3d2e35f1731a2 (netfilter: move
++	 * skb_gso_segment into nfnetlink_queue module).
++	 *
++	 * Following code replicates the gso handling from
++	 * 'net/netfilter/nfnetlink_queue_core.c':nfqnl_enqueue_packet().
++	 */
++
++	skb = entry->skb;
++
++	switch (entry->state.pf) {
++	case NFPROTO_IPV4:
++		skb->protocol = htons(ETH_P_IP);
++		break;
++	case NFPROTO_IPV6:
++		skb->protocol = htons(ETH_P_IPV6);
++		break;
++	}
++
++	if (!skb_is_gso(entry->skb))
++		return __imq_nf_queue(entry, dev);
++
++	nf_bridge_adjust_skb_data(skb);
++	segs = skb_gso_segment(skb, 0);
++	/* Does not use PTR_ERR to limit the number of error codes that can be
++	 * returned by nf_queue.  For instance, callers rely on -ECANCELED to
++	 * mean 'ignore this hook'.
++	 */
++	err = -ENOBUFS;
++	if (IS_ERR(segs))
++		goto out_err;
++	queued = 0;
++	err = 0;
++	do {
++		struct sk_buff *nskb = segs->next;
++		if (nskb && nskb->next)
++			nskb->cb_next = NULL;
++		if (err == 0)
++			err = __imq_nf_queue_gso(entry, dev, segs);
++		if (err == 0)
++			queued++;
++		else
++			kfree_skb(segs);
++		segs = nskb;
++	} while (segs);
++
++	if (queued) {
++		if (err) /* some segments are already queued */
++			free_entry(entry);
++		kfree_skb(skb);
++		return 0;
++	}
++
++out_err:
++	nf_bridge_adjust_segmented_data(skb);
++	retval = err;
++out_no_dev:
++	return retval;
++}
++
++static int __imq_nf_queue(struct nf_queue_entry *entry, struct net_device *dev)
++{
++	struct sk_buff *skb_orig, *skb, *skb_shared, *skb_popd;
++	struct Qdisc *q;
++	struct sk_buff *to_free = NULL;
++	struct netdev_queue *txq;
++	spinlock_t *root_lock;
++	int users;
++	int retval = -EINVAL;
++	unsigned int orig_queue_index;
++
++	dev->last_rx = jiffies;
++
++	skb = entry->skb;
++	skb_orig = NULL;
++
++	/* skb has owner? => make clone */
++	if (unlikely(skb->destructor)) {
++		skb_orig = skb;
++		skb = skb_clone(skb, GFP_ATOMIC);
++		if (unlikely(!skb)) {
++			retval = -ENOMEM;
++			goto out;
++		}
++		skb->cb_next = NULL;
++		entry->skb = skb;
++	}
++
++	dev->stats.rx_bytes += skb->len;
++	dev->stats.rx_packets++;
++
++	if (!skb->dev) {
++		/* skb->dev == NULL causes problems, try the find cause. */
++		if (net_ratelimit()) {
++			dev_warn(&dev->dev,
++				 "received packet with skb->dev == NULL\n");
++			dump_stack();
++		}
++
++		skb->dev = dev;
++	}
++
++	/* Disables softirqs for lock below */
++	rcu_read_lock_bh();
++
++	/* Multi-queue selection */
++	orig_queue_index = skb_get_queue_mapping(skb);
++	txq = imq_select_queue(dev, skb);
++
++	q = rcu_dereference(txq->qdisc);
++	if (unlikely(!q->enqueue))
++		goto packet_not_eaten_by_imq_dev;
++
++	skb->nf_queue_entry = entry;
++	root_lock = qdisc_lock(q);
++	spin_lock(root_lock);
++
++	users = atomic_read(&skb->users);
++
++	skb_shared = skb_get(skb); /* increase reference count by one */
++
++	/* backup skb->cb, as qdisc layer will overwrite it */
++	skb_save_cb(skb_shared);
++	qdisc_enqueue_root(skb_shared, q, &to_free); /* might kfree_skb */
++	if (likely(atomic_read(&skb_shared->users) == users + 1)) {
++		bool validate;
++
++		kfree_skb(skb_shared); /* decrease reference count by one */
++
++		skb->destructor = &imq_skb_destructor;
++
++		skb_popd = qdisc_dequeue_skb(q, &validate);
++
++		/* cloned? */
++		if (unlikely(skb_orig))
++			kfree_skb(skb_orig); /* free original */
++
++		spin_unlock(root_lock);
++
++#if 0
++		/* schedule qdisc dequeue */
++		__netif_schedule(q);
++#else
++		if (likely(skb_popd)) {
++			/* Note that we validate skb (GSO, checksum, ...) outside of locks */
++			if (validate)
++        		skb_popd = validate_xmit_skb_list(skb_popd, dev);
++
++			if (skb_popd) {
++				int dummy_ret;
++				int cpu = smp_processor_id(); /* ok because BHs are off */
++
++				txq = skb_get_tx_queue(dev, skb_popd);
++				/*
++				IMQ device will not be frozen or stoped, and it always be successful.
++				So we need not check its status and return value to accelerate.
++				*/
++				if (imq_dev_accurate_stats && txq->xmit_lock_owner != cpu) {
++					HARD_TX_LOCK(dev, txq, cpu);
++					if (!netif_xmit_frozen_or_stopped(txq)) {
++						dev_hard_start_xmit(skb_popd, dev, txq, &dummy_ret);
++					}
++					HARD_TX_UNLOCK(dev, txq);
++				} else {
++					if (!netif_xmit_frozen_or_stopped(txq)) {
++						dev_hard_start_xmit(skb_popd, dev, txq, &dummy_ret);
++					}
++				}
++			}
++		} else {
++			/* No ready skb, then schedule it */
++			__netif_schedule(q);
++		}
++#endif
++		rcu_read_unlock_bh();
++		retval = 0;
++		goto out;
++	} else {
++		skb_restore_cb(skb_shared); /* restore skb->cb */
++		skb->nf_queue_entry = NULL;
++		/*
++		 * qdisc dropped packet and decreased skb reference count of
++		 * skb, so we don't really want to and try refree as that would
++		 * actually destroy the skb.
++		 */
++		spin_unlock(root_lock);
++		goto packet_not_eaten_by_imq_dev;
++	}
++
++packet_not_eaten_by_imq_dev:
++	skb_set_queue_mapping(skb, orig_queue_index);
++	rcu_read_unlock_bh();
++
++	/* cloned? restore original */
++	if (unlikely(skb_orig)) {
++		kfree_skb(skb);
++		entry->skb = skb_orig;
++	}
++	retval = -1;
++out:
++	if (unlikely(to_free)) {
++		kfree_skb_list(to_free);
++	}
++	return retval;
++}
++static unsigned int imq_nf_hook(void *priv,
++				struct sk_buff *skb,
++				const struct nf_hook_state *state)
++{
++	return (skb->imq_flags & IMQ_F_ENQUEUE) ? NF_IMQ_QUEUE : NF_ACCEPT;
++}
++
++static int imq_close(struct net_device *dev)
++{
++	netif_stop_queue(dev);
++	return 0;
++}
++
++static int imq_open(struct net_device *dev)
++{
++	netif_start_queue(dev);
++	return 0;
++}
++
++static const struct net_device_ops imq_netdev_ops = {
++	.ndo_open		= imq_open,
++	.ndo_stop		= imq_close,
++	.ndo_start_xmit		= imq_dev_xmit,
++	.ndo_get_stats		= imq_get_stats,
++};
++
++static void imq_setup(struct net_device *dev)
++{
++	dev->netdev_ops		= &imq_netdev_ops;
++	dev->type		= ARPHRD_VOID;
++	dev->mtu		= 16000; /* too small? */
++	dev->tx_queue_len	= 11000; /* too big? */
++	dev->flags		= IFF_NOARP;
++	dev->features		= NETIF_F_SG | NETIF_F_FRAGLIST |
++				  NETIF_F_GSO | NETIF_F_HW_CSUM |
++				  NETIF_F_HIGHDMA;
++	dev->priv_flags		&= ~(IFF_XMIT_DST_RELEASE |
++				     IFF_TX_SKB_SHARING);
++}
++
++static int imq_validate(struct nlattr *tb[], struct nlattr *data[])
++{
++	int ret = 0;
++
++	if (tb[IFLA_ADDRESS]) {
++		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
++			ret = -EINVAL;
++			goto end;
++		}
++		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
++			ret = -EADDRNOTAVAIL;
++			goto end;
++		}
++	}
++	return 0;
++end:
++	pr_warn("IMQ: imq_validate failed (%d)\n", ret);
++	return ret;
++}
++
++static struct rtnl_link_ops imq_link_ops __read_mostly = {
++	.kind		= "imq",
++	.priv_size	= 0,
++	.setup		= imq_setup,
++	.validate	= imq_validate,
++};
++
++static const struct nf_queue_handler imq_nfqh = {
++	.outfn = imq_nf_queue,
++};
++
++static int __init imq_init_hooks(void)
++{
++	int ret;
++
++	nf_register_queue_imq_handler(&imq_nfqh);
++
++	ret = nf_register_hooks(imq_ops, ARRAY_SIZE(imq_ops));
++	if (ret < 0)
++		nf_unregister_queue_imq_handler();
++
++	return ret;
++}
++
++static int __init imq_init_one(int index)
++{
++	struct net_device *dev;
++	int ret;
++
++	dev = alloc_netdev_mq(0, "imq%d", NET_NAME_UNKNOWN, imq_setup, numqueues);
++	if (!dev)
++		return -ENOMEM;
++
++	ret = dev_alloc_name(dev, dev->name);
++	if (ret < 0)
++		goto fail;
++
++	dev->rtnl_link_ops = &imq_link_ops;
++	ret = register_netdevice(dev);
++	if (ret < 0)
++		goto fail;
++
++	return 0;
++fail:
++	free_netdev(dev);
++	return ret;
++}
++
++static int __init imq_init_devs(void)
++{
++	int err, i;
++
++	if (numdevs < 1 || numdevs > IMQ_MAX_DEVS) {
++		pr_err("IMQ: numdevs has to be betweed 1 and %u\n",
++		       IMQ_MAX_DEVS);
++		return -EINVAL;
++	}
++
++	if (numqueues < 1 || numqueues > IMQ_MAX_QUEUES) {
++		pr_err("IMQ: numqueues has to be betweed 1 and %u\n",
++		       IMQ_MAX_QUEUES);
++		return -EINVAL;
++	}
++
++	get_random_bytes(&imq_hashrnd, sizeof(imq_hashrnd));
++
++	rtnl_lock();
++	err = __rtnl_link_register(&imq_link_ops);
++
++	for (i = 0; i < numdevs && !err; i++)
++		err = imq_init_one(i);
++
++	if (err) {
++		__rtnl_link_unregister(&imq_link_ops);
++		memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
++	}
++	rtnl_unlock();
++
++	return err;
++}
++
++static int __init imq_init_module(void)
++{
++	int err;
++
++#if defined(CONFIG_IMQ_NUM_DEVS)
++	BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS > 16);
++	BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS < 2);
++	BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS - 1 > IMQ_F_IFMASK);
++#endif
++
++	err = imq_init_devs();
++	if (err) {
++		pr_err("IMQ: Error trying imq_init_devs(net)\n");
++		return err;
++	}
++
++	err = imq_init_hooks();
++	if (err) {
++		pr_err(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
++		rtnl_link_unregister(&imq_link_ops);
++		memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
++		return err;
++	}
++
++	pr_info("IMQ driver loaded successfully. (numdevs = %d, numqueues = %d, imq_dev_accurate_stats = %d)\n",
++		numdevs, numqueues, imq_dev_accurate_stats);
++
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++	pr_info("\tHooking IMQ before NAT on PREROUTING.\n");
++#else
++	pr_info("\tHooking IMQ after NAT on PREROUTING.\n");
++#endif
++#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++	pr_info("\tHooking IMQ before NAT on POSTROUTING.\n");
++#else
++	pr_info("\tHooking IMQ after NAT on POSTROUTING.\n");
++#endif
++
++	return 0;
++}
++
++static void __exit imq_unhook(void)
++{
++	nf_unregister_hooks(imq_ops, ARRAY_SIZE(imq_ops));
++	nf_unregister_queue_imq_handler();
++}
++
++static void __exit imq_cleanup_devs(void)
++{
++	rtnl_link_unregister(&imq_link_ops);
++	memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
++}
++
++static void __exit imq_exit_module(void)
++{
++	imq_unhook();
++	imq_cleanup_devs();
++	pr_info("IMQ driver unloaded successfully.\n");
++}
++
++module_init(imq_init_module);
++module_exit(imq_exit_module);
++
++module_param(numdevs, int, 0);
++module_param(numqueues, int, 0);
++module_param(imq_dev_accurate_stats, int, 0);
++MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)");
++MODULE_PARM_DESC(numqueues, "number of queues per IMQ device");
++MODULE_PARM_DESC(imq_dev_accurate_stats, "Notify if need the accurate imq device stats");
++
++MODULE_AUTHOR("https://github.com/imq/linuximq");
++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See https://github.com/imq/linuximq/wiki for more information.");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_RTNL_LINK("imq");
+diff --git a/include/linux/imq.h b/include/linux/imq.h
+new file mode 100644
+index 0000000..1babb09
+--- /dev/null
++++ b/include/linux/imq.h
+@@ -0,0 +1,13 @@
++#ifndef _IMQ_H
++#define _IMQ_H
++
++/* IFMASK (16 device indexes, 0 to 15) and flag(s) fit in 5 bits */
++#define IMQ_F_BITS	5
++
++#define IMQ_F_IFMASK	0x0f
++#define IMQ_F_ENQUEUE	0x10
++
++#define IMQ_MAX_DEVS	(IMQ_F_IFMASK + 1)
++
++#endif /* _IMQ_H */
++
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index e16a2a9..4a1090a 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -3669,6 +3669,19 @@ static inline void netif_tx_unlock_bh(struct net_device *dev)
+ 	}						\
+ }
+ 
++#define HARD_TX_LOCK_BH(dev, txq) {           \
++    if ((dev->features & NETIF_F_LLTX) == 0) {  \
++        __netif_tx_lock_bh(txq);      \
++    }                       \
++}
++
++#define HARD_TX_UNLOCK_BH(dev, txq) {          \
++    if ((dev->features & NETIF_F_LLTX) == 0) {  \
++        __netif_tx_unlock_bh(txq);         \
++    }                       \
++}
++
++
+ static inline void netif_tx_disable(struct net_device *dev)
+ {
+ 	unsigned int i;
+diff --git a/include/linux/netfilter/xt_IMQ.h b/include/linux/netfilter/xt_IMQ.h
+new file mode 100644
+index 0000000..9b07230
+--- /dev/null
++++ b/include/linux/netfilter/xt_IMQ.h
+@@ -0,0 +1,9 @@
++#ifndef _XT_IMQ_H
++#define _XT_IMQ_H
++
++struct xt_imq_info {
++	unsigned int todev;     /* target imq device */
++};
++
++#endif /* _XT_IMQ_H */
++
+diff --git a/include/linux/netfilter_ipv4/ipt_IMQ.h b/include/linux/netfilter_ipv4/ipt_IMQ.h
+new file mode 100644
+index 0000000..7af320f
+--- /dev/null
++++ b/include/linux/netfilter_ipv4/ipt_IMQ.h
+@@ -0,0 +1,10 @@
++#ifndef _IPT_IMQ_H
++#define _IPT_IMQ_H
++
++/* Backwards compatibility for old userspace */
++#include <linux/netfilter/xt_IMQ.h>
++
++#define ipt_imq_info xt_imq_info
++
++#endif /* _IPT_IMQ_H */
++
+diff --git a/include/linux/netfilter_ipv6/ip6t_IMQ.h b/include/linux/netfilter_ipv6/ip6t_IMQ.h
+new file mode 100644
+index 0000000..198ac01
+--- /dev/null
++++ b/include/linux/netfilter_ipv6/ip6t_IMQ.h
+@@ -0,0 +1,10 @@
++#ifndef _IP6T_IMQ_H
++#define _IP6T_IMQ_H
++
++/* Backwards compatibility for old userspace */
++#include <linux/netfilter/xt_IMQ.h>
++
++#define ip6t_imq_info xt_imq_info
++
++#endif /* _IP6T_IMQ_H */
++
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index c8f9fa6..6c425c2 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -39,6 +39,10 @@
+ #include <linux/in6.h>
+ #include <linux/if_packet.h>
+ #include <net/flow.h>
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++#include <linux/imq.h>
++#endif
++
+ 
+ /* The interface for checksum offload between the stack and networking drivers
+  * is as follows...
+@@ -654,6 +658,9 @@ struct sk_buff {
+ 	 * first. This is owned by whoever has the skb queued ATM.
+ 	 */
+ 	char			cb[48] __aligned(8);
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	void			*cb_next;
++#endif
+ 
+ 	unsigned long		_skb_refdst;
+ 	void			(*destructor)(struct sk_buff *skb);
+@@ -663,6 +670,9 @@ struct sk_buff {
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ 	struct nf_conntrack	*nfct;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++       struct nf_queue_entry   *nf_queue_entry;
++#endif
+ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+ 	struct nf_bridge_info	*nf_bridge;
+ #endif
+@@ -743,6 +753,9 @@ struct sk_buff {
+ 	__u8			offload_fwd_mark:1;
+ #endif
+ 	/* 2, 4 or 5 bit hole */
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	__u8			imq_flags:IMQ_F_BITS;
++#endif
+ 
+ #ifdef CONFIG_NET_SCHED
+ 	__u16			tc_index;	/* traffic control index */
+@@ -903,6 +916,12 @@ void kfree_skb_list(struct sk_buff *segs);
+ void skb_tx_error(struct sk_buff *skb);
+ void consume_skb(struct sk_buff *skb);
+ void  __kfree_skb(struct sk_buff *skb);
++
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++int skb_save_cb(struct sk_buff *skb);
++int skb_restore_cb(struct sk_buff *skb);
++#endif
++
+ extern struct kmem_cache *skbuff_head_cache;
+ 
+ void kfree_skb_partial(struct sk_buff *skb, bool head_stolen);
+@@ -3594,6 +3613,10 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
+ 	if (copy)
+ 		dst->nfctinfo = src->nfctinfo;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++       dst->imq_flags = src->imq_flags;
++       dst->nf_queue_entry = src->nf_queue_entry;
++#endif
+ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+ 	dst->nf_bridge  = src->nf_bridge;
+ 	nf_bridge_get(src->nf_bridge);
+diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
+index 2280cfe..ec8fa51 100644
+--- a/include/net/netfilter/nf_queue.h
++++ b/include/net/netfilter/nf_queue.h
+@@ -30,6 +30,12 @@ struct nf_queue_handler {
+ void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
+ void nf_unregister_queue_handler(struct net *net);
+ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
++void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
++
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++void nf_register_queue_imq_handler(const struct nf_queue_handler *qh);
++void nf_unregister_queue_imq_handler(void);
++#endif
+ 
+ void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
+ void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
+diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
+index cd334c9..6757228 100644
+--- a/include/net/pkt_sched.h
++++ b/include/net/pkt_sched.h
+@@ -105,6 +105,8 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
+ 
+ void __qdisc_run(struct Qdisc *q);
+ 
++struct sk_buff *qdisc_dequeue_skb(struct Qdisc *q, bool *validate);
++
+ static inline void qdisc_run(struct Qdisc *q)
+ {
+ 	if (qdisc_run_begin(q))
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index e6aa0a2..08b37dc 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -518,6 +518,13 @@ static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ 	return sch->enqueue(skb, sch, to_free);
+ }
+ 
++static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch,
++				      struct sk_buff **to_free)
++{
++    qdisc_skb_cb(skb)->pkt_len = skb->len;
++    return qdisc_enqueue(skb, sch, to_free) & NET_XMIT_MASK;
++}
++
+ static inline bool qdisc_is_percpu_stats(const struct Qdisc *q)
+ {
+ 	return q->flags & TCQ_F_CPUSTATS;
+diff --git a/include/uapi/linux/netfilter.h b/include/uapi/linux/netfilter.h
+index d93f949..23fb6d1 100644
+--- a/include/uapi/linux/netfilter.h
++++ b/include/uapi/linux/netfilter.h
+@@ -14,7 +14,8 @@
+ #define NF_QUEUE 3
+ #define NF_REPEAT 4
+ #define NF_STOP 5
+-#define NF_MAX_VERDICT NF_STOP
++#define NF_IMQ_QUEUE 6
++#define NF_MAX_VERDICT NF_IMQ_QUEUE
+ 
+ /* we overload the higher bits for encoding auxiliary data such as the queue
+  * number or errno values. Not nice, but better than additional function
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 6666b28..3e12add 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -141,6 +141,9 @@
+ #include <linux/netfilter_ingress.h>
+ #include <linux/sctp.h>
+ #include <linux/crash_dump.h>
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++#include <linux/imq.h>
++#endif
+ 
+ #include "net-sysfs.h"
+ 
+@@ -2906,7 +2909,12 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
+ 	unsigned int len;
+ 	int rc;
+ 
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	if ((!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) &&
++		!(skb->imq_flags & IMQ_F_ENQUEUE))
++#else
+ 	if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
++#endif
+ 		dev_queue_xmit_nit(skb, dev);
+ 
+ 	len = skb->len;
+@@ -2945,6 +2953,8 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *de
+ 	return skb;
+ }
+ 
++EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
++
+ static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb,
+ 					  netdev_features_t features)
+ {
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 9bf1289..e3fcf17 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -82,6 +82,87 @@ struct kmem_cache *skbuff_head_cache __read_mostly;
+ static struct kmem_cache *skbuff_fclone_cache __read_mostly;
+ int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
+ EXPORT_SYMBOL(sysctl_max_skb_frags);
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++static struct kmem_cache *skbuff_cb_store_cache __read_mostly;
++#endif
++
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++/* Control buffer save/restore for IMQ devices */
++struct skb_cb_table {
++	char			cb[48] __aligned(8);
++	void			*cb_next;
++	atomic_t		refcnt;
++};
++
++static DEFINE_SPINLOCK(skb_cb_store_lock);
++
++int skb_save_cb(struct sk_buff *skb)
++{
++	struct skb_cb_table *next;
++
++	next = kmem_cache_alloc(skbuff_cb_store_cache, GFP_ATOMIC);
++	if (!next)
++		return -ENOMEM;
++
++	BUILD_BUG_ON(sizeof(skb->cb) != sizeof(next->cb));
++
++	memcpy(next->cb, skb->cb, sizeof(skb->cb));
++	next->cb_next = skb->cb_next;
++
++	atomic_set(&next->refcnt, 1);
++
++	skb->cb_next = next;
++	return 0;
++}
++EXPORT_SYMBOL(skb_save_cb);
++
++int skb_restore_cb(struct sk_buff *skb)
++{
++	struct skb_cb_table *next;
++
++	if (!skb->cb_next)
++		return 0;
++
++	next = skb->cb_next;
++
++	BUILD_BUG_ON(sizeof(skb->cb) != sizeof(next->cb));
++
++	memcpy(skb->cb, next->cb, sizeof(skb->cb));
++	skb->cb_next = next->cb_next;
++
++	spin_lock(&skb_cb_store_lock);
++
++	if (atomic_dec_and_test(&next->refcnt))
++		kmem_cache_free(skbuff_cb_store_cache, next);
++
++	spin_unlock(&skb_cb_store_lock);
++
++	return 0;
++}
++EXPORT_SYMBOL(skb_restore_cb);
++
++static void skb_copy_stored_cb(struct sk_buff *   , const struct sk_buff *     ) __attribute__ ((unused));
++static void skb_copy_stored_cb(struct sk_buff *new, const struct sk_buff *__old)
++{
++	struct skb_cb_table *next;
++	struct sk_buff *old;
++
++	if (!__old->cb_next) {
++		new->cb_next = NULL;
++		return;
++	}
++
++	spin_lock(&skb_cb_store_lock);
++
++	old = (struct sk_buff *)__old;
++
++	next = old->cb_next;
++	atomic_inc(&next->refcnt);
++	new->cb_next = next;
++
++	spin_unlock(&skb_cb_store_lock);
++}
++#endif
+ 
+ /**
+  *	skb_panic - private function for out-of-line support
+@@ -654,6 +735,28 @@ static void skb_release_head_state(struct sk_buff *skb)
+ 		WARN_ON(in_irq());
+ 		skb->destructor(skb);
+ 	}
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	/*
++	 * This should not happen. When it does, avoid memleak by restoring
++	 * the chain of cb-backups.
++	 */
++	while (skb->cb_next != NULL) {
++		if (net_ratelimit())
++			pr_warn("IMQ: kfree_skb: skb->cb_next: %08x\n",
++				(unsigned int)(uintptr_t)skb->cb_next);
++
++		skb_restore_cb(skb);
++	}
++	/*
++	 * This should not happen either, nf_queue_entry is nullified in
++	 * imq_dev_xmit(). If we have non-NULL nf_queue_entry then we are
++	 * leaking entry pointers, maybe memory. We don't know if this is
++	 * pointer to already freed memory, or should this be freed.
++	 * If this happens we need to add refcounting, etc for nf_queue_entry.
++	 */
++	if (skb->nf_queue_entry && net_ratelimit())
++		pr_warn("%s\n", "IMQ: kfree_skb: skb->nf_queue_entry != NULL");
++#endif
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ 	nf_conntrack_put(skb->nfct);
+ #endif
+@@ -843,6 +946,10 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+ 	new->sp			= secpath_get(old->sp);
+ #endif
+ 	__nf_copy(new, old, false);
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	new->cb_next = NULL;
++	/*skb_copy_stored_cb(new, old);*/
++#endif
+ 
+ 	/* Note : this field could be in headers_start/headers_end section
+ 	 * It is not yet because we do not want to have a 16 bit hole
+@@ -3464,6 +3571,13 @@ void __init skb_init(void)
+ 						0,
+ 						SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ 						NULL);
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++	skbuff_cb_store_cache = kmem_cache_create("skbuff_cb_store_cache",
++						  sizeof(struct skb_cb_table),
++						  0,
++						  SLAB_HWCACHE_ALIGN|SLAB_PANIC,
++						  NULL);
++#endif
+ }
+ 
+ /**
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 59eb4ed..8020b07 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -66,9 +66,6 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
+ 	struct in6_addr *nexthop;
+ 	int ret;
+ 
+-	skb->protocol = htons(ETH_P_IPV6);
+-	skb->dev = dev;
+-
+ 	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
+ 		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
+ 
+@@ -150,6 +147,13 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+ 		return 0;
+ 	}
+ 
++	/*
++	* IMQ-patch: moved setting skb->dev and skb->protocol from
++	* ip6_finish_output2 to fix crashing at netif_skb_features().
++	*/
++	skb->protocol = htons(ETH_P_IPV6);
++	skb->dev = dev;
++
+ 	return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
+ 			    net, sk, skb, NULL, dev,
+ 			    ip6_finish_output,
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index 4a2e5a3..fc5cc9a 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -833,6 +833,18 @@ config NETFILTER_XT_TARGET_LOG
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config NETFILTER_XT_TARGET_IMQ
++        tristate '"IMQ" target support'
++	depends on NETFILTER_XTABLES
++	depends on IP_NF_MANGLE || IP6_NF_MANGLE
++	select IMQ
++	default m if NETFILTER_ADVANCED=n
++        help
++          This option adds a `IMQ' target which is used to specify if and
++          to which imq device packets should get enqueued/dequeued.
++
++          To compile it as a module, choose M here.  If unsure, say N.
++
+ config NETFILTER_XT_TARGET_MARK
+ 	tristate '"MARK" target support'
+ 	depends on NETFILTER_ADVANCED
+diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
+index e5c5e1e..3128bc5 100644
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -119,6 +119,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
++obj-$(CONFIG_NETFILTER_XT_TARGET_IMQ) += xt_IMQ.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_NETMAP) += xt_NETMAP.o
+diff --git a/net/netfilter/core.c b/net/netfilter/core.c
+index 004af03..768a08b 100644
+--- a/net/netfilter/core.c
++++ b/net/netfilter/core.c
+@@ -360,8 +360,11 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
+ 		ret = NF_DROP_GETERR(verdict);
+ 		if (ret == 0)
+ 			ret = -EPERM;
+-	} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
++	} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE ||
++		   (verdict & NF_VERDICT_MASK) == NF_IMQ_QUEUE) {
+ 		ret = nf_queue(skb, state, &entry, verdict);
++		if (ret == -ECANCELED)
++			goto next_hook;
+ 		if (ret == 1 && entry)
+ 			goto next_hook;
+ 	}
+diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
+index 8f08d75..c12c9eb 100644
+--- a/net/netfilter/nf_queue.c
++++ b/net/netfilter/nf_queue.c
+@@ -27,6 +27,23 @@
+  * receives, no matter what.
+  */
+ 
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++static const struct nf_queue_handler __rcu *queue_imq_handler __read_mostly;
++
++void nf_register_queue_imq_handler(const struct nf_queue_handler *qh)
++{
++	rcu_assign_pointer(queue_imq_handler, qh);
++}
++EXPORT_SYMBOL_GPL(nf_register_queue_imq_handler);
++
++void nf_unregister_queue_imq_handler(void)
++{
++	RCU_INIT_POINTER(queue_imq_handler, NULL);
++	synchronize_rcu();
++}
++EXPORT_SYMBOL_GPL(nf_unregister_queue_imq_handler);
++#endif
++
+ /* return EBUSY when somebody else is registered, return EEXIST if the
+  * same handler is registered, return 0 in case of success. */
+ void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh)
+@@ -108,16 +125,28 @@ void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry)
+ }
+ 
+ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
+-		      unsigned int queuenum)
++		      unsigned int verdict)
+ {
+ 	int status = -ENOENT;
+ 	struct nf_queue_entry *entry = NULL;
+ 	const struct nf_afinfo *afinfo;
+ 	const struct nf_queue_handler *qh;
+ 	struct net *net = state->net;
++	unsigned int queuetype = verdict & NF_VERDICT_MASK;
++	unsigned int queuenum  = verdict >> NF_VERDICT_QBITS;
+ 
+ 	/* QUEUE == DROP if no one is waiting, to be safe. */
+-	qh = rcu_dereference(net->nf.queue_handler);
++	if (queuetype == NF_IMQ_QUEUE) {
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++		qh = rcu_dereference(queue_imq_handler);
++#else
++		BUG();
++		goto err_unlock;
++#endif
++	} else {
++		qh = rcu_dereference(net->nf.queue_handler);
++	}
++
+ 	if (!qh) {
+ 		status = -ESRCH;
+ 		goto err;
+@@ -164,8 +193,14 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
+ 	int ret;
+ 
+ 	RCU_INIT_POINTER(state->hook_entries, entry);
+-	ret = __nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
++	ret = __nf_queue(skb, state, verdict);
+ 	if (ret < 0) {
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++		if (ret == -ECANCELED && skb->imq_flags == 0) { // down interface
++			*entryp = rcu_dereference(entry->next);
++			return 1;
++		}
++#endif
+ 		if (ret == -ESRCH &&
+ 		    (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) {
+ 			*entryp = rcu_dereference(entry->next);
+@@ -218,6 +253,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
+ 		local_bh_enable();
+ 		break;
+ 	case NF_QUEUE:
++	case NF_IMQ_QUEUE:
+ 		err = nf_queue(skb, &entry->state, &hook_entry, verdict);
+ 		if (err == 1) {
+ 			if (hook_entry)
+diff --git a/net/netfilter/xt_IMQ.c b/net/netfilter/xt_IMQ.c
+new file mode 100644
+index 0000000..f9c5817
+--- /dev/null
++++ b/net/netfilter/xt_IMQ.c
+@@ -0,0 +1,72 @@
++/*
++ * This target marks packets to be enqueued to an imq device
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_IMQ.h>
++#include <linux/imq.h>
++
++static unsigned int imq_target(struct sk_buff *pskb,
++				const struct xt_action_param *par)
++{
++	const struct xt_imq_info *mr = par->targinfo;
++
++	pskb->imq_flags = (mr->todev & IMQ_F_IFMASK) | IMQ_F_ENQUEUE;
++
++	return XT_CONTINUE;
++}
++
++static int imq_checkentry(const struct xt_tgchk_param *par)
++{
++	struct xt_imq_info *mr = par->targinfo;
++
++	if (mr->todev > IMQ_MAX_DEVS - 1) {
++		pr_warn("IMQ: invalid device specified, highest is %u\n",
++			IMQ_MAX_DEVS - 1);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static struct xt_target xt_imq_reg[] __read_mostly = {
++	{
++		.name           = "IMQ",
++		.family		= AF_INET,
++		.checkentry     = imq_checkentry,
++		.target         = imq_target,
++		.targetsize	= sizeof(struct xt_imq_info),
++		.table		= "mangle",
++		.me             = THIS_MODULE
++	},
++	{
++		.name           = "IMQ",
++		.family		= AF_INET6,
++		.checkentry     = imq_checkentry,
++		.target         = imq_target,
++		.targetsize	= sizeof(struct xt_imq_info),
++		.table		= "mangle",
++		.me             = THIS_MODULE
++	},
++};
++
++static int __init imq_init(void)
++{
++	return xt_register_targets(xt_imq_reg, ARRAY_SIZE(xt_imq_reg));
++}
++
++static void __exit imq_fini(void)
++{
++	xt_unregister_targets(xt_imq_reg, ARRAY_SIZE(xt_imq_reg));
++}
++
++module_init(imq_init);
++module_exit(imq_fini);
++
++MODULE_AUTHOR("https://github.com/imq/linuximq");
++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See https://github.com/imq/linuximq/wiki for more information.");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_IMQ");
++MODULE_ALIAS("ip6t_IMQ");
++
+diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
+index 6cfb6e9..4c675e9 100644
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -154,6 +154,14 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate,
+ 	return skb;
+ }
+ 
++struct sk_buff *qdisc_dequeue_skb(struct Qdisc *q, bool *validate)
++{
++	int packets;
++
++	return dequeue_skb(q, validate, &packets);
++}
++EXPORT_SYMBOL(qdisc_dequeue_skb);
++
+ /*
+  * Transmit possibly several skbs, and handle the return status as
+  * required. Owning running seqcount bit guarantees that
Index: npl/kernel/linux_src/linux_src.SlackBuild
===================================================================
--- npl/kernel/linux_src/linux_src.SlackBuild	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/linux_src.SlackBuild	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -14,10 +14,10 @@
 
 #unpack basic kernel and apply all incremental patches
-tar -xf $CWD/linux-4.4.tar.xz || exit 1
+tar -xf $CWD/linux-4.9.tar.xz || exit 1
 cd linux-* || exit 1
 #if you want to create a newer kernel: just download newest patches, and increase patchlevel
 #also increase .major file to trigger rebuilds!
-PATCHLEVEL=72
-VER=4.4.$PATCHLEVEL
+PATCHLEVEL=149
+VER=4.9.$PATCHLEVEL
 #bunzip2 $CWD/patch-$VER.bz2 || exit 1
 #gunzip $CWD/patch-$VER.gz || exit 1
@@ -43,5 +43,8 @@
 #patch -p1 < $CWD/fbcondecor-3.14b.patch || exit 1
 #patch -F3 -p1 < $CWD/fbcondecor-3.15.patch || exit 1
-patch  -p1 < $CWD/fbcondecor-3.19.patch || exit 1
+#patch  -p1 < $CWD/fbcondecor-3.19.patch || exit 1
+
+#from https://dev.gentoo.org/~mpagano/genpatches/patches-4.9-143.html
+patch  -p1 < $CWD/4200_fbcondecor.patch || exit 1
 
 
@@ -51,5 +54,6 @@
 #patch -p1 -F3 < $CWD/linux-3.13-imq.diff || exit 1
 #patch -p1 -F3 < $CWD/linux-3.13.10_hardened_gentoo.diff || exit 1
-patch -p1  < $CWD/linux-4.4.5-imq.diff || exit 1
+#patch -p1  < $CWD/linux-4.4.5-imq.diff || exit 1
+patch -p1  < $CWD/linux-4.9-imq.diff || exit 1
 
 
Index: npl/kernel/linux_src/linux_src.build
===================================================================
--- npl/kernel/linux_src/linux_src.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/linux_src.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6551
+6558
Index: npl/kernel/linux_src/linux_src.major
===================================================================
--- npl/kernel/linux_src/linux_src.major	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/linux_src.major	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,2 +1,2 @@
-404072000
+409149001
 
Index: npl/kernel/linux_src/linux_src.md5
===================================================================
--- npl/kernel/linux_src/linux_src.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/linux_src.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,8 +1,14 @@
-017c99ede49e47e606a889dffe7e23ab  ./config
+1c0d964fcb8ab76dd04f19f83bdabbc2  ./4200_fbcondecor.patch
+a479e3ee3b9252fba112e4e011c3058b  ./config
 8b7ca23aa660578023a0a244ae235888  ./fbcondecor-3.19.patch
 467d0a59ae2bfe466a370d65768b8ace  ./linux-4.4.5-imq.diff
 9a78fa2eb6c68ca5a40ed5af08142599  ./linux-4.4.tar.xz
-612eaca595756d9a879815252733f148  ./linux_src.pkg
-f8e92ed9ffe8143840c999f4763b5c53  ./linux_src.SlackBuild
-42ceaa2f4a94660086e0ec3175eac239  ./linux_src.SlackBuild.log.gz
+6b10d4581a7f626ea0634ce0e2ad0250  ./linux-4.9-imq.diff
+0a68ef3615c64bd5ee54a3320e46667d  ./linux-4.9.tar.xz
+4f9feea78b058e676574848e108fe594  ./linux_src.pkg
+6b66e4b02a92e6d643336d7969031116  ./linux_src.SlackBuild
+accffe59dd330ecf4330ee17cdc8b662  ./linux_src.SlackBuild.log.gz
+dcfc0db36564de7afa191888d77d667c  ./patch-4.4.165.xz
 706589ba15cc3b1635c8bb1bc8938b14  ./patch-4.4.72.xz
+2440673308ee069058e273517db635d2  ./patch-4.9.141.xz
+3f6f4513701ef63c8afdce3ebc917393  ./patch-4.9.149.xz
Index: npl/kernel/linux_src/linux_src.version
===================================================================
--- npl/kernel/linux_src/linux_src.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/linux_src/linux_src.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-4.4.72_bigmem_syn3
+4.9.149_bigmem_syn3
Index: npl/kernel/open_vm_tools/open_vm_tools.SlackBuild
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools.SlackBuild	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools.SlackBuild	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -55,5 +55,5 @@
 #Directory where the sourcefiles are unpacked. 
 #(you might have to adjust this if autodetection fails)
-SRC_DIR=`ls -c|head -1`/open-vm-tools
+SRC_DIR=`ls -c|head -1`
 
 #apply patches
@@ -69,8 +69,8 @@
 MAKE_OPTS=""
 
-autoreconf -i || exit 1
+#autoreconf -i || exit 1
 #export CFLAGS="-Wno-error=cpp -Wno-error=format="
 chmod +x configure
-./configure --prefix=/usr --without-x --without-icu --disable-docs --without-kernel-modules  || exit 1
+./configure --prefix=/usr --without-x --without-icu --disable-docs --without-kernel-modules --without-xml2 || exit 1
 
 #AUTOMAKE: Compile
Index: npl/kernel/open_vm_tools/open_vm_tools.build
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6553
Index: npl/kernel/open_vm_tools/open_vm_tools.depver
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools.depver	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools.depver	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,4 +1,4 @@
 linux	0
-linux_src	404072000
+linux_src	409149001
 glib2	2
 procps_ng	0
Index: npl/kernel/open_vm_tools/open_vm_tools.md5
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools.md5	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools.md5	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,5 +1,5 @@
-fa2da0f0a8eea056c2e226def180d370  ./open_vm_tools_dev.pkg
-ccd2ee72aaf3c273f44bbb15b64b772c  ./open_vm_tools.pkg
-00093fce9cc4e852605b2b138c325a71  ./open_vm_tools.SlackBuild
-3b62ac0559ae4683eee1a870a6840e82  ./open_vm_tools.SlackBuild.log.gz
-3b7253225c4131ee2d5e490c3b86cf1f  ./open-vm-tools-stable-10.0.7.zip
+2af26884a7ac37f63a8dd46da91ce205  ./open-vm-tools-10.3.5-10430147.tar.gz
+462e4834c33e070858a4bebae1ff12ae  ./open_vm_tools_dev.pkg
+c235379a370cf150636e90526789be6c  ./open_vm_tools.pkg
+ca02f86a7073e3008815c2ba435a9082  ./open_vm_tools.SlackBuild
+2c93c26c72826e940315d657bd117b23  ./open_vm_tools.SlackBuild.log.gz
Index: npl/kernel/open_vm_tools/open_vm_tools.version
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-10.0.7
+10430147
Index: npl/kernel/open_vm_tools/open_vm_tools_dev.build
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools_dev.build	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools_dev.build	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-6550
+6553
Index: npl/kernel/open_vm_tools/open_vm_tools_dev.version
===================================================================
--- npl/kernel/open_vm_tools/open_vm_tools_dev.version	(revision 9b9dbbba977f5adf88ddfe04ea069a88195cfa2f)
+++ npl/kernel/open_vm_tools/open_vm_tools_dev.version	(revision 6936b8932b048eb73512487926566f8def134e13)
@@ -1,1 +1,1 @@
-10.0.7
+10430147
