guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

08/14: gnu: Add linux-libre-loongson2f.


From: Mark H. Weaver
Subject: 08/14: gnu: Add linux-libre-loongson2f.
Date: Wed, 30 Sep 2015 22:13:20 +0000

mhw pushed a commit to branch wip-loongson2f
in repository guix.

commit 4f179371798f187f7fc7edeca69797b6d3cb8587
Author: Mark H Weaver <address@hidden>
Date:   Thu Aug 6 17:51:27 2015 -0400

    gnu: Add linux-libre-loongson2f.
    
    * gnu/packages/linux-libre-loongson2f.conf,
      gnu/packages/patches/linux-libre-export-loongson-chipcfg.patch,
      gnu/packages/patches/linux-libre-gdium.patch,
      gnu/packages/patches/linux-libre-loongson2-cpufreq-fix.patch,
      gnu/packages/patches/linux-libre-loongson2-math-emu.patch,
      gnu/packages/patches/linux-libre-loongson2-max-physmem-bits.patch,
      gnu/packages/patches/linux-libre-mips-ftrace-fix.patch,
      gnu/packages/patches/linux-libre-mips-hugetlb-fix.patch,
      gnu/packages/patches/linux-libre-mips-math-emu-fix-pt1.patch,
      gnu/packages/patches/linux-libre-mips-math-emu-fix-pt2.patch,
      gnu/packages/patches/linux-libre-yeeloong-rfkill-key-fix.patch,
      gnu/packages/patches/linux-libre-yeeloong-silence-ec-messages.patch,
      gnu/packages/patches/linux-libre-yeeloong.patch: New files.
    * gnu-system.am (dist_patch_DATA): Add patches.
    * Makefile.am (KCONFIGS): Add linux-libre-loongson2f.conf.
    * gnu/packages/linux.scm (linux-libre-loongson2f): New variable.
---
 Makefile.am                                        |    3 +-
 gnu-system.am                                      |   12 +
 gnu/packages/linux-libre-loongson2f.conf           | 2988 +++++++++++++++++
 gnu/packages/linux.scm                             |   27 +
 .../linux-libre-export-loongson-chipcfg.patch      |   28 +
 gnu/packages/patches/linux-libre-gdium.patch       | 2549 +++++++++++++++
 .../linux-libre-loongson2-cpufreq-fix.patch        |   59 +
 .../patches/linux-libre-loongson2-math-emu.patch   |  386 +++
 .../linux-libre-loongson2-max-physmem-bits.patch   |   36 +
 .../patches/linux-libre-mips-ftrace-fix.patch      |   85 +
 .../patches/linux-libre-mips-hugetlb-fix.patch     |   15 +
 .../linux-libre-mips-math-emu-fix-pt1.patch        |   35 +
 .../linux-libre-mips-math-emu-fix-pt2.patch        |   66 +
 .../linux-libre-yeeloong-rfkill-key-fix.patch      |   48 +
 .../linux-libre-yeeloong-silence-ec-messages.patch |   26 +
 gnu/packages/patches/linux-libre-yeeloong.patch    | 3451 ++++++++++++++++++++
 16 files changed, 9813 insertions(+), 1 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index a8dab5d..58edebc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -154,7 +154,8 @@ guix/download.go: guix/build/download.go
 # Linux-Libre configurations.
 KCONFIGS =                                     \
   gnu/packages/linux-libre-i686.conf           \
-  gnu/packages/linux-libre-x86_64.conf
+  gnu/packages/linux-libre-x86_64.conf         \
+  gnu/packages/linux-libre-loongson2f.conf
 
 # Templates, examples.
 EXAMPLES =                                     \
diff --git a/gnu-system.am b/gnu-system.am
index 98634a0..9f8a91e 100644
--- a/gnu-system.am
+++ b/gnu-system.am
@@ -538,6 +538,18 @@ dist_patch_DATA =                                          
\
   gnu/packages/patches/libwmf-CVE-2006-3376.patch              \
   gnu/packages/patches/libwmf-CVE-2009-1364.patch              \
   gnu/packages/patches/libwmf-CVE-2015-0848+4588+4695+4696.patch \
+  gnu/packages/patches/linux-libre-export-loongson-chipcfg.patch \
+  gnu/packages/patches/linux-libre-gdium.patch                 \
+  gnu/packages/patches/linux-libre-loongson2-cpufreq-fix.patch \
+  gnu/packages/patches/linux-libre-loongson2-math-emu.patch    \
+  gnu/packages/patches/linux-libre-loongson2-max-physmem-bits.patch \
+  gnu/packages/patches/linux-libre-mips-ftrace-fix.patch       \
+  gnu/packages/patches/linux-libre-mips-hugetlb-fix.patch      \
+  gnu/packages/patches/linux-libre-mips-math-emu-fix-pt1.patch \
+  gnu/packages/patches/linux-libre-mips-math-emu-fix-pt2.patch \
+  gnu/packages/patches/linux-libre-yeeloong-rfkill-key-fix.patch \
+  gnu/packages/patches/linux-libre-yeeloong-silence-ec-messages.patch \
+  gnu/packages/patches/linux-libre-yeeloong.patch              \
   gnu/packages/patches/lirc-localstatedir.patch                        \
   gnu/packages/patches/libpthread-glibc-preparation.patch      \
   gnu/packages/patches/lm-sensors-hwmon-attrs.patch            \
diff --git a/gnu/packages/linux-libre-loongson2f.conf 
b/gnu/packages/linux-libre-loongson2f.conf
new file mode 100644
index 0000000..fbb81bc
--- /dev/null
+++ b/gnu/packages/linux-libre-loongson2f.conf
@@ -0,0 +1,2988 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/mips 4.2.0-gnu Kernel Configuration
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_ATH25 is not set
+# CONFIG_ATH79 is not set
+# CONFIG_BMIPS_GENERIC is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_INGENIC is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON32 is not set
+CONFIG_MACH_LOONGSON64=y
+# CONFIG_MACH_PISTACHIO is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD3 is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_RALINK is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_CAVIUM_OCTEON_SOC is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_MIPS_PARAVIRT is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+# CONFIG_LEMOTE_FULOONG2E is not set
+CONFIG_LEMOTE_MACH2F=y
+# CONFIG_DEXXON_GDIUM is not set
+# CONFIG_LOONGSON_MACH3X is not set
+CONFIG_CS5536=y
+CONFIG_LOONGSON_SUSPEND=y
+CONFIG_LOONGSON_UART_BASE=y
+CONFIG_LOONGSON_MC146818=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_I8259=y
+# CONFIG_MIPS_MACHINE is not set
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_ISA_DMA_SUPPORT_BROKEN=y
+CONFIG_ISA_DMA_API=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_MIPS_HUGE_TLB_SUPPORT=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_LOONGSON2F=y
+CONFIG_CPU_NOP_WORKAROUNDS=y
+CONFIG_CPU_JUMP_WORKAROUNDS=y
+CONFIG_CPU_LOONGSON2F_WORKAROUNDS=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y
+CONFIG_CPU_LOONGSON2=y
+CONFIG_SYS_HAS_CPU_LOONGSON2F=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_CPUFREQ=y
+CONFIG_CPU_SUPPORTS_ADDRWINCFG=y
+CONFIG_CPU_SUPPORTS_HUGEPAGES=y
+CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+# CONFIG_KVM_GUEST is not set
+CONFIG_PAGE_SIZE_16KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_BOARD_SCACHE=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_HAS_WB=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MEMORY_BALLOON=y
+# CONFIG_COMPACTION is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_CMA is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_MIPS_O32_FP64_SUPPORT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+CONFIG_KERNEL_LZMA=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_USELIB is not set
+# CONFIG_AUDIT is not set
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_HZ_PERIODIC=y
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_SRCU=y
+# CONFIG_TASKS_RCU is not set
+# CONFIG_RCU_STALL_COMMON is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_PAGE_COUNTER=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_SWAP_ENABLED=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_CGROUP_WRITEBACK=y
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_BPF=y
+CONFIG_EXPERT=y
+CONFIG_MULTIUSER=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=y
+CONFIG_PCI_QUIRKS=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_CLONE_BACKWARDS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_COMPRESS is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_CMDLINE_PARSER is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_CMDLINE_PARTITION is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=m
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_ASN1=m
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_BUS_ADDR_T_64BIT=y
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_PASID is not set
+
+#
+# PCI host controller drivers
+#
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_COREDUMP=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_HIBERNATE_CALLBACKS=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_PM_SLEEP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_CLK=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Idle
+#
+# CONFIG_CPU_IDLE is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_NET=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+CONFIG_NET_INGRESS=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=m
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_NET_IP_TUNNEL=m
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=m
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+CONFIG_GENEVE_CORE=m
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_DCTCP is not set
+# CONFIG_TCP_CONG_CDG is not set
+CONFIG_DEFAULT_BIC=y
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="bic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=m
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_NETLINK=m
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_ZONES is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set
+# CONFIG_NF_TABLES is not set
+CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+CONFIG_NETFILTER_XT_MATCH_ECN=m
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_IPV4 is not set
+CONFIG_NF_REJECT_IPV4=m
+# CONFIG_NF_NAT_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_NAT is not set
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_REJECT_IPV6=m
+# CONFIG_NF_LOG_IPV6 is not set
+# CONFIG_NF_NAT_IPV6 is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_OBJCNT is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+# CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+CONFIG_HAVE_NET_DSA=y
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=m
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_MPLS is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CGROUP_NET_CLASSID is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_JIT is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+# CONFIG_MAC80211_RC_MINSTREL_VHT is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_RFKILL_GPIO is not set
+CONFIG_NET_9P=m
+CONFIG_NET_9P_VIRTIO=m
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+CONFIG_HAVE_BPF_JIT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+
+#
+# Bus devices
+#
+# CONFIG_BRCMSTB_GISB_ARB is not set
+CONFIG_CONNECTOR=m
+# CONFIG_MTD is not set
+# CONFIG_OF is not set
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_VIRTIO_BLK=m
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_SRAM is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_93CX6=y
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+
+#
+# Altera FPGA firmware download module
+#
+
+#
+# Intel MIC Bus Driver
+#
+
+#
+# SCIF Bus Driver
+#
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+
+#
+# SCIF Driver
+#
+# CONFIG_GENWQE is not set
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_KERNEL_API is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_NETLINK=y
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SAS_HOST_SMP=y
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPT3SAS is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_SNIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_WD719X is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_BFA_FC is not set
+CONFIG_SCSI_VIRTIO=m
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+# CONFIG_SATA_PMP is not set
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_AHCI_PLATFORM=m
+# CONFIG_SATA_INIC162X is not set
+CONFIG_SATA_ACARD_AHCI=m
+CONFIG_SATA_SIL24=m
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+CONFIG_PATA_CS5536=y
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_BCACHE is not set
+CONFIG_BLK_DEV_DM_BUILTIN=y
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_MQ_DEFAULT is not set
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_BUFIO=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_LOG_WRITES is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+CONFIG_DUMMY=m
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_IPVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_GENEVE is not set
+CONFIG_NETCONSOLE=m
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_TUN=m
+# CONFIG_TUN_VNET_CROSS_LE is not set
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+# CONFIG_NLMON is not set
+# CONFIG_ARCNET is not set
+
+#
+# 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_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_AGERE is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CAVIUM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_IP1000 is not set
+# CONFIG_JME is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+CONFIG_NET_VENDOR_REALTEK=y
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_R8169 is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_SFC is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+CONFIG_REALTEK_PHY=y
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_DP83867_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_MPPE=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLHC=m
+# CONFIG_SLIP_COMPRESSED is not set
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_NET_DRIVERS=m
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AIRO is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+CONFIG_ATH_COMMON=m
+CONFIG_ATH_CARDS=m
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH5K_PCI is not set
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_COMMON=m
+CONFIG_ATH9K_BTCOEX_SUPPORT=y
+# CONFIG_ATH9K is not set
+CONFIG_ATH9K_HTC=m
+# CONFIG_ATH9K_HTC_DEBUGFS is not set
+# CONFIG_CARL9170 is not set
+# CONFIG_ATH6KL is not set
+# CONFIG_AR5523 is not set
+# CONFIG_WIL6210 is not set
+# CONFIG_ATH10K is not set
+# CONFIG_WCN36XX is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMFMAC is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL_MEDIATEK is not set
+# CONFIG_RTL_CARDS is not set
+# CONFIG_WL_TI is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_MWIFIEX is not set
+# CONFIG_CW1200 is not set
+# CONFIG_RSI_91X is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_LEDS=y
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_POLLDEV is not set
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_CYPRESS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+CONFIG_MOUSE_PS2_SENTELIC=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_FOCALTECH=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+CONFIG_MOUSE_SYNAPTICS_USB=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVMEM=y
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_PCI=m
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_DW is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_BCM63XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_VIRTIO_CONSOLE=m
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HW_RANDOM_VIRTIO=m
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_XILLYBUS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO drivers
+#
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+CONFIG_GPIO_LOONGSON=y
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_VX855 is not set
+
+#
+# MFD GPIO expanders
+#
+
+#
+# PCI GPIO expanders
+#
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_RDC321X is not set
+
+#
+# USB GPIO expanders
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_AVS is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_EMULATION is not set
+
+#
+# Texas Instruments thermal drivers
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=m
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RTSX_PCI is not set
+CONFIG_MFD_RTSX_USB=m
+# CONFIG_MFD_SM501 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+
+#
+# Direct Rendering Manager
+#
+# CONFIG_DRM is not set
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_SIMPLE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_PROC_FS=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_RAWMIDI_SEQ=m
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_DUMMY=m
+# CONFIG_SND_ALOOP is not set
+CONFIG_SND_VIRMIDI=m
+# CONFIG_SND_MTPAV is not set
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT=10
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+CONFIG_SND_CS5535AUDIO=m
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SE6X is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# HD-Audio
+#
+# CONFIG_SND_HDA_INTEL is not set
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_MIPS is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_BCD2000=m
+CONFIG_SND_USB_LINE6=m
+CONFIG_SND_USB_POD=m
+CONFIG_SND_USB_PODHD=m
+CONFIG_SND_USB_TONEPORT=m
+CONFIG_SND_USB_VARIAX=m
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+
+#
+# HID support
+#
+CONFIG_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=y
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_BETOP_FF is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+CONFIG_HID_PLANTRONICS=m
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_ULPI_BUS is not set
+CONFIG_USB_MON=m
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_PCI=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_FUSBH200_HCD is not set
+# CONFIG_USB_FOTG210_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PCI=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_REALTEK_AUTOPM=y
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_ISP1760 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_METRO is not set
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+# CONFIG_USB_SERIAL_MXUPORT is not set
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+CONFIG_USB_SERIAL_SSU100=m
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# 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
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_EZUSB_FX2=m
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_CHAOSKEY is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_CLASS_FLASH is not set
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LT3593 is not set
+
+#
+# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
+#
+# CONFIG_LEDS_PM8941_WLED is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRTIO=m
+
+#
+# Virtio drivers
+#
+CONFIG_VIRTIO_PCI=m
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=m
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+# CONFIG_COMEDI is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8723AU is not set
+# CONFIG_RTS5208 is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_FB_SM750 is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_DGNC is not set
+# CONFIG_DGAP is not set
+# CONFIG_GS_FPGABOOT is not set
+CONFIG_MIPS_PLATFORM_DEVICES=y
+CONFIG_LEMOTE_YEELOONG2F=y
+# CONFIG_LEMOTE_LYNLOONG2F is not set
+# CONFIG_CHROME_PLATFORMS is not set
+
+#
+# Hardware Spinlock drivers
+#
+
+#
+# Clock Source drivers
+#
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_MAILBOX is not set
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Generic IOMMU Pagetable Support
+#
+
+#
+# Remoteproc drivers
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_NTB is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_PWM is not set
+CONFIG_IRQ_MIPS_CPU=y
+# CONFIG_IPACK_BUS is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+CONFIG_POWERCAP=y
+# CONFIG_MCB is not set
+# CONFIG_THUNDERBOLT is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_LIBNVDIMM is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_ENCRYPTION=m
+CONFIG_EXT4_FS_ENCRYPTION=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+# CONFIG_BTRFS_DEBUG is not set
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_F2FS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_FANOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+CONFIG_OVERLAY_FS=m
+
+#
+# Caches
+#
+CONFIG_FSCACHE=m
+# CONFIG_FSCACHE_STATS is not set
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_FSCACHE_OBJECT_LIST is not set
+CONFIG_CACHEFILES=m
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_CHILDREN=y
+CONFIG_KERNFS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_CONFIGFS_FS=m
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V2=m
+CONFIG_NFS_V3=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_PNFS_BLOCK=m
+CONFIG_PNFS_FLEXFILE_LAYOUT=m
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFS_FSCACHE=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFSD is not set
+CONFIG_GRACE_PERIOD=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_SUNRPC_BACKCHANNEL=y
+CONFIG_SUNRPC_SWAP=y
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_UPCALL is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_ACL=y
+CONFIG_CIFS_DEBUG=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_DFS_UPCALL is not set
+# CONFIG_CIFS_SMB2 is not set
+# CONFIG_CIFS_FSCACHE is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_9P_FS=m
+CONFIG_9P_FSCACHE=y
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_9P_FS_SECURITY=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_MAC_ROMAN=m
+CONFIG_NLS_MAC_CELTIC=m
+CONFIG_NLS_MAC_CENTEURO=m
+CONFIG_NLS_MAC_CROATIAN=m
+CONFIG_NLS_MAC_CYRILLIC=m
+CONFIG_NLS_MAC_GAELIC=m
+CONFIG_NLS_MAC_GREEK=m
+CONFIG_NLS_MAC_ICELAND=m
+CONFIG_NLS_MAC_INUIT=m
+CONFIG_NLS_MAC_ROMANIAN=m
+CONFIG_NLS_MAC_TURKISH=m
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+
+#
+# printk and dmesg options
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+
+#
+# Compile-time checks and compiler options
+#
+# CONFIG_DEBUG_INFO is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_PAGE_OWNER is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+CONFIG_DEBUG_KERNEL=y
+
+#
+# Memory Debugging
+#
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Lockups and Hangs
+#
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHED_INFO=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+CONFIG_TIMER_STATS=y
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_STACKTRACE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+
+#
+# RCU Debugging
+#
+# CONFIG_PROVE_RCU is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_LKDTM is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_USER_COPY is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_DEBUG_ZBOOT is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_BIG_KEYS is not set
+CONFIG_ENCRYPTED_KEYS=m
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_XOR_BLOCKS=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_AKCIPHER=m
+CONFIG_CRYPTO_RSA=m
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_ECHAINIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_GHASH=y
+CONFIG_CRYPTO_POLY1305=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_CHACHA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_HASH=y
+CONFIG_CRYPTO_DRBG_CTR=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_USER_API_RNG is not set
+# CONFIG_CRYPTO_USER_API_AEAD is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_PERCPU_RWSEM=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_842_COMPRESS=m
+CONFIG_842_DECOMPRESS=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_COMPRESS=m
+CONFIG_LZ4HC_COMPRESS=m
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+CONFIG_DQL=y
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_AVERAGE=y
+CONFIG_CLZ_TAB=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_MPILIB=m
+CONFIG_OID_REGISTRY=m
+CONFIG_FONT_SUPPORT=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+CONFIG_FONT_7x14=y
+CONFIG_FONT_PEARL_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_6x10 is not set
+CONFIG_FONT_SUN8x16=y
+CONFIG_FONT_SUN12x22=y
+CONFIG_FONT_10x18=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_KVM_COMPAT=y
+CONFIG_VIRTUALIZATION=y
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 4a90476..19ad83e 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -64,6 +64,7 @@
   #:use-module (guix build-system cmake)
   #:use-module (guix build-system python)
   #:use-module (guix build-system trivial)
+  #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
   #:use-module (ice-9 match))
 
@@ -315,6 +316,32 @@ It has been modified to remove all non-free binary blobs.")
     (license gpl2)
     (home-page "http://www.gnu.org/software/linux-libre/";))))
 
+(define-public linux-libre-loongson2f
+  (package (inherit linux-libre)
+    (name "linux-libre-loongson2f")
+    (source (origin
+              (inherit (package-source linux-libre))
+              (patches
+               (map search-patch
+                    '("linux-libre-mips-hugetlb-fix.patch"
+                      "linux-libre-mips-ftrace-fix.patch"
+                      "linux-libre-mips-math-emu-fix-pt1.patch"
+                      "linux-libre-mips-math-emu-fix-pt2.patch"
+                      "linux-libre-loongson2-math-emu.patch"
+                      "linux-libre-loongson2-cpufreq-fix.patch"
+                      "linux-libre-loongson2-max-physmem-bits.patch"
+                      "linux-libre-export-loongson-chipcfg.patch"
+                      "linux-libre-yeeloong.patch"
+                      "linux-libre-yeeloong-rfkill-key-fix.patch"
+                      "linux-libre-yeeloong-silence-ec-messages.patch"
+                      "linux-libre-gdium.patch")))))
+    (supported-systems '("mips64el-linux"))
+    (native-inputs
+     (let ((conf (search-path %load-path
+                              "gnu/packages/linux-libre-loongson2f.conf")))
+       `(,@(alist-delete "kconfig" (package-native-inputs linux-libre))
+         ("kconfig" ,conf))))))
+
 
 ;;;
 ;;; Pluggable authentication modules (PAM).
diff --git a/gnu/packages/patches/linux-libre-export-loongson-chipcfg.patch 
b/gnu/packages/patches/linux-libre-export-loongson-chipcfg.patch
new file mode 100644
index 0000000..b392356
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-export-loongson-chipcfg.patch
@@ -0,0 +1,28 @@
+From: Alexandre Oliva <address@hidden>
+Date: Thu, 6 Aug 2015 01:54:21 -0400
+Subject: [PATCH 6/9] Loongson: export loongson_chipcfg
+
+Building drivers/cpufreq/loongson_cpufreq as a module would fail
+because loongson_chipcfg wasn't exported in
+arch/mips/loongson/common/env.c.  Fixed.
+
+Signed-off-by: Alexandre Oliva <address@hidden>
+---
+ arch/mips/loongson64/common/env.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/mips/loongson64/common/env.c 
b/arch/mips/loongson64/common/env.c
+index 22f04ca..fc454f2 100644
+--- a/arch/mips/loongson64/common/env.c
++++ b/arch/mips/loongson64/common/env.c
+@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap;
+ struct loongson_system_configuration loongson_sysconf;
+ 
+ u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
++EXPORT_SYMBOL_GPL(loongson_chipcfg);
+ u64 loongson_chiptemp[MAX_PACKAGES];
+ u64 loongson_freqctrl[MAX_PACKAGES];
+ 
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-gdium.patch 
b/gnu/packages/patches/linux-libre-gdium.patch
new file mode 100644
index 0000000..79bd39a
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-gdium.patch
@@ -0,0 +1,2549 @@
+Add support for the gdium laptop.  This selection of patches was derived from
+looking at the differences between the linux-stable and loongson-community git
+repositories.
+
+diff --git a/arch/mips/include/asm/mach-loongson64/machine.h 
b/arch/mips/include/asm/mach-loongson64/machine.h
+index cb2b602..78fcd38 100644
+--- a/arch/mips/include/asm/mach-loongson64/machine.h
++++ b/arch/mips/include/asm/mach-loongson64/machine.h
+@@ -24,6 +24,12 @@
+ 
+ #endif
+ 
++#ifdef CONFIG_DEXXON_GDIUM
++
++#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10
++
++#endif
++
+ #ifdef CONFIG_LOONGSON_MACH3X
+ 
+ #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC
+diff --git a/arch/mips/loongson64/Kconfig b/arch/mips/loongson64/Kconfig
+index 659ca91..e6a9ac3 100644
+--- a/arch/mips/loongson64/Kconfig
++++ b/arch/mips/loongson64/Kconfig
+@@ -59,6 +59,31 @@ config LEMOTE_MACH2F
+         These family machines include fuloong2f mini PC, yeeloong2f notebook,
+         LingLoong allinone PC and so forth.
+ 
++config DEXXON_GDIUM
++      bool "Dexxon Gdium Netbook"
++      select ARCH_SPARSEMEM_ENABLE
++      select BOARD_SCACHE
++      select BOOT_ELF32
++      select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
++      select CPU_HAS_WB
++      select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
++      select DMA_NONCOHERENT
++      select GENERIC_ISA_DMA_SUPPORT_BROKEN
++      select HW_HAS_PCI
++      select I8259
++      select IRQ_MIPS_CPU
++      select ISA
++      select SYS_HAS_CPU_LOONGSON2F
++      select SYS_HAS_EARLY_PRINTK
++      select SYS_SUPPORTS_32BIT_KERNEL
++      select SYS_SUPPORTS_64BIT_KERNEL
++      select SYS_SUPPORTS_HIGHMEM
++      select SYS_SUPPORTS_LITTLE_ENDIAN
++      select ARCH_REQUIRE_GPIOLIB
++      select HAVE_PWM if MFD_SM501
++      help
++        Dexxon gdium netbook based on Loongson 2F and SM502.
++
+ config LOONGSON_MACH3X
+       bool "Generic Loongson 3 family machines"
+       select ARCH_SPARSEMEM_ENABLE
+@@ -151,6 +176,24 @@ config LOONGSON_MC146818
+       bool
+       default n
+ 
++config GDIUM_PWM_CLOCK
++      tristate "Gdium PWM Timer"
++      default n
++      depends on HAVE_PWM && EXPERIMENTAL && BROKEN
++      select MIPS_EXTERNAL_TIMER
++      help
++        This options enables the experimental sm501-pwm based clock. With it,
++        you may be possible to use the loongson2f cpufreq driver.
++
++config GDIUM_VERSION
++      int "Configure Gdium Version"
++      depends on DEXXON_GDIUM
++      default "3"
++      help
++        I have no information about how to determine which version your board
++        is, If the default config doesn't work for it, please change it to
++        smaller ones.
++
+ config LEFI_FIRMWARE_INTERFACE
+       bool
+ 
+diff --git a/arch/mips/loongson64/Makefile b/arch/mips/loongson64/Makefile
+index 7429994..63214c8 100644
+--- a/arch/mips/loongson64/Makefile
++++ b/arch/mips/loongson64/Makefile
+@@ -17,6 +17,12 @@ obj-$(CONFIG_LEMOTE_FULOONG2E)      += fuloong-2e/
+ obj-$(CONFIG_LEMOTE_MACH2F)  += lemote-2f/
+ 
+ #
++# Dexxon gdium netbook, based on loongson 2F and SM502
++#
++
++obj-$(CONFIG_DEXXON_GDIUM)  += gdium/
++
++#
+ # All Loongson-3 family machines
+ #
+ 
+diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform
+index 0ac20eb..cd957dd 100644
+--- a/arch/mips/loongson64/Platform
++++ b/arch/mips/loongson64/Platform
+@@ -30,4 +30,5 @@ platform-$(CONFIG_MACH_LOONGSON64) += loongson/
+ cflags-$(CONFIG_MACH_LOONGSON64) += 
-I$(srctree)/arch/mips/include/asm/mach-loongson64 -mno-branch-likely
+ load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
+ load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
++load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000
+ load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000
+diff --git a/arch/mips/loongson64/common/cmdline.c 
b/arch/mips/loongson64/common/cmdline.c
+index 679a18a..96d5919 100644
+--- a/arch/mips/loongson64/common/cmdline.c
++++ b/arch/mips/loongson64/common/cmdline.c
+@@ -66,6 +66,11 @@ void __init prom_init_cmdline(void)
+               if ((strstr(arcs_cmdline, "vga=")) == NULL)
+                       strcat(arcs_cmdline, " vga=0x313");
+               break;
++      case MACH_DEXXON_GDIUM2F10:
++              /* gdium has a 1024x600 screen */
++              if ((strstr(arcs_cmdline, "video=")) == NULL)
++                      strcat(arcs_cmdline, " video=sm501fb:address@hidden");
++              break;
+       default:
+               break;
+       }
+diff --git a/arch/mips/loongson64/gdium/Makefile 
b/arch/mips/loongson64/gdium/Makefile
+new file mode 100644
+index 0000000..f3f4f51
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/Makefile
+@@ -0,0 +1,6 @@
++# Makefile for gdium
++
++obj-y += irq.o reset.o platform.o
++
++obj-$(CONFIG_MFD_SM501) += sm501-pwm.o
++obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o
+diff --git a/arch/mips/loongson64/gdium/gdium-clock.c 
b/arch/mips/loongson64/gdium/gdium-clock.c
+new file mode 100644
+index 0000000..fdbf42a
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/gdium-clock.c
+@@ -0,0 +1,234 @@
++/*
++ * Doesn't work really well. When used, the clocksource is producing
++ * bad timings and the clockevent can't be used (don't have one shot feature
++ * thus can't switch on the fly and the pwm is initialised too late to be able
++ * to use it at boot time).
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/pwm.h>
++#include <linux/clocksource.h>
++#include <linux/debugfs.h>
++#include <asm/irq_cpu.h>
++#include <asm/mipsregs.h>
++#include <asm/mips-boards/bonito64.h>
++#include <asm/time.h>
++
++#include <loongson.h>
++
++#define CLOCK_PWM             1
++#define CLOCK_PWM_FREQ                1500000                         /* Freq 
in Hz */
++#define CLOCK_LATCH           ((CLOCK_PWM_FREQ + HZ/2) / HZ)
++#define CLOCK_PWM_PERIOD      (1000000000/CLOCK_PWM_FREQ)     /* period ns  */
++#define CLOCK_PWM_DUTY                50
++#define CLOCK_PWM_IRQ         (MIPS_CPU_IRQ_BASE + 4)
++
++static const char drv_name[] = "gdium-clock";
++
++static struct pwm_device *clock_pwm;
++
++static DEFINE_SPINLOCK(clock_pwm_lock);
++static uint64_t clock_tick;
++
++static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id)
++{
++      struct clock_event_device *cd = dev_id;
++      unsigned long flag;
++
++      spin_lock_irqsave(&clock_pwm_lock, flag);
++      clock_tick++;
++      /* wait intn2 to finish */
++      do {
++              LOONGSON_INTENCLR = (1 << 13);
++      } while (LOONGSON_INTISR & (1 << 13));
++      spin_unlock_irqrestore(&clock_pwm_lock, flag);
++
++      if (cd && cd->event_handler)
++              cd->event_handler(cd);
++
++      return IRQ_HANDLED;
++}
++
++static cycle_t gdium_pwm_clock_read(struct clocksource *cs)
++{
++      unsigned long flag;
++      uint32_t jifs;
++      uint64_t ticks;
++
++      spin_lock_irqsave(&clock_pwm_lock, flag);
++      jifs = jiffies;
++      ticks = clock_tick;
++      spin_unlock_irqrestore(&clock_pwm_lock, flag);
++      /* return (cycle_t)ticks; */
++      return (cycle_t)(CLOCK_LATCH * jifs);
++}
++
++static struct clocksource gdium_pwm_clock_clocksource = {
++      .name   = "gdium_csrc",
++      .read   = gdium_pwm_clock_read,
++      .mask   = CLOCKSOURCE_MASK(64),
++      .flags  = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY,
++      .shift  = 20,
++};
++
++/* Debug fs */
++static int gdium_pwm_clock_show(struct seq_file *s, void *p)
++{
++      unsigned long flag;
++      uint64_t ticks;
++
++      spin_lock_irqsave(&clock_pwm_lock, flag);
++      ticks = clock_tick;
++      spin_unlock_irqrestore(&clock_pwm_lock, flag);
++      seq_printf(s, "%lld\n", ticks);
++      return 0;
++}
++
++static int gdium_pwm_clock_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, gdium_pwm_clock_show, inode->i_private);
++}
++
++static const struct file_operations gdium_pwm_clock_fops = {
++      .open           = gdium_pwm_clock_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .owner          = THIS_MODULE,
++};
++static struct dentry   *debugfs_file;
++
++static void gdium_pwm_clock_set_mode(enum clock_event_mode mode,
++              struct clock_event_device *evt)
++{
++      /* Nothing to do ...  */
++}
++
++static struct clock_event_device gdium_pwm_clock_cevt = {
++      .name           = "gdium_cevt",
++      .features       = CLOCK_EVT_FEAT_PERIODIC,
++      /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
++      .rating         = 299,
++      .irq            = CLOCK_PWM_IRQ,
++      .set_mode       = gdium_pwm_clock_set_mode,
++};
++
++static struct platform_device_id platform_device_ids[] = {
++      {
++              .name = "gdium-pwmclk",
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(platform, platform_device_ids);
++
++static struct platform_driver gdium_pwm_clock_driver = {
++      .driver         = {
++              .name   = drv_name,
++              .owner  = THIS_MODULE,
++      },
++      .id_table = platform_device_ids,
++};
++
++static int gdium_pwm_clock_drvinit(void)
++{
++      int ret;
++      struct clocksource *cs = &gdium_pwm_clock_clocksource;
++      struct clock_event_device *cd = &gdium_pwm_clock_cevt;
++      unsigned int cpu = smp_processor_id();
++
++      clock_tick = 0;
++
++      clock_pwm = pwm_request(CLOCK_PWM, drv_name);
++      if (clock_pwm == NULL) {
++              pr_err("unable to request PWM for Gdium clock\n");
++              return -EBUSY;
++      }
++      ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD);
++      if (ret) {
++              pr_err("unable to configure PWM for Gdium clock\n");
++              goto err_pwm_request;
++      }
++      ret = pwm_enable(clock_pwm);
++      if (ret) {
++              pr_err("unable to enable PWM for Gdium clock\n");
++              goto err_pwm_request;
++      }
++
++      cd->cpumask = cpumask_of(cpu);
++
++      cd->shift = 22;
++      cd->mult  = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift);
++      cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd);
++      cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
++      clockevents_register_device(&gdium_pwm_clock_cevt);
++
++      /* SM501 PWM1 connected to intn2 <->ip4 */
++      LOONGSON_INTPOL = (1 << 13);
++      LOONGSON_INTEDGE &= ~(1 << 13);
++      ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, 
IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt);
++      if (ret) {
++              pr_err("Can't claim irq\n");
++              goto err_pwm_disable;
++      }
++
++      cs->rating = 200;
++      cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift);
++      ret = clocksource_register(&gdium_pwm_clock_clocksource);
++      if (ret) {
++              pr_err("Can't register clocksource\n");
++              goto err_irq;
++      }
++      pr_info("Clocksource registered with shift %d and mult %d\n",
++                      cs->shift, cs->mult);
++
++      debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO,
++                      NULL, NULL, &gdium_pwm_clock_fops);
++
++      return 0;
++
++err_irq:
++      free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
++err_pwm_disable:
++      pwm_disable(clock_pwm);
++err_pwm_request:
++      pwm_free(clock_pwm);
++      return ret;
++}
++
++static void gdium_pwm_clock_drvexit(void)
++{
++      free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
++      pwm_disable(clock_pwm);
++      pwm_free(clock_pwm);
++}
++
++
++static int __devinit gdium_pwm_clock_init(void)
++{
++      int ret = gdium_pwm_clock_drvinit();
++
++      if (ret) {
++              pr_err("Fail to register gdium clock driver\n");
++              return ret;
++      }
++
++      return platform_driver_register(&gdium_pwm_clock_driver);
++}
++
++static void __exit gdium_pwm_clock_cleanup(void)
++{
++      gdium_pwm_clock_drvexit();
++      platform_driver_unregister(&gdium_pwm_clock_driver);
++}
++
++module_init(gdium_pwm_clock_init);
++module_exit(gdium_pwm_clock_cleanup);
++
++MODULE_AUTHOR("Arnaud Patard <address@hidden>");
++MODULE_DESCRIPTION("Gdium PWM clock driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:gdium-pwmclk");
+diff --git a/arch/mips/loongson64/gdium/irq.c 
b/arch/mips/loongson64/gdium/irq.c
+new file mode 100644
+index 0000000..2415d20
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/irq.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2007 Lemote Inc.
++ * Author: Fuxin Zhang, address@hidden
++ *
++ * Copyright (c) 2010 yajin <address@hidden>
++ *
++ *  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.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/module.h>
++
++#include <loongson.h>
++#include <machine.h>
++
++#define LOONGSON_TIMER_IRQ      (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
++#define LOONGSON_NORTH_BRIDGE_IRQ       (MIPS_CPU_IRQ_BASE + 6) /* bonito */
++#define LOONGSON_UART_IRQ       (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
++
++void mach_irq_dispatch(unsigned int pending)
++{
++      if (pending & CAUSEF_IP7)
++              do_IRQ(LOONGSON_TIMER_IRQ);
++      else if (pending & CAUSEF_IP6) {        /* North Bridge, Perf counter */
++              do_perfcnt_IRQ();
++              bonito_irqdispatch();
++      } else if (pending & CAUSEF_IP3)        /* CPU UART */
++              do_IRQ(LOONGSON_UART_IRQ);
++#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE)
++      else if (pending & CAUSEF_IP4)          /* SM501 PWM clock */
++              do_IRQ(MIPS_CPU_IRQ_BASE + 4);
++#endif
++      else
++              spurious_interrupt();
++}
++
++static irqreturn_t ip6_action(int cpl, void *dev_id)
++{
++      return IRQ_HANDLED;
++}
++
++struct irqaction ip6_irqaction = {
++      .handler = ip6_action,
++      .name = "cascade",
++      .flags = IRQF_SHARED,
++};
++
++void __init mach_init_irq(void)
++{
++      /* setup north bridge irq (bonito) */
++      setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
++}
+diff --git a/arch/mips/loongson64/gdium/platform.c 
b/arch/mips/loongson64/gdium/platform.c
+new file mode 100644
+index 0000000..ffafba4
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/platform.c
+@@ -0,0 +1,135 @@
++/*
++ * Copyright (c) 2009 Philippe Vachon <address@hidden>
++ *
++ * 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.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/pwm_backlight.h>
++#include <linux/i2c.h>
++#include <linux/i2c-gpio.h>
++
++#define GDIUM_GPIO_BASE 224
++
++static struct i2c_board_info __initdata sm502dev_i2c_devices[] = {
++      {
++              I2C_BOARD_INFO("lm75", 0x48),
++      },
++      {
++              I2C_BOARD_INFO("m41t83", 0x68),
++      },
++      {
++              I2C_BOARD_INFO("gdium-laptop", 0x40),
++      },
++};
++
++static int sm502dev_backlight_init(struct device *dev)
++{
++      /* Add gpio request stuff here */
++      return 0;
++}
++
++static void sm502dev_backlight_exit(struct device *dev)
++{
++      /* Add gpio free stuff here */
++}
++
++static struct platform_pwm_backlight_data backlight_data = {
++      .pwm_id         = 0,
++      .max_brightness = 15,
++      .dft_brightness = 8,
++      .pwm_period_ns  = 50000, /* 20 kHz */
++      .init           = sm502dev_backlight_init,
++      .exit           = sm502dev_backlight_exit,
++};
++
++static struct platform_device backlight = {
++      .name = "pwm-backlight",
++      .dev  = {
++              .platform_data = &backlight_data,
++      },
++      .id   = -1,
++};
++
++/*
++ * Warning this stunt is very dangerous
++ * as the sm501 gpio have dynamic numbers...
++ */
++/* bus 0 is the one for the ST7, DS75 etc... */
++static struct i2c_gpio_platform_data i2c_gpio0_data = {
++#if CONFIG_GDIUM_VERSION > 2
++      .sda_pin        = GDIUM_GPIO_BASE + 13,
++      .scl_pin        = GDIUM_GPIO_BASE + 6,
++#else
++      .sda_pin        = 192+15,
++      .scl_pin        = 192+14,
++#endif
++      .udelay         = 5,
++      .timeout        = HZ / 10,
++      .sda_is_open_drain = 0,
++      .scl_is_open_drain = 0,
++};
++
++static struct platform_device i2c_gpio0_device = {
++      .name   = "i2c-gpio",
++      .id     = 0,
++      .dev    = { .platform_data  = &i2c_gpio0_data, },
++};
++
++/* bus 1 is for the CRT/VGA external screen */
++static struct i2c_gpio_platform_data i2c_gpio1_data = {
++      .sda_pin        = GDIUM_GPIO_BASE + 10,
++      .scl_pin        = GDIUM_GPIO_BASE + 9,
++      .udelay         = 5,
++      .timeout        = HZ / 10,
++      .sda_is_open_drain = 0,
++      .scl_is_open_drain = 0,
++};
++
++static struct platform_device i2c_gpio1_device = {
++      .name   = "i2c-gpio",
++      .id     = 1,
++      .dev    = { .platform_data  = &i2c_gpio1_data, },
++};
++
++static struct platform_device gdium_clock = {
++      .name           = "gdium-pwmclk",
++      .id             = -1,
++};
++
++static struct platform_device *devices[] __initdata = {
++      &i2c_gpio0_device,
++      &i2c_gpio1_device,
++      &backlight,
++      &gdium_clock,
++};
++
++static int __init gdium_platform_devices_setup(void)
++{
++      int ret;
++
++      pr_info("Registering gdium platform devices\n");
++
++      ret = i2c_register_board_info(0, sm502dev_i2c_devices,
++              ARRAY_SIZE(sm502dev_i2c_devices));
++
++      if (ret != 0) {
++              pr_info("Error while registering platform devices: %d\n", ret);
++              return ret;
++      }
++
++      platform_add_devices(devices, ARRAY_SIZE(devices));
++
++      return 0;
++}
++
++/*
++ * some devices are on the pwm stuff which is behind the mfd which is
++ * behind the pci bus so arch_initcall can't work because too early
++ */
++late_initcall(gdium_platform_devices_setup);
+diff --git a/arch/mips/loongson64/gdium/reset.c 
b/arch/mips/loongson64/gdium/reset.c
+new file mode 100644
+index 0000000..8289f95
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/reset.c
+@@ -0,0 +1,22 @@
++/* Board-specific reboot/shutdown routines
++ *
++ * Copyright (C) 2010 yajin <address@hidden>
++ *
++ * 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.
++ */
++#include <loongson.h>
++
++void mach_prepare_shutdown(void)
++{
++      LOONGSON_GPIOIE &= ~(1<<1);
++      LOONGSON_GPIODATA |= (1<<1);
++}
++
++void mach_prepare_reboot(void)
++{
++      LOONGSON_GPIOIE &= ~(1<<2);
++      LOONGSON_GPIODATA &= ~(1<<2);
++}
+diff --git a/arch/mips/loongson64/gdium/sm501-pwm.c 
b/arch/mips/loongson64/gdium/sm501-pwm.c
+new file mode 100644
+index 0000000..5af3b23
+--- /dev/null
++++ b/arch/mips/loongson64/gdium/sm501-pwm.c
+@@ -0,0 +1,465 @@
++/*
++ * SM501 PWM clock
++ * Copyright (C) 2009-2010 Arnaud Patard <address@hidden>
++ *
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/pwm.h>
++#include <linux/sm501.h>
++#include <linux/sm501-regs.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++
++static const char drv_name[] = "sm501-pwm";
++
++#define INPUT_CLOCK           96 /* MHz */
++#define PWM_COUNT             3
++
++#define SM501PWM_HIGH_COUNTER (1<<20)
++#define SM501PWM_LOW_COUNTER  (1<<8)
++#define SM501PWM_CLOCK_DIVIDE (1>>4)
++#define SM501PWM_IP           (1<<3)
++#define SM501PWM_I            (1<<2)
++#define SM501PWM_E            (1<<0)
++
++struct pwm_device {
++      struct list_head        node;
++      struct device           *dev;
++      void __iomem            *regs;
++      int                     duty_ns;
++      int                     period_ns;
++      char                    enabled;
++      void                    (*handler)(struct pwm_device *pwm);
++
++      const char              *label;
++      unsigned int            use_count;
++      unsigned int            pwm_id;
++};
++
++struct sm501pwm_info {
++      void __iomem    *regs;
++      int             irq;
++      struct resource *res;
++      struct device   *dev;
++      struct dentry   *debugfs;
++
++      struct pwm_device pwm[3];
++};
++
++int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
++{
++      unsigned int high, low, divider;
++      int divider1, divider2;
++      unsigned long long delay;
++
++      if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns)
++              return -EINVAL;
++
++      /* Get delay
++       * We're loosing some precision but multiplying then dividing
++       * will overflow
++       */
++      if (period_ns > 1000) {
++              delay = period_ns / 1000;
++              delay *= INPUT_CLOCK;
++      } else {
++              delay = period_ns * 96;
++              delay /= 1000;
++      }
++
++      /* Get the number of clock low and high */
++      high  = delay * duty_ns / period_ns;
++      low = delay - high;
++
++      /* Get divider to make 'low' and 'high' fit into 12 bits */
++      /* No need to say that the divider must be >= 0 */
++      divider1 = fls(low)-12;
++      divider2 = fls(high)-12;
++
++      if (divider1 < 0)
++              divider1 = 0;
++      if (divider2 < 0)
++              divider2 = 0;
++
++      divider = max(divider1, divider2);
++
++      low >>= divider;
++      high >>= divider;
++
++      pwm->duty_ns = duty_ns;
++      pwm->period_ns = period_ns;
++
++      writel((high<<20)|(low<<8)|(divider<<4), pwm->regs);
++      return 0;
++}
++EXPORT_SYMBOL(pwm_config);
++
++int pwm_enable(struct pwm_device *pwm)
++{
++      u32 reg;
++
++      if (!pwm)
++              return -EINVAL;
++
++      switch (pwm->pwm_id) {
++      case 0:
++              sm501_configure_gpio(pwm->dev->parent, 29, 1);
++              break;
++      case 1:
++              sm501_configure_gpio(pwm->dev->parent, 30, 1);
++              break;
++      case 2:
++              sm501_configure_gpio(pwm->dev->parent, 31, 1);
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      reg = readl(pwm->regs);
++      reg |= (SM501PWM_IP | SM501PWM_E);
++      writel(reg, pwm->regs);
++      pwm->enabled = 1;
++
++      return 0;
++}
++EXPORT_SYMBOL(pwm_enable);
++
++void pwm_disable(struct pwm_device *pwm)
++{
++      u32 reg;
++
++      if (!pwm)
++              return;
++
++      reg = readl(pwm->regs);
++      reg &= ~(SM501PWM_IP | SM501PWM_E);
++      writel(reg, pwm->regs);
++
++      switch (pwm->pwm_id) {
++      case 0:
++              sm501_configure_gpio(pwm->dev->parent, 29, 0);
++              break;
++      case 1:
++              sm501_configure_gpio(pwm->dev->parent, 30, 0);
++              break;
++      case 2:
++              sm501_configure_gpio(pwm->dev->parent, 31, 0);
++              break;
++      default:
++              break;
++      }
++      pwm->enabled = 0;
++}
++EXPORT_SYMBOL(pwm_disable);
++
++static DEFINE_MUTEX(pwm_lock);
++static LIST_HEAD(pwm_list);
++
++struct pwm_device *pwm_request(int pwm_id, const char *label)
++{
++      struct pwm_device *pwm;
++      int found = 0;
++
++      mutex_lock(&pwm_lock);
++
++      list_for_each_entry(pwm, &pwm_list, node) {
++              if (pwm->pwm_id == pwm_id && pwm->use_count == 0) {
++                      pwm->use_count++;
++                      pwm->label = label;
++                      found = 1;
++                      break;
++              }
++      }
++
++      mutex_unlock(&pwm_lock);
++
++      return (found) ? pwm : NULL;
++}
++EXPORT_SYMBOL(pwm_request);
++
++void pwm_free(struct pwm_device *pwm)
++{
++      mutex_lock(&pwm_lock);
++
++      if (pwm->use_count) {
++              pwm->use_count--;
++              pwm->label = NULL;
++      } else
++              dev_warn(pwm->dev, "PWM device already freed\n");
++
++      mutex_unlock(&pwm_lock);
++}
++EXPORT_SYMBOL(pwm_free);
++
++int pwm_int_enable(struct pwm_device *pwm)
++{
++      unsigned long conf;
++
++      if (!pwm || !pwm->regs || !pwm->handler)
++              return -EINVAL;
++
++      conf = readl(pwm->regs);
++      conf |= SM501PWM_I;
++      writel(conf, pwm->regs);
++      return 0;
++}
++EXPORT_SYMBOL(pwm_int_enable);
++
++int pwm_int_disable(struct pwm_device *pwm)
++{
++      unsigned long conf;
++
++      if (!pwm || !pwm->regs || !pwm->handler)
++              return -EINVAL;
++
++      conf = readl(pwm->regs);
++      conf &= ~SM501PWM_I;
++      writel(conf, pwm->regs);
++      return 0;
++}
++EXPORT_SYMBOL(pwm_int_disable);
++
++int pwm_set_handler(struct pwm_device *pwm,
++                  void (*handler)(struct pwm_device *pwm))
++{
++      if (!pwm || !handler)
++              return -EINVAL;
++      pwm->handler = handler;
++      return 0;
++}
++EXPORT_SYMBOL(pwm_set_handler);
++
++static irqreturn_t sm501pwm_irq(int irq, void *dev_id)
++{
++      unsigned long value;
++      struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id;
++      struct pwm_device *pwm;
++      int i;
++
++      value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0);
++
++      /* Check is the interrupt is for us */
++      if (value & (1<<22)) {
++              for (i = 0 ; i < PWM_COUNT ; i++) {
++                      /*
++                       * Find which pwm triggered the interrupt
++                       * and ack
++                       */
++                      value = readl(info->regs + i*4);
++                      if (value & SM501PWM_IP)
++                              writel(value | SM501PWM_IP, info->regs + i*4);
++
++                      pwm = &info->pwm[i];
++                      if (pwm->handler)
++                              pwm->handler(pwm);
++              }
++              return IRQ_HANDLED;
++      }
++
++      return IRQ_NONE;
++}
++
++static void add_pwm(int id, struct sm501pwm_info *info)
++{
++      struct pwm_device *pwm = &info->pwm[id];
++
++      pwm->use_count  = 0;
++      pwm->pwm_id     = id;
++      pwm->dev        = info->dev;
++      pwm->regs       = info->regs + id * 4;
++
++      mutex_lock(&pwm_lock);
++      list_add_tail(&pwm->node, &pwm_list);
++      mutex_unlock(&pwm_lock);
++}
++
++static void del_pwm(int id, struct sm501pwm_info *info)
++{
++      struct pwm_device *pwm = &info->pwm[id];
++
++      pwm->use_count  = 0;
++      pwm->pwm_id     = -1;
++      mutex_lock(&pwm_lock);
++      list_del(&pwm->node);
++      mutex_unlock(&pwm_lock);
++}
++
++/* Debug fs */
++static int sm501pwm_show(struct seq_file *s, void *p)
++{
++      struct pwm_device *pwm;
++
++      mutex_lock(&pwm_lock);
++      list_for_each_entry(pwm, &pwm_list, node) {
++              if (pwm->use_count) {
++                      seq_printf(s, "pwm-%d (%12s) %d %d %s\n",
++                                      pwm->pwm_id, pwm->label,
++                                      pwm->duty_ns, pwm->period_ns,
++                                      pwm->enabled ? "on" : "off");
++                      seq_printf(s, "       %08x\n", readl(pwm->regs));
++              }
++      }
++      mutex_unlock(&pwm_lock);
++
++      return 0;
++}
++
++static int sm501pwm_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, sm501pwm_show, inode->i_private);
++}
++
++static const struct file_operations sm501pwm_fops = {
++      .open           = sm501pwm_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .owner          = THIS_MODULE,
++};
++
++static int __init sm501pwm_probe(struct platform_device *pdev)
++{
++      struct sm501pwm_info *info;
++      struct device   *dev = &pdev->dev;
++      struct resource *res;
++      int ret = 0;
++      int res_len;
++      int i;
++
++      info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL);
++      if (!info) {
++              dev_err(dev, "Allocation failure\n");
++              ret = -ENOMEM;
++              goto err;
++      }
++      info->dev = dev;
++      platform_set_drvdata(pdev, info);
++
++      /* Get irq number */
++      info->irq = platform_get_irq(pdev, 0);
++      if (!info->irq) {
++              dev_err(dev, "no irq found\n");
++              ret = -ENODEV;
++              goto err_alloc;
++      }
++
++      /* Get regs address */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(dev, "No memory resource found\n");
++              ret = -ENODEV;
++              goto err_alloc;
++      }
++      info->res = res;
++      res_len = (res->end - res->start)+1;
++
++      if (!request_mem_region(res->start, res_len, drv_name)) {
++              dev_err(dev, "Can't request iomem resource\n");
++              ret = -EBUSY;
++              goto err_alloc;
++      }
++
++      info->regs = ioremap(res->start, res_len);
++      if (!info->regs) {
++              dev_err(dev, "ioremap failed\n");
++              ret = -ENOMEM;
++              goto err_mem;
++      }
++
++      ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info);
++      if (ret != 0) {
++              dev_err(dev, "can't get irq\n");
++              goto err_map;
++      }
++
++
++      sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1);
++
++      for (i = 0; i < 3; i++)
++              add_pwm(i, info);
++
++      dev_info(dev, "SM501 PWM Found at %lx irq %d\n",
++               (unsigned long)info->res->start, info->irq);
++
++      info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO,
++                              NULL, info, &sm501pwm_fops);
++
++
++      return 0;
++
++err_map:
++      iounmap(info->regs);
++
++err_mem:
++      release_mem_region(res->start, res_len);
++
++err_alloc:
++      kfree(info);
++      platform_set_drvdata(pdev, NULL);
++err:
++      return ret;
++}
++
++static int sm501pwm_remove(struct platform_device *pdev)
++{
++      struct sm501pwm_info *info = platform_get_drvdata(pdev);
++      int i;
++
++      if (info->debugfs)
++              debugfs_remove(info->debugfs);
++
++      for (i = 0; i < 3; i++) {
++              pwm_disable(&info->pwm[i]);
++              del_pwm(i, info);
++      }
++
++      sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0);
++      sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22);
++
++      free_irq(info->irq, info);
++      iounmap(info->regs);
++      release_mem_region(info->res->start,
++                         (info->res->end - info->res->start)+1);
++      kfree(info);
++      platform_set_drvdata(pdev, NULL);
++
++      return 0;
++}
++
++static struct platform_driver sm501pwm_driver = {
++      .probe          = sm501pwm_probe,
++      .remove         = sm501pwm_remove,
++      .driver         = {
++              .name   = drv_name,
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __devinit sm501pwm_init(void)
++{
++      return platform_driver_register(&sm501pwm_driver);
++}
++
++static void __exit sm501pwm_cleanup(void)
++{
++      platform_driver_unregister(&sm501pwm_driver);
++}
++
++module_init(sm501pwm_init);
++module_exit(sm501pwm_cleanup);
++
++MODULE_AUTHOR("Arnaud Patard <address@hidden>");
++MODULE_DESCRIPTION("SM501 PWM driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:sm501-pwm");
+diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
+index 2eda01e..8adaa3d 100644
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_LASAT)          += pci-lasat.o
+ obj-$(CONFIG_MIPS_COBALT)     += fixup-cobalt.o
+ obj-$(CONFIG_LEMOTE_FULOONG2E)        += fixup-fuloong2e.o ops-loongson2.o
+ obj-$(CONFIG_LEMOTE_MACH2F)   += fixup-lemote2f.o ops-loongson2.o
++obj-$(CONFIG_DEXXON_GDIUM)      += fixup-gdium.o ops-loongson2.o
+ obj-$(CONFIG_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o
+ obj-$(CONFIG_MIPS_MALTA)      += fixup-malta.o pci-malta.o
+ obj-$(CONFIG_PMC_MSP7120_GW)  += fixup-pmcmsp.o ops-pmcmsp.o
+diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c
+new file mode 100644
+index 0000000..b296220
+--- /dev/null
++++ b/arch/mips/pci/fixup-gdium.c
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2010 yajin <address@hidden>
++ *
++ *  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.
++ */
++
++#include <linux/init.h>
++#include <linux/pci.h>
++
++#include <loongson.h>
++/*
++ * http://www.pcidatabase.com
++ * GDIUM has different PCI mapping
++ *  slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI
++ *  slog 14 (0x126f/0x0501) -> sm501
++ *  slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers
++ *                             plus Single EHCI controller
++ *  slot 16 (0x10ec/0x8139) -> Realtek 8139c
++ *  slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller
++ */
++
++#undef INT_IRQA
++#undef INT_IRQB
++#undef INT_IRQC
++#undef INT_IRQD
++#define INT_IRQA 36
++#define INT_IRQB 37
++#define INT_IRQC 38
++#define INT_IRQD 39
++
++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++      int irq = 0;
++
++      switch (slot) {
++      case 13:
++              irq = INT_IRQC + ((pin - 1) & 3);
++              break;
++      case 14:
++              irq = INT_IRQA;
++              break;
++      case 15:
++#if CONFIG_GDIUM_VERSION > 2
++              irq = INT_IRQB;
++#else
++              irq = INT_IRQA + ((pin - 1) & 3);
++#endif
++              break;
++      case 16:
++              irq = INT_IRQD;
++              break;
++#if CONFIG_GDIUM_VERSION > 2
++      case 17:
++              irq = INT_IRQC;
++              break;
++#endif
++      default:
++              pr_info(" strange pci slot number %d on gdium.\n", slot);
++              break;
++      }
++      return irq;
++}
++
++/* Do platform specific device initialization at pci_enable_device() time */
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++      return 0;
++}
++
++/* Fixups for the USB host controllers */
++static void __init gdium_usb_host_fixup(struct pci_dev *dev)
++{
++      unsigned int val;
++      pci_read_config_dword(dev, 0xe0, &val);
++#if CONFIG_GDIUM_VERSION > 2
++      pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3);
++#else
++      pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5);
++      pci_write_config_dword(dev, 0xe4, 1<<5);
++#endif
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
++                              gdium_usb_host_fixup);
++#if CONFIG_GDIUM_VERSION > 2
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550,
++                              gdium_usb_host_fixup);
++#endif
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index 15338af..e839ebf 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -869,6 +869,13 @@ config HID_ZYDACRON
+       ---help---
+       Support for Zydacron remote control.
+ 
++config HID_GDIUM
++      bool "Gdium Fn keys support" if EMBEDDED
++      depends on USB_HID && DEXXON_GDIUM
++      default !EMBEDDED
++      ---help---
++      Support for Functions keys available on Gdiums.
++
+ config HID_SENSOR_HUB
+       tristate "HID Sensors framework support"
+       depends on HID && HAS_IOMEM
+diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
+index e4a21df..51fc941 100644
+--- a/drivers/hid/Makefile
++++ b/drivers/hid/Makefile
+@@ -98,6 +98,7 @@ obj-$(CONFIG_HID_ZYDACRON)   += hid-zydacron.o
+ wacom-objs                    := wacom_wac.o wacom_sys.o
+ obj-$(CONFIG_HID_WACOM)               += wacom.o
+ obj-$(CONFIG_HID_WALTOP)      += hid-waltop.o
++obj-$(CONFIG_HID_GDIUM)               += hid-gdium.o
+ obj-$(CONFIG_HID_WIIMOTE)     += hid-wiimote.o
+ obj-$(CONFIG_HID_SENSOR_HUB)  += hid-sensor-hub.o
+ obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR)        += hid-sensor-custom.o
+diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c
+new file mode 100644
+index 0000000..67cc095
+--- /dev/null
++++ b/drivers/hid/hid-gdium.c
+@@ -0,0 +1,210 @@
++/*
++ * hid-gdium  --  Gdium laptop function keys
++ *
++ * Arnaud Patard <address@hidden>
++ *
++ * Based on hid-apple.c
++ *
++ *  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.
++ */
++
++
++#include <linux/device.h>
++#include <linux/hid.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++
++#include "hid-ids.h"
++
++#define GDIUM_FN_ON   1
++
++static int fnmode = GDIUM_FN_ON;
++module_param(fnmode, int, 0644);
++MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = 
Enabled)");
++
++struct gdium_data {
++      unsigned int fn_on;
++};
++
++
++struct gdium_key_translation {
++      u16 from;
++      u16 to;
++};
++
++static struct gdium_key_translation gdium_fn_keys[] = {
++      { KEY_F1,       KEY_CAMERA },
++      { KEY_F2,       KEY_CONNECT },
++      { KEY_F3,       KEY_MUTE },
++      { KEY_F4,       KEY_VOLUMEUP},
++      { KEY_F5,       KEY_VOLUMEDOWN },
++      { KEY_F6,       KEY_SWITCHVIDEOMODE },
++      { KEY_F7,       KEY_F19 }, /* F7+12. Have to use existant keycodes */
++      { KEY_F8,       KEY_BRIGHTNESSUP },
++      { KEY_F9,       KEY_BRIGHTNESSDOWN },
++      { KEY_F10,      KEY_SLEEP },
++      { KEY_F11,      KEY_PROG1 },
++      { KEY_F12,      KEY_PROG2 },
++      { KEY_UP,       KEY_PAGEUP },
++      { KEY_DOWN,     KEY_PAGEDOWN },
++      { KEY_INSERT,   KEY_NUMLOCK },
++      { KEY_DELETE,   KEY_SCROLLLOCK },
++      { KEY_T,        KEY_STOPCD },
++      { KEY_F,        KEY_PREVIOUSSONG },
++      { KEY_H,        KEY_NEXTSONG },
++      { KEY_G,        KEY_PLAYPAUSE },
++      { }
++};
++
++static struct gdium_key_translation *gdium_find_translation(
++              struct gdium_key_translation *table, u16 from)
++{
++      struct gdium_key_translation *trans;
++
++      /* Look for the translation */
++      for (trans = table; trans->from; trans++)
++              if (trans->from == from)
++                      return trans;
++      return NULL;
++}
++
++static int hidinput_gdium_event(struct hid_device *hid, struct input_dev 
*input,
++              struct hid_usage *usage, __s32 value)
++{
++      struct gdium_data *data = hid_get_drvdata(hid);
++      struct gdium_key_translation *trans;
++      int do_translate;
++
++      if (usage->type != EV_KEY)
++              return 0;
++
++      if ((usage->code == KEY_FN)) {
++              data->fn_on = !!value;
++              input_event(input, usage->type, usage->code, value);
++              return 1;
++      }
++
++      if (fnmode) {
++              trans = gdium_find_translation(gdium_fn_keys, usage->code);
++              if (trans) {
++                      do_translate = data->fn_on;
++                      if (do_translate) {
++                              input_event(input, usage->type, trans->to, 
value);
++                              return 1;
++                      }
++              }
++      }
++
++      return 0;
++}
++
++static int gdium_input_event(struct hid_device *hdev, struct hid_field *field,
++                      struct hid_usage *usage, __s32 value)
++{
++      if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 
!usage->type)
++              return 0;
++
++      if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value))
++              return 1;
++
++      return 0;
++}
++
++
++static void gdium_input_setup(struct input_dev *input)
++{
++      struct gdium_key_translation *trans;
++
++      set_bit(KEY_NUMLOCK, input->keybit);
++
++      /* Enable all needed keys */
++      for (trans = gdium_fn_keys; trans->from; trans++)
++              set_bit(trans->to, input->keybit);
++}
++
++static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi,
++              struct hid_field *field, struct hid_usage *usage,
++              unsigned long **bit, int *max)
++{
++      if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD)
++                      && ((usage->hid & HID_USAGE) == 0x82)) {
++              hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
++              gdium_input_setup(hi->input);
++              return 1;
++      }
++      return 0;
++}
++
++static int gdium_input_probe(struct hid_device *hdev, const struct 
hid_device_id *id)
++{
++      struct gdium_data *data;
++      int ret;
++
++      data = kzalloc(sizeof(*data), GFP_KERNEL);
++      if (!data) {
++              dev_err(&hdev->dev, "can't alloc gdium keyboard data\n");
++              return -ENOMEM;
++      }
++
++      hid_set_drvdata(hdev, data);
++
++      ret = hid_parse(hdev);
++      if (ret) {
++              dev_err(&hdev->dev, "parse failed\n");
++              goto err_free;
++      }
++
++      ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
++      if (ret) {
++              dev_err(&hdev->dev, "hw start failed\n");
++              goto err_free;
++      }
++
++      return 0;
++err_free:
++      kfree(data);
++      return ret;
++}
++static void gdium_input_remove(struct hid_device *hdev)
++{
++      hid_hw_stop(hdev);
++      kfree(hid_get_drvdata(hdev));
++}
++
++static const struct hid_device_id gdium_input_devices[] = {
++      { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) },
++      {}
++};
++MODULE_DEVICE_TABLE(hid, gdium_input_devices);
++
++static struct hid_driver gdium_input_driver = {
++      .name = "gdium-fnkeys",
++      .id_table = gdium_input_devices,
++      .probe = gdium_input_probe,
++      .remove = gdium_input_remove,
++      .event = gdium_input_event,
++      .input_mapping = gdium_input_mapping,
++};
++
++static int gdium_input_init(void)
++{
++      int ret;
++
++      ret = hid_register_driver(&gdium_input_driver);
++      if (ret)
++               pr_err("can't register gdium keyboard driver\n");
++
++      return ret;
++}
++static void gdium_input_exit(void)
++{
++      hid_unregister_driver(&gdium_input_driver);
++}
++
++module_init(gdium_input_init);
++module_exit(gdium_input_exit);
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 7ce93d9..da52392 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -1018,6 +1018,9 @@
+ #define USB_VENDOR_ID_ZYTRONIC                0x14c8
+ #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005
+ 
++#define USB_VENDOR_ID_GDIUM           0x04B4
++#define USB_DEVICE_ID_GDIUM           0xe001
++
+ #define USB_VENDOR_ID_PRIMAX  0x0461
+ #define USB_DEVICE_ID_PRIMAX_MOUSE_4D22       0x4d22
+ #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
+diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
+index 91077ef..2cfd9ff 100644
+--- a/drivers/mfd/sm501.c
++++ b/drivers/mfd/sm501.c
+@@ -58,7 +58,7 @@ struct sm501_gpio {
+ struct sm501_gpio {
+       /* no gpio support, empty definition for sm501_devdata. */
+ };
+-#endif
++#endif        /* CONFIG_MFD_SM501_GPIO */
+ 
+ struct sm501_devdata {
+       spinlock_t                       reg_lock;
+@@ -1124,6 +1124,22 @@ static inline int sm501_gpio_isregistered(struct 
sm501_devdata *sm)
+ {
+       return sm->gpio.registered;
+ }
++
++void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned
++              char mode)
++{
++      unsigned long set, reg, offset = gpio;
++
++      if (offset >= 32) {
++              reg = SM501_GPIO63_32_CONTROL;
++              offset = gpio - 32;
++      } else
++              reg = SM501_GPIO31_0_CONTROL;
++
++      set = mode ? 1 << offset : 0;
++
++      sm501_modify_reg(dev, reg, set, 0);
++}
+ #else
+ static inline int sm501_register_gpio(struct sm501_devdata *sm)
+ {
+@@ -1143,7 +1159,13 @@ static inline int sm501_gpio_isregistered(struct 
sm501_devdata *sm)
+ {
+       return 0;
+ }
+-#endif
++
++void sm501_configure_gpio(struct device *dev, unsigned int gpio,
++                       unsigned char mode)
++{
++}
++#endif        /* CONFIG_MFD_SM501_GPIO */
++EXPORT_SYMBOL_GPL(sm501_configure_gpio);
+ 
+ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
+                                           struct sm501_platdata_gpio_i2c *iic)
+@@ -1198,6 +1220,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata 
*sm,
+       return 0;
+ }
+ 
++/* register sm501 PWM device */
++static int sm501_register_pwm(struct sm501_devdata *sm)
++{
++      struct platform_device *pdev;
++
++      pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0);
++      if (!pdev)
++              return -ENOMEM;
++      sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC);
++      sm501_create_irq(sm, &pdev->resource[1]);
++
++      return sm501_register_device(sm, pdev);
++}
++
+ /* sm501_dbg_regs
+  *
+  * Debug attribute to attach to parent device to show core registers
+@@ -1356,6 +1392,8 @@ static int sm501_init_dev(struct sm501_devdata *sm)
+                       sm501_register_uart(sm, idata->devices);
+               if (idata->devices & SM501_USE_GPIO)
+                       sm501_register_gpio(sm);
++              if (idata->devices & SM501_USE_PWM)
++                      sm501_register_pwm(sm);
+       }
+ 
+       if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
+@@ -1542,10 +1580,15 @@ static struct sm501_initdata sm501_pci_initdata = {
+       .devices        = SM501_USE_ALL,
+ 
+       /* Errata AB-3 says that 72MHz is the fastest available
+-       * for 33MHZ PCI with proper bus-mastering operation */
+-
++       * for 33MHZ PCI with proper bus-mastering operation
++       * For gdium, it works under 84&112M clock freq.*/
++#ifdef CONFIG_DEXXON_GDIUM
++      .mclk           = 84 * MHZ,
++      .m1xclk         = 112 * MHZ,
++#else
+       .mclk           = 72 * MHZ,
+       .m1xclk         = 144 * MHZ,
++#endif
+ };
+ 
+ static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
+diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
+index c80714b..70a607d 100644
+--- a/drivers/platform/mips/Kconfig
++++ b/drivers/platform/mips/Kconfig
+@@ -47,6 +47,17 @@ config LEMOTE_LYNLOONG2F
+         size-fixed screen: 1360x768 with sisfb video driver. and also, it has
+         its own specific suspend support.
+ 
++config GDIUM_LAPTOP
++      tristate "GDIUM laptop extras"
++      depends on DEXXON_GDIUM
++      select POWER_SUPPLY
++      select I2C
++      select INPUT_POLLDEV
++      default m
++      help
++        This mini-driver drives the ST7 chipset present in the Gdium laptops.
++        This gives battery support, wlan rfkill.
++
+ config MIPS_ACPI
+       bool
+       default y if LOONGSON_MACH3X
+diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
+index 0e21bfb..0bc93de 100644
+--- a/drivers/platform/mips/Makefile
++++ b/drivers/platform/mips/Makefile
+@@ -7,5 +7,7 @@ CFLAGS_yeeloong_laptop.o = 
-I$(srctree)/arch/mips/loongson64/lemote-2f
+ 
+ obj-$(CONFIG_LEMOTE_LYNLOONG2F)       += lynloong_pc.o
+ 
++obj-$(CONFIG_GDIUM_LAPTOP)    += gdium_laptop.o
++
+ obj-$(CONFIG_MIPS_ACPI) += acpi_init.o
+ obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o
+diff --git a/drivers/platform/mips/gdium_laptop.c 
b/drivers/platform/mips/gdium_laptop.c
+new file mode 100644
+index 0000000..41a65ad
+--- /dev/null
++++ b/drivers/platform/mips/gdium_laptop.c
+@@ -0,0 +1,927 @@
++/*
++ * gdium_laptop  --  Gdium laptop extras
++ *
++ * Arnaud Patard <address@hidden>
++ *
++ *  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.
++ *
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/input-polldev.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/i2c.h>
++#include <linux/mutex.h>
++#include <linux/power_supply.h>
++#include <linux/workqueue.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <asm/gpio.h>
++
++/* For input device */
++#define SCAN_INTERVAL         150
++
++/* For battery status */
++#define BAT_SCAN_INTERVAL     500
++
++#define EC_FIRM_VERSION               0
++
++#if CONFIG_GDIUM_VERSION > 2
++#define EC_REG_BASE           1
++#else
++#define EC_REG_BASE           0
++#endif
++
++#define EC_STATUS             (EC_REG_BASE+0)
++#define EC_STATUS_LID         (1<<0)
++#define EC_STATUS_PWRBUT      (1<<1)
++#define EC_STATUS_BATID               (1<<2)          /* this bit has no real 
meaning on v2.         */
++                                              /* Same as EC_STATUS_ADAPT      
               */
++                                              /* but on v3 it's BATID which 
mean bat present */
++#define EC_STATUS_SYS_POWER   (1<<3)
++#define EC_STATUS_WLAN                (1<<4)
++#define EC_STATUS_ADAPT               (1<<5)
++
++#define EC_CTRL                       (EC_REG_BASE+1)
++#define EC_CTRL_DDR_CLK               (1<<0)
++#define EC_CTRL_CHARGE_LED    (1<<1)
++#define EC_CTRL_BEEP          (1<<2)
++#define EC_CTRL_SUSB          (1<<3)  /* memory power */
++#define EC_CTRL_TRICKLE               (1<<4)
++#define EC_CTRL_WLAN_EN               (1<<5)
++#define EC_CTRL_SUSC          (1<<6) /* main power */
++#define EC_CTRL_CHARGE_EN     (1<<7)
++
++#define EC_BAT_LOW            (EC_REG_BASE+2)
++#define EC_BAT_HIGH           (EC_REG_BASE+3)
++
++#define EC_SIGN                       (EC_REG_BASE+4)
++#define EC_SIGN_OS            0xAE /* write 0xae to control pm stuff */
++#define EC_SIGN_EC            0x00 /* write 0x00 to let the st7 manage pm 
stuff */
++
++#if 0
++#define EC_TEST                       (EC_REG_BASE+5) /* Depending on 
firmware version this register */
++                                              /* may be the programmation 
register so don't play */
++                                              /* with it */
++#endif
++
++#define BAT_VOLT_PRESENT      500000  /* Min voltage to consider battery 
present uV */
++#define BAT_MIN                       7000000 /* Min battery voltage in uV */
++#define BAT_MIN_MV            7000    /* Min battery voltage in mV */
++#define BAT_TRICKLE_EN                8000000 /* Charging at 1.4A before  
8.0V and then charging at 0.25A */
++#define BAT_MAX                       7950000 /* Max battery voltage ~8V in V 
*/
++#define BAT_MAX_MV            7950    /* Max battery voltage ~8V in V */
++#define BAT_READ_ERROR                300000  /* battery read error of 0.3V */
++#define BAT_READ_ERROR_MV     300     /* battery read error of 0.3V */
++
++#define SM502_WLAN_ON         (224+16)/* SM502 GPIO16 may be used on gdium v2 
(v3?) as wlan_on */
++                                      /* when R422 is connected */
++
++static unsigned char verbose;
++static unsigned char gpio16;
++static unsigned char ec;
++module_param(verbose, byte, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(verbose, "Add some debugging messages");
++module_param(gpio16, byte, S_IRUGO);
++MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502");
++module_param(ec, byte, S_IRUGO);
++MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)");
++
++struct gdium_laptop_data {
++      struct i2c_client               *client;
++      struct input_polled_dev         *input_polldev;
++      struct dentry                   *debugfs;
++      struct mutex                    mutex;
++      struct platform_device          *bat_pdev;
++      struct power_supply             gdium_ac;
++      struct power_supply             gdium_battery;
++      struct workqueue_struct         *workqueue;
++      struct delayed_work             work;
++      char                            charge_cmd;
++      /* important registers value */
++      char                            status;
++      char                            ctrl;
++      /* mV */
++      int                             battery_level;
++      char                            version;
++};
++
++/**********************************************************************/
++/* Low level I2C functions                                            */
++/* All are supposed to be called with mutex held                      */
++/**********************************************************************/
++/*
++ * Return battery voltage in mV
++ * >= 0 battery voltage
++ * < 0 error
++ */
++static s32 ec_read_battery(struct i2c_client *client)
++{
++      unsigned char bat_low, bat_high;
++      s32 data;
++      unsigned int ret;
++
++      /*
++       * a = battery high
++       * b = battery low
++       * bat = a << 2 | b & 0x03;
++       * battery voltage = (bat / 1024) * 5 * 2
++       */
++      data = i2c_smbus_read_byte_data(client, EC_BAT_LOW);
++      if (data < 0) {
++              dev_err(&client->dev, "ec_read_bat: read bat_low failed\n");
++              return data;
++      }
++      bat_low = data & 0xff;
++      if (verbose)
++              dev_info(&client->dev, "bat_low %x\n", bat_low);
++
++      data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH);
++      if (data < 0) {
++              dev_err(&client->dev, "ec_read_bat: read bat_high failed\n");
++              return data;
++      }
++      bat_high = data & 0xff;
++      if (verbose)
++              dev_info(&client->dev, "bat_high %x\n", bat_high);
++
++      ret = (bat_high << 2) | (bat_low & 3);
++      /*
++       * mV
++       */
++      ret = (ret * 5 * 2) * 1000 / 1024;
++
++      return ret;
++}
++
++static s32 ec_read_version(struct i2c_client *client)
++{
++#if CONFIG_GDIUM_VERSION > 2
++      return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION);
++#else
++      return 0;
++#endif
++}
++
++static s32 ec_read_status(struct i2c_client *client)
++{
++      return i2c_smbus_read_byte_data(client, EC_STATUS);
++}
++
++static s32 ec_read_ctrl(struct i2c_client *client)
++{
++      return i2c_smbus_read_byte_data(client, EC_CTRL);
++}
++
++static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue)
++{
++      return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue);
++}
++
++static s32 ec_read_sign(struct i2c_client *client)
++{
++      return i2c_smbus_read_byte_data(client, EC_SIGN);
++}
++
++static s32 ec_write_sign(struct i2c_client *client, unsigned char sign)
++{
++      unsigned char value;
++      s32 ret;
++
++      ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign);
++      if (ret < 0) {
++              dev_err(&client->dev, "ec_set_control: write failed\n");
++              return ret;
++      }
++
++      value = ec_read_sign(client);
++      if (value != sign) {
++              dev_err(&client->dev, "Failed to set control to %s\n",
++                              sign == EC_SIGN_OS ? "OS" : "EC");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++#if 0
++static int ec_power_off(struct i2c_client *client)
++{
++      char value;
++      int ret;
++
++      value = ec_read_ctrl(client);
++      if (value < 0) {
++              dev_err(&client->dev, "ec_power_off: read failed\n");
++              return value;
++      }
++      value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC);
++      ret = ec_write_ctrl(client, value);
++      if (ret < 0) {
++              dev_err(&client->dev, "ec_power_off: write failed\n");
++              return ret;
++      }
++
++      return 0;
++}
++#endif
++
++static s32 ec_wlan_status(struct i2c_client *client)
++{
++      s32 value;
++
++      value = ec_read_ctrl(client);
++      if (value < 0)
++              return value;
++
++      return (value & EC_CTRL_WLAN_EN) ? 1 : 0;
++}
++
++static s32 ec_wlan_en(struct i2c_client *client, int on)
++{
++      s32 value;
++
++      value = ec_read_ctrl(client);
++      if (value < 0)
++              return value;
++
++      value &= ~EC_CTRL_WLAN_EN;
++      if (on)
++              value |= EC_CTRL_WLAN_EN;
++
++      return ec_write_ctrl(client, value&0xff);
++}
++
++#if 0
++static s32 ec_led_status(struct i2c_client *client)
++{
++      s32 value;
++
++      value = ec_read_ctrl(client);
++      if (value < 0)
++              return value;
++
++      return (value & EC_CTRL_CHARGE_LED) ? 1 : 0;
++}
++#endif
++
++/* Changing the charging led status has never worked */
++static s32 ec_led_en(struct i2c_client *client, int on)
++{
++#if 0
++      s32 value;
++
++      value = ec_read_ctrl(client);
++      if (value < 0)
++              return value;
++
++      value &= ~EC_CTRL_CHARGE_LED;
++      if (on)
++              value |= EC_CTRL_CHARGE_LED;
++      return ec_write_ctrl(client, value&0xff);
++#else
++      return 0;
++#endif
++}
++
++static s32 ec_charge_en(struct i2c_client *client, int on, int trickle)
++{
++      s32 value;
++      s32 set = 0;
++
++      value = ec_read_ctrl(client);
++      if (value < 0)
++              return value;
++
++      if (on)
++              set |= EC_CTRL_CHARGE_EN;
++      if (trickle)
++              set |= EC_CTRL_TRICKLE;
++
++      /* Be clever : don't change values if you don't need to */
++      if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set)
++              return 0;
++
++      value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE);
++      value |= set;
++      ec_led_en(client, on);
++      return ec_write_ctrl(client, (unsigned char)(value&0xff));
++
++}
++
++/**********************************************************************/
++/* Input functions                                                    */
++/**********************************************************************/
++struct gdium_keys {
++      int last_state;
++      int key_code;
++      int mask;
++      int type;
++};
++
++static struct gdium_keys gkeys[] = {
++      {
++              .key_code       = KEY_WLAN,
++              .mask           = EC_STATUS_WLAN,
++              .type           = EV_KEY,
++      },
++      {
++              .key_code       = KEY_POWER,
++              .mask           = EC_STATUS_PWRBUT,
++              .type           = EV_KEY, /*EV_PWR,*/
++      },
++      {
++              .key_code       = SW_LID,
++              .mask           = EC_STATUS_LID,
++              .type           = EV_SW,
++      },
++};
++
++static void gdium_laptop_keys_poll(struct input_polled_dev *dev)
++{
++      int state, i;
++      struct gdium_laptop_data *data = dev->private;
++      struct i2c_client *client = data->client;
++      struct input_dev *input = dev->input;
++      s32 status;
++
++      mutex_lock(&data->mutex);
++      status = ec_read_status(client);
++      mutex_unlock(&data->mutex);
++
++      if (status < 0) {
++              /*
++               * Don't know exactly  which version of the firmware
++               * has this bug but when the power button is pressed
++               * there are i2c read errors :(
++               */
++              if ((data->version >= 0x13) && !gkeys[1].last_state) {
++                      input_event(input, EV_KEY, KEY_POWER, 1);
++                      input_sync(input);
++                      gkeys[1].last_state = 1;
++              }
++              return;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(gkeys); i++) {
++              state = status & gkeys[i].mask;
++              if (state != gkeys[i].last_state) {
++                      gkeys[i].last_state = state;
++                      /* for power key, we want power & key press/release 
event */
++                      if (gkeys[i].type == EV_PWR) {
++                              input_event(input, EV_KEY, gkeys[i].key_code, 
!!state);
++                              input_sync(input);
++                      }
++                      /* Disable wifi on key press but not key release */
++                      /*
++                       * On firmware >= 0x13 the EC_STATUS_WLAN has it's
++                       * original meaning of Wifi status and no more the
++                       * wifi button status so we have to ignore the event
++                       * on theses versions
++                       */
++                      if (state && (gkeys[i].key_code == KEY_WLAN) && 
(data->version < 0x13)) {
++                              mutex_lock(&data->mutex);
++                              ec_wlan_en(client, !ec_wlan_status(client));
++                              if (gpio16)
++                                      gpio_set_value(SM502_WLAN_ON, 
!ec_wlan_status(client));
++                              mutex_unlock(&data->mutex);
++                      }
++
++                      input_event(input, gkeys[i].type, gkeys[i].key_code, 
!!state);
++                      input_sync(input);
++              }
++      }
++}
++
++static int gdium_laptop_input_init(struct gdium_laptop_data *data)
++{
++      struct i2c_client *client = data->client;
++      struct input_dev *input;
++      int ret, i;
++
++      data->input_polldev = input_allocate_polled_device();
++      if (!data->input_polldev) {
++              ret = -ENOMEM;
++              goto err;
++      }
++
++      input = data->input_polldev->input;
++      input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
++      data->input_polldev->poll = gdium_laptop_keys_poll;
++      data->input_polldev->poll_interval = SCAN_INTERVAL;
++      data->input_polldev->private = data;
++      input->name = "gdium-keys";
++      input->dev.parent = &client->dev;
++
++      input->id.bustype = BUS_HOST;
++      input->id.vendor = 0x0001;
++      input->id.product = 0x0001;
++      input->id.version = 0x0100;
++
++      for (i = 0; i < ARRAY_SIZE(gkeys); i++)
++              input_set_capability(input, gkeys[i].type, gkeys[i].key_code);
++
++      ret = input_register_polled_device(data->input_polldev);
++      if (ret) {
++              dev_err(&client->dev, "Unable to register button device\n");
++              goto err_poll_dev;
++      }
++
++      return 0;
++
++err_poll_dev:
++      input_free_polled_device(data->input_polldev);
++err:
++      return ret;
++}
++
++static void gdium_laptop_input_exit(struct gdium_laptop_data *data)
++{
++      input_unregister_polled_device(data->input_polldev);
++      input_free_polled_device(data->input_polldev);
++}
++
++/**********************************************************************/
++/* Battery management                                                 */
++/**********************************************************************/
++static int gdium_ac_get_props(struct power_supply *psy,
++              enum power_supply_property psp,
++              union power_supply_propval *val)
++{
++      char status;
++      struct gdium_laptop_data *data = container_of(psy, struct 
gdium_laptop_data, gdium_ac);
++      int ret = 0;
++
++      if (!data) {
++              pr_err("gdium-ac: gdium_laptop_data not found\n");
++              return -EINVAL;
++      }
++
++      status = data->status;
++      switch (psp) {
++      case POWER_SUPPLY_PROP_ONLINE:
++              val->intval = !!(status & EC_STATUS_ADAPT);
++              break;
++      default:
++              ret = -EINVAL;
++              break;
++      }
++
++      return ret;
++}
++
++#undef RET
++#define RET (val->intval)
++
++static int gdium_battery_get_props(struct power_supply *psy,
++              enum power_supply_property psp,
++              union power_supply_propval *val)
++{
++      char status, ctrl;
++      struct gdium_laptop_data *data = container_of(psy, struct 
gdium_laptop_data, gdium_battery);
++      int percentage_capacity = 0, charge_now = 0, time_to_empty = 0;
++      int ret = 0, tmp;
++
++      if (!data) {
++              pr_err("gdium-battery: gdium_laptop_data not found\n");
++              return -EINVAL;
++      }
++
++      status = data->status;
++      ctrl   = data->ctrl;
++      switch (psp) {
++      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
++              /* uAh */
++              RET = 5000000;
++              break;
++      case POWER_SUPPLY_PROP_CURRENT_NOW:
++      case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
++              /* This formula is gotten by gnuplot with the statistic data */
++              time_to_empty = (data->battery_level - BAT_MIN_MV + 
BAT_READ_ERROR_MV) * 113 - 29870;
++              if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) {
++                      /* seconds */
++                      RET = time_to_empty / 10;
++                      break;
++              }
++              /* fall through */
++      case POWER_SUPPLY_PROP_CHARGE_NOW:
++      case POWER_SUPPLY_PROP_CAPACITY: {
++              tmp = data->battery_level * 1000;
++              /* > BAT_MIN to avoid negative values */
++              percentage_capacity = 0;
++              if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN))
++                      percentage_capacity = 
(tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN);
++
++              if (percentage_capacity > 100)
++                      percentage_capacity = 100;
++
++              if (psp == POWER_SUPPLY_PROP_CAPACITY) {
++                      RET = percentage_capacity;
++                      break;
++              }
++              charge_now = 50000 * percentage_capacity;
++              if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) {
++                      /* uAh */
++                      RET = charge_now;
++                      break;
++              }
++      }       /* fall through */
++      case POWER_SUPPLY_PROP_STATUS: {
++              if (status & EC_STATUS_ADAPT)
++                      if (ctrl & EC_CTRL_CHARGE_EN)
++                              RET = POWER_SUPPLY_STATUS_CHARGING;
++                      else
++                              RET = POWER_SUPPLY_STATUS_NOT_CHARGING;
++              else
++                      RET = POWER_SUPPLY_STATUS_DISCHARGING;
++
++              if (psp == POWER_SUPPLY_PROP_STATUS)
++                      break;
++              /* mAh -> µA */
++              switch (RET) {
++              case POWER_SUPPLY_STATUS_CHARGING:
++                      RET = -(data->charge_cmd == 2) ? 1400000 : 250000;
++                      break;
++              case POWER_SUPPLY_STATUS_DISCHARGING:
++                      RET = charge_now / time_to_empty * 36000;
++                      break;
++              case POWER_SUPPLY_STATUS_NOT_CHARGING:
++              default:
++                      RET = 0;
++                      break;
++              }
++      } break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++              RET = BAT_MAX+BAT_READ_ERROR;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
++              RET = BAT_MIN-BAT_READ_ERROR;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++              /* mV -> uV */
++              RET = data->battery_level * 1000;
++              break;
++      case POWER_SUPPLY_PROP_PRESENT:
++#if CONFIG_GDIUM_VERSION > 2
++              RET = !!(status & EC_STATUS_BATID);
++#else
++              RET = !!(data->battery_level > BAT_VOLT_PRESENT);
++#endif
++              break;
++      case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
++              tmp = data->battery_level * 1000;
++              RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
++              if (status & EC_STATUS_BATID) {
++                      if (tmp >= BAT_MAX) {
++                              RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
++                              if (tmp >= BAT_MAX+BAT_READ_ERROR)
++                                      RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
++                      } else if (tmp <= BAT_MIN+BAT_READ_ERROR) {
++                              RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
++                              if (tmp <= BAT_MIN)
++                                      RET = 
POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
++                      } else
++                              RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
++              }
++              break;
++      case POWER_SUPPLY_PROP_CHARGE_TYPE:
++              if (ctrl & EC_CTRL_TRICKLE)
++                      RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
++              else if (ctrl & EC_CTRL_CHARGE_EN)
++                      RET = POWER_SUPPLY_CHARGE_TYPE_FAST;
++              else
++                      RET = POWER_SUPPLY_CHARGE_TYPE_NONE;
++              break;
++      case POWER_SUPPLY_PROP_CURRENT_MAX:
++              /* 1.4A ? */
++              RET = 1400000;
++              break;
++      default:
++              break;
++      }
++
++      return ret;
++}
++#undef RET
++
++static enum power_supply_property gdium_ac_props[] = {
++      POWER_SUPPLY_PROP_ONLINE,
++};
++
++static enum power_supply_property gdium_battery_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_PRESENT,
++      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
++      POWER_SUPPLY_PROP_CHARGE_NOW,
++      POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_CURRENT_MAX,
++      POWER_SUPPLY_PROP_CURRENT_NOW,
++      POWER_SUPPLY_PROP_CAPACITY,
++      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
++      POWER_SUPPLY_PROP_CHARGE_TYPE,
++};
++
++static void gdium_laptop_battery_work(struct work_struct *work)
++{
++      struct gdium_laptop_data *data = container_of(work, struct 
gdium_laptop_data, work.work);
++      struct i2c_client *client;
++      int ret;
++      char old_status, old_charge_cmd;
++      char present;
++      s32 status;
++
++      mutex_lock(&data->mutex);
++      client  = data->client;
++      status  = ec_read_status(client);
++      ret     = ec_read_battery(client);
++
++      if ((status < 0) || (ret < 0))
++              goto i2c_read_error;
++
++      old_status = data->status;
++      old_charge_cmd = data->charge_cmd;
++      data->status = status;
++
++      /*
++       * Charge only if :
++       * - battery present
++       * - ac adapter plugged in
++       * - battery not fully charged
++       */
++#if CONFIG_GDIUM_VERSION > 2
++      present = !!(data->status & EC_STATUS_BATID);
++#else
++      present = !!(ret > BAT_VOLT_PRESENT);
++#endif
++      data->battery_level = 0;
++      if (present) {
++              data->battery_level = (unsigned int)ret;
++              if (data->status & EC_STATUS_ADAPT)
++                      data->battery_level -= BAT_READ_ERROR_MV;
++      }
++
++      data->charge_cmd = 0;
++      if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level 
<= BAT_MAX_MV))
++              data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3;
++
++      ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1);
++
++      /*
++       * data->ctrl must be set _after_ calling ec_charge_en as this will 
change the
++       * control register content
++       */
++      data->ctrl = ec_read_ctrl(client);
++
++      if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) 
{
++              power_supply_changed(&data->gdium_ac);
++              /* Send charging/discharging state change */
++              power_supply_changed(&data->gdium_battery);
++      } else if ((data->status & EC_STATUS_ADAPT) &&
++                      ((old_charge_cmd&2) != (data->charge_cmd&2)))
++              power_supply_changed(&data->gdium_battery);
++
++i2c_read_error:
++      mutex_unlock(&data->mutex);
++      queue_delayed_work(data->workqueue, &data->work, 
msecs_to_jiffies(BAT_SCAN_INTERVAL));
++}
++
++static int gdium_laptop_battery_init(struct gdium_laptop_data *data)
++{
++      int ret;
++
++      data->bat_pdev = platform_device_register_simple("gdium-battery", 0, 
NULL, 0);
++      if (IS_ERR(data->bat_pdev))
++              return PTR_ERR(data->bat_pdev);
++
++      data->gdium_battery.name                = data->bat_pdev->name;
++      data->gdium_battery.properties          = gdium_battery_props;
++      data->gdium_battery.num_properties      = 
ARRAY_SIZE(gdium_battery_props);
++      data->gdium_battery.get_property        = gdium_battery_get_props;
++      data->gdium_battery.use_for_apm         = 1;
++
++      ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery);
++      if (ret)
++              goto err_platform;
++
++      data->gdium_ac.name                     = "gdium-ac";
++      data->gdium_ac.type                     = POWER_SUPPLY_TYPE_MAINS;
++      data->gdium_ac.properties               = gdium_ac_props;
++      data->gdium_ac.num_properties           = ARRAY_SIZE(gdium_ac_props);
++      data->gdium_ac.get_property             = gdium_ac_get_props;
++/*    data->gdium_ac.use_for_apm_ac           = 1,    */
++
++      ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac);
++      if (ret)
++              goto err_battery;
++
++      if (!ec) {
++              INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work);
++              data->workqueue = 
create_singlethread_workqueue("gdium-battery-work");
++              if (!data->workqueue) {
++                      ret = -ESRCH;
++                      goto err_work;
++              }
++              queue_delayed_work(data->workqueue, &data->work, 
msecs_to_jiffies(BAT_SCAN_INTERVAL));
++      }
++
++      return 0;
++
++err_work:
++err_battery:
++      power_supply_unregister(&data->gdium_battery);
++err_platform:
++      platform_device_unregister(data->bat_pdev);
++
++      return ret;
++}
++static void gdium_laptop_battery_exit(struct gdium_laptop_data *data)
++{
++      if (!ec) {
++              cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
++              destroy_workqueue(data->workqueue);
++      }
++      power_supply_unregister(&data->gdium_battery);
++      power_supply_unregister(&data->gdium_ac);
++      platform_device_unregister(data->bat_pdev);
++}
++
++/* Debug fs */
++static int gdium_laptop_regs_show(struct seq_file *s, void *p)
++{
++      struct gdium_laptop_data *data = s->private;
++      struct i2c_client *client = data->client;
++
++      mutex_lock(&data->mutex);
++      seq_printf(s, "Version    : 0x%02x\n", (unsigned 
char)ec_read_version(client));
++      seq_printf(s, "Status     : 0x%02x\n", (unsigned 
char)ec_read_status(client));
++      seq_printf(s, "Ctrl       : 0x%02x\n", (unsigned 
char)ec_read_ctrl(client));
++      seq_printf(s, "Sign       : 0x%02x\n", (unsigned 
char)ec_read_sign(client));
++      seq_printf(s, "Bat Lo     : 0x%02x\n", (unsigned 
char)i2c_smbus_read_byte_data(client, EC_BAT_LOW));
++      seq_printf(s, "Bat Hi     : 0x%02x\n", (unsigned 
char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH));
++      seq_printf(s, "Battery    : %d uV\n",  (unsigned 
int)ec_read_battery(client) * 1000);
++      seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", 
data->charge_cmd & 1 ? "T" : " ");
++
++      mutex_unlock(&data->mutex);
++      return 0;
++}
++
++static int gdium_laptop_regs_open(struct inode *inode,
++                                       struct file *file)
++{
++      return single_open(file, gdium_laptop_regs_show, inode->i_private);
++}
++
++static const struct file_operations gdium_laptop_regs_fops = {
++      .open           = gdium_laptop_regs_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .owner          = THIS_MODULE,
++};
++
++
++static int gdium_laptop_probe(struct i2c_client *client, const struct 
i2c_device_id *id)
++{
++      struct gdium_laptop_data *data;
++      int ret;
++
++      if (!i2c_check_functionality(client->adapter, 
I2C_FUNC_SMBUS_BYTE_DATA)) {
++              dev_err(&client->dev,
++                              "%s: no smbus_byte support !\n", __func__);
++              return -ENODEV;
++      }
++
++      data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL);
++      if (!data)
++              return -ENOMEM;
++
++      i2c_set_clientdata(client, data);
++      data->client = client;
++      mutex_init(&data->mutex);
++
++      ret = ec_read_version(client);
++      if (ret < 0)
++              goto err_alloc;
++
++      data->version = (unsigned char)ret;
++
++      ret = gdium_laptop_input_init(data);
++      if (ret)
++              goto err_alloc;
++
++      ret = gdium_laptop_battery_init(data);
++      if (ret)
++              goto err_input;
++
++
++      if (!ec) {
++              ret = ec_write_sign(client, EC_SIGN_OS);
++              if (ret)
++                      goto err_sign;
++      }
++
++      if (gpio16) {
++              ret = gpio_request(SM502_WLAN_ON, "wlan-on");
++              if (ret < 0)
++                      goto err_sign;
++              gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client));
++              gpio_direction_output(SM502_WLAN_ON, 1);
++      }
++
++      dev_info(&client->dev, "Found firmware 0x%02x\n", data->version);
++      data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO,
++                              NULL, data, &gdium_laptop_regs_fops);
++
++      return 0;
++
++err_sign:
++      gdium_laptop_battery_exit(data);
++err_input:
++      gdium_laptop_input_exit(data);
++err_alloc:
++      kfree(data);
++      return ret;
++}
++
++static int gdium_laptop_remove(struct i2c_client *client)
++{
++      struct gdium_laptop_data *data = i2c_get_clientdata(client);
++
++      if (gpio16)
++              gpio_free(SM502_WLAN_ON);
++      ec_write_sign(client, EC_SIGN_EC);
++      if (data->debugfs)
++              debugfs_remove(data->debugfs);
++
++      gdium_laptop_battery_exit(data);
++      gdium_laptop_input_exit(data);
++
++      kfree(data);
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg)
++{
++      struct gdium_laptop_data *data = i2c_get_clientdata(client);
++
++      if (!ec)
++              cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
++      return 0;
++}
++
++static int gdium_laptop_resume(struct i2c_client *client)
++{
++      struct gdium_laptop_data *data = i2c_get_clientdata(client);
++
++      if (!ec)
++              queue_delayed_work(data->workqueue, &data->work, 
msecs_to_jiffies(BAT_SCAN_INTERVAL));
++      return 0;
++}
++#else
++#define gdium_laptop_suspend NULL
++#define gdium_laptop_resume NULL
++#endif
++static const struct i2c_device_id gdium_id[] = {
++      { "gdium-laptop" },
++      {},
++};
++MODULE_DEVICE_TABLE(i2c, gdium_id);
++
++static struct i2c_driver gdium_laptop_driver = {
++      .driver = {
++              .name = "gdium-laptop",
++              .owner = THIS_MODULE,
++      },
++      .probe = gdium_laptop_probe,
++      .remove = gdium_laptop_remove,
++      .shutdown = gdium_laptop_remove,
++      .suspend = gdium_laptop_suspend,
++      .resume = gdium_laptop_resume,
++      .id_table = gdium_id,
++};
++
++static int __init gdium_laptop_init(void)
++{
++      return i2c_add_driver(&gdium_laptop_driver);
++}
++
++static void __exit gdium_laptop_exit(void)
++{
++      i2c_del_driver(&gdium_laptop_driver);
++}
++
++module_init(gdium_laptop_init);
++module_exit(gdium_laptop_exit);
++
++MODULE_AUTHOR("Arnaud Patard <address@hidden>");
++MODULE_DESCRIPTION("Gdium laptop extras");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 0fe4ad8..45e46d4 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -744,6 +744,7 @@ comment "Platform RTC drivers"
+ config RTC_DRV_CMOS
+       tristate "PC-style 'CMOS'"
+       depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
++      depends on !DEXXON_GDIUM
+       default y if X86
+       help
+         Say "yes" here to get direct support for the real time clock
+diff --git a/include/linux/sm501.h b/include/linux/sm501.h
+index 02fde50..a8677f0 100644
+--- a/include/linux/sm501.h
++++ b/include/linux/sm501.h
+@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev,
+ extern unsigned long sm501_find_clock(struct device *dev,
+                                     int clksrc, unsigned long req_freq);
+ 
++extern void sm501_configure_gpio(struct device *dev,
++                              unsigned int gpio, unsigned char mode);
++
+ /* sm501_misc_control
+  *
+  * Modify the SM501's MISC_CONTROL register
+@@ -122,6 +125,7 @@ struct sm501_reg_init {
+ #define SM501_USE_AC97                (1<<7)
+ #define SM501_USE_I2S         (1<<8)
+ #define SM501_USE_GPIO                (1<<9)
++#define SM501_USE_PWM         (1<<10)
+ 
+ #define SM501_USE_ALL         (0xffffffff)
+ 
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-loongson2-cpufreq-fix.patch 
b/gnu/packages/patches/linux-libre-loongson2-cpufreq-fix.patch
new file mode 100644
index 0000000..e94b31d
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-loongson2-cpufreq-fix.patch
@@ -0,0 +1,59 @@
+From acda4b2b30a1dbb61e5600bc787a98b705564d7a Mon Sep 17 00:00:00 2001
+From: Alexandre Oliva <address@hidden>
+Date: Fri, 22 Aug 2014 19:11:21 -0300
+Subject: [PATCH 4/9] loongson2 cpufreq: unregister on init failure
+
+If the loongson2_cpufreq module fails to init, e.g. because
+any of the cpufreq_register functions fail, it must unregister
+so that the module is unloaded successfully and no misinitialized
+device remains in the udev device list.  Fixed.
+
+Signed-off-by: Alexandre Oliva <address@hidden>
+---
+ drivers/cpufreq/loongson2_cpufreq.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/cpufreq/loongson2_cpufreq.c 
b/drivers/cpufreq/loongson2_cpufreq.c
+index fc897ba..ac60f6b 100644
+--- a/drivers/cpufreq/loongson2_cpufreq.c
++++ b/drivers/cpufreq/loongson2_cpufreq.c
+@@ -161,20 +161,32 @@ static int __init cpufreq_init(void)
+       /* Register platform stuff */
+       ret = platform_driver_register(&platform_driver);
+       if (ret)
+-              return ret;
++              goto err_return;
+ 
+       pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
+ 
+-      cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
+-                                CPUFREQ_TRANSITION_NOTIFIER);
++      ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
++                                      CPUFREQ_TRANSITION_NOTIFIER);
++      if (ret)
++              goto err_platform_driver_unregister;
+ 
+       ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
++      if (ret)
++              goto err_cpufreq_unregister_notifier;
+ 
+-      if (!ret && !nowait) {
++      if (!nowait) {
+               saved_cpu_wait = cpu_wait;
+               cpu_wait = loongson2_cpu_wait;
+       }
+ 
++      return 0;
++
++ err_cpufreq_unregister_notifier:
++      cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
++                                  CPUFREQ_TRANSITION_NOTIFIER);
++ err_platform_driver_unregister:
++      platform_driver_unregister(&platform_driver);
++ err_return:
+       return ret;
+ }
+ 
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-loongson2-math-emu.patch 
b/gnu/packages/patches/linux-libre-loongson2-math-emu.patch
new file mode 100644
index 0000000..edf35c1
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-loongson2-math-emu.patch
@@ -0,0 +1,386 @@
+From fd6faa493baa986e43d011f7bc84c3fe3b811b2b Mon Sep 17 00:00:00 2001
+From: Mark H Weaver <address@hidden>
+Date: Thu, 6 Aug 2015 01:28:10 -0400
+Subject: [PATCH 3/9] Support Loongson2f floating-point instructions in
+ mips/math-emu.
+
+* (arch/mips/include/asm/inst.h): Add Loongson2f function field values
+  for madd/msub/nmadd/nmsub that use the spec2 opcode, and the
+  Loongson2f/MIPS-5 format field value for paired-single
+  floating-point operations.
+
+* (arch/mips/math-emu/cp1emu.c): Add support for the Loongson2f
+  instructions for madd/msub/nmadd/nmsub, which use the spec2 opcode.
+  Also add support for the Loongson2f instructions that use the
+  paired-single floating-point format.
+---
+ arch/mips/include/uapi/asm/inst.h |   4 +-
+ arch/mips/math-emu/cp1emu.c       | 281 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 283 insertions(+), 2 deletions(-)
+
+diff --git a/arch/mips/include/uapi/asm/inst.h 
b/arch/mips/include/uapi/asm/inst.h
+index 9b6ccbd..99e6430 100644
+--- a/arch/mips/include/uapi/asm/inst.h
++++ b/arch/mips/include/uapi/asm/inst.h
+@@ -65,6 +65,8 @@ enum spec_op {
+ enum spec2_op {
+       madd_op, maddu_op, mul_op, spec2_3_unused_op,
+       msub_op, msubu_op, /* more unused ops */
++      loongson_madd_op = 0x18, loongson_msub_op,
++      loongson_nmadd_op, loongson_nmsub_op,
+       clz_op = 0x20, clo_op,
+       dclz_op = 0x24, dclo_op,
+       sdbpp_op = 0x3f
+@@ -151,7 +153,7 @@ enum cop0_com_func {
+  */
+ enum cop1_fmt {
+       s_fmt, d_fmt, e_fmt, q_fmt,
+-      w_fmt, l_fmt
++      w_fmt, l_fmt, ps_fmt
+ };
+ 
+ /*
+diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
+index ed82f0e..86ec4f2 100644
+--- a/arch/mips/math-emu/cp1emu.c
++++ b/arch/mips/math-emu/cp1emu.c
+@@ -7,6 +7,9 @@
+  * Kevin D. Kissell, address@hidden and Carsten Langgaard, address@hidden
+  * Copyright (C) 2000  MIPS Technologies, Inc.
+  *
++ * Loongson instruction support
++ * Copyright (C) 2011  Mark H Weaver <address@hidden>
++ *
+  *  This program is free software; you can distribute it and/or modify it
+  *  under the terms of the GNU General Public License (Version 2) as
+  *  published by the Free Software Foundation.
+@@ -61,6 +64,11 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct 
*,
+ static int fpux_emu(struct pt_regs *,
+       struct mips_fpu_struct *, mips_instruction, void *__user *);
+ 
++#ifdef CONFIG_MACH_LOONGSON64
++static int loongson_spec2_emu(struct pt_regs *,
++      struct mips_fpu_struct *, mips_instruction, void *__user *);
++#endif
++
+ /* Control registers */
+ 
+ #define FPCREG_RID    0       /* $0  = revision id */
+@@ -843,6 +851,14 @@ do {                                                      
                \
+ #define DPFROMREG(dp, x)      DIFROMREG((dp).bits, x)
+ #define DPTOREG(dp, x)        DITOREG((dp).bits, x)
+ 
++/* Support for Loongson paired single floating-point format */
++#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x);          \
++                      (si1) = (u32)di; (si2) = (u32)(di >> 32); })
++#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x)
++
++#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x)
++#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x)
++
+ /*
+  * Emulate a CFC1 instruction.
+  */
+@@ -1349,6 +1365,16 @@ emul:
+                       xcp->regs[MIPSInst_RD(ir)] =
+                               xcp->regs[MIPSInst_RS(ir)];
+               break;
++
++#ifdef CONFIG_MACH_LOONGSON64
++      case spec2_op:{
++              int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
++              if (sig)
++                      return sig;
++              break;
++      }
++#endif
++
+       default:
+ sigill:
+               return SIGILL;
+@@ -1426,6 +1452,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
+ DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
+ DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
+ 
++#ifdef CONFIG_MACH_LOONGSON64
++static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct 
*ctx,
++      mips_instruction ir, void *__user *fault_addr)
++{
++      int rfmt;               /* resulting format */
++      unsigned rcsr = 0;      /* resulting csr */
++      union {
++              union ieee754dp d;
++              struct {
++                      union ieee754sp s;
++                      union ieee754sp s2;
++              };
++      } rv;                   /* resulting value */
++
++      /* XXX maybe add a counter for loongson spec2 fp instructions? */
++      /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
++
++      switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
++      case s_fmt:{
++              union ieee754sp(*handler) (union ieee754sp, union ieee754sp, 
union ieee754sp);
++              union ieee754sp fd, fs, ft;
++
++              switch (MIPSInst_FUNC(ir)) {
++              case loongson_madd_op:
++                      handler = fpemu_sp_madd;
++                      goto scoptop;
++              case loongson_msub_op:
++                      handler = fpemu_sp_msub;
++                      goto scoptop;
++              case loongson_nmadd_op:
++                      handler = fpemu_sp_nmadd;
++                      goto scoptop;
++              case loongson_nmsub_op:
++                      handler = fpemu_sp_nmsub;
++                      goto scoptop;
++
++                    scoptop:
++                      SPFROMREG(fd, MIPSInst_FD(ir));
++                      SPFROMREG(fs, MIPSInst_FS(ir));
++                      SPFROMREG(ft, MIPSInst_FT(ir));
++                      rv.s = (*handler) (fd, fs, ft);
++
++                    copcsr:
++                      if (ieee754_cxtest(IEEE754_INEXACT))
++                              rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
++                      if (ieee754_cxtest(IEEE754_UNDERFLOW))
++                              rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
++                      if (ieee754_cxtest(IEEE754_OVERFLOW))
++                              rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
++                      if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
++                              rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
++
++                      break;
++
++              default:
++                      return SIGILL;
++              }
++              break;
++      }
++
++      case d_fmt:{
++              union ieee754dp(*handler) (union ieee754dp, union ieee754dp, 
union ieee754dp);
++              union ieee754dp fd, fs, ft;
++
++              switch (MIPSInst_FUNC(ir)) {
++              case loongson_madd_op:
++                      handler = fpemu_dp_madd;
++                      goto dcoptop;
++              case loongson_msub_op:
++                      handler = fpemu_dp_msub;
++                      goto dcoptop;
++              case loongson_nmadd_op:
++                      handler = fpemu_dp_nmadd;
++                      goto dcoptop;
++              case loongson_nmsub_op:
++                      handler = fpemu_dp_nmsub;
++                      goto dcoptop;
++
++                    dcoptop:
++                      DPFROMREG(fd, MIPSInst_FD(ir));
++                      DPFROMREG(fs, MIPSInst_FS(ir));
++                      DPFROMREG(ft, MIPSInst_FT(ir));
++                      rv.d = (*handler) (fd, fs, ft);
++                      goto copcsr;
++
++              default:
++                      return SIGILL;
++              }
++              break;
++      }
++
++      case ps_fmt:{
++              union ieee754sp(*handler) (union ieee754sp, union ieee754sp, 
union ieee754sp);
++              struct _ieee754_csr ieee754_csr_save;
++              union ieee754sp fd1, fs1, ft1;
++              union ieee754sp fd2, fs2, ft2;
++
++              switch (MIPSInst_FUNC(ir)) {
++              case loongson_madd_op:
++                      handler = fpemu_sp_madd;
++                      goto pscoptop;
++              case loongson_msub_op:
++                      handler = fpemu_sp_msub;
++                      goto pscoptop;
++              case loongson_nmadd_op:
++                      handler = fpemu_sp_nmadd;
++                      goto pscoptop;
++              case loongson_nmsub_op:
++                      handler = fpemu_sp_nmsub;
++                      goto pscoptop;
++
++                    pscoptop:
++                      PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
++                      PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
++                      PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
++                      rv.s = (*handler) (fd1, fs1, ft1);
++                      ieee754_csr_save = ieee754_csr;
++                      rv.s2 = (*handler) (fd2, fs2, ft2);
++                      ieee754_csr.cx |= ieee754_csr_save.cx;
++                      ieee754_csr.sx |= ieee754_csr_save.sx;
++                      goto copcsr;
++
++              default:
++                      return SIGILL;
++              }
++              break;
++      }
++
++      default:
++              return SIGILL;
++      }
++
++      /*
++       * Update the fpu CSR register for this operation.
++       * If an exception is required, generate a tidy SIGFPE exception,
++       * without updating the result register.
++       * Note: cause exception bits do not accumulate, they are rewritten
++       * for each op; only the flag/sticky bits accumulate.
++       */
++      ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
++      if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
++              /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
++              return SIGFPE;
++      }
++
++      /*
++       * Now we can safely write the result back to the register file.
++       */
++      switch (rfmt) {
++      case d_fmt:
++              DPTOREG(rv.d, MIPSInst_FD(ir));
++              break;
++      case s_fmt:
++              SPTOREG(rv.s, MIPSInst_FD(ir));
++              break;
++      case ps_fmt:
++              PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
++              break;
++      default:
++              return SIGILL;
++      }
++
++      return 0;
++}
++#endif
++
+ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+       mips_instruction ir, void *__user *fault_addr)
+ {
+@@ -1636,7 +1828,12 @@ static int fpu_emu(struct pt_regs *xcp, struct 
mips_fpu_struct *ctx,
+       unsigned cond;
+       union {
+               union ieee754dp d;
+-              union ieee754sp s;
++              struct {
++                      union ieee754sp s;
++#ifdef CONFIG_MACH_LOONGSON64
++                      union ieee754sp s2; /* for Loongson paired singles */
++#endif
++              };
+               int w;
+               s64 l;
+       } rv;                   /* resulting value */
+@@ -2047,6 +2244,83 @@ dcopuop:
+               break;
+       }
+ 
++#ifdef CONFIG_MACH_LOONGSON64
++      case ps_fmt:{           /* 6 */
++              /* Support for Loongson paired single fp instructions */
++              union {
++                      union ieee754sp(*b) (union ieee754sp, union ieee754sp);
++                      union ieee754sp(*u) (union ieee754sp);
++              } handler;
++
++              switch (MIPSInst_FUNC(ir)) {
++                      /* binary ops */
++              case fadd_op:
++                      handler.b = ieee754sp_add;
++                      goto pscopbop;
++              case fsub_op:
++                      handler.b = ieee754sp_sub;
++                      goto pscopbop;
++              case fmul_op:
++                      handler.b = ieee754sp_mul;
++                      goto pscopbop;
++
++                      /* unary  ops */
++              case fabs_op:
++                      handler.u = ieee754sp_abs;
++                      goto pscopuop;
++              case fneg_op:
++                      handler.u = ieee754sp_neg;
++                      goto pscopuop;
++              case fmov_op:
++                      /* an easy one */
++                      PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
++                      break;
++
++                    pscopbop: /* paired binary op handler */
++                      {
++                              struct _ieee754_csr ieee754_csr_save;
++                              union ieee754sp fs1, ft1;
++                              union ieee754sp fs2, ft2;
++
++                              PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
++                              PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
++                              rv.s  = (*handler.b) (fs1, ft1);
++                              ieee754_csr_save = ieee754_csr;
++                              rv.s2 = (*handler.b) (fs2, ft2);
++                              ieee754_csr.cx |= ieee754_csr_save.cx;
++                              ieee754_csr.sx |= ieee754_csr_save.sx;
++                              goto copcsr;
++                      }
++                    pscopuop: /* paired unary op handler */
++                      {
++                              struct _ieee754_csr ieee754_csr_save;
++                              union ieee754sp fs1;
++                              union ieee754sp fs2;
++
++                              PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
++                              rv.s  = (*handler.u) (fs1);
++                              ieee754_csr_save = ieee754_csr;
++                              rv.s2 = (*handler.u) (fs2);
++                              ieee754_csr.cx |= ieee754_csr_save.cx;
++                              ieee754_csr.sx |= ieee754_csr_save.sx;
++                              goto copcsr;
++                      }
++                      break;
++
++              default:
++                      if (MIPSInst_FUNC(ir) >= fcmp_op) {
++                              /* Loongson fp hardware handles all
++                                 cases of fp compare insns, so we
++                                 shouldn't have to */
++                              printk ("Loongson paired-single fp compare"
++                                      " unimplemented in cp1emu.c\n");
++                      }
++                      return SIGILL;
++              }
++              break;
++      }
++#endif
++
+       case l_fmt:
+ 
+               if (!cpu_has_mips_3_4_5_64_r2_r6)
+@@ -2118,6 +2392,11 @@ dcopuop:
+ 
+               DITOREG(rv.l, MIPSInst_FD(ir));
+               break;
++#ifdef CONFIG_MACH_LOONGSON64
++      case ps_fmt:
++              PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
++              break;
++#endif
+       default:
+               return SIGILL;
+       }
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-loongson2-max-physmem-bits.patch 
b/gnu/packages/patches/linux-libre-loongson2-max-physmem-bits.patch
new file mode 100644
index 0000000..7908c3d
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-loongson2-max-physmem-bits.patch
@@ -0,0 +1,36 @@
+From 8d7280c9ee3d7de6f129b9c3112faffb20841154 Mon Sep 17 00:00:00 2001
+From: Alexandre Oliva <address@hidden>
+Date: Wed, 15 Oct 2014 02:00:28 -0300
+Subject: [PATCH 5/9] Loongson2: restore working MAX_PHYSMEM_BITS definition
+
+Commit c461731836 bumped MAX_PHYSMEM_BITS up unconditionally, but
+this causes Loongson2 machines to freeze very early on boot.
+
+To restore Loongson2 to a functional state, I have restored the
+original definition, for Loongson2 only.
+
+Signed-off-by: Alexandre Oliva <address@hidden>
+---
+ arch/mips/include/asm/sparsemem.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/mips/include/asm/sparsemem.h 
b/arch/mips/include/asm/sparsemem.h
+index b1071c1..8b8e551 100644
+--- a/arch/mips/include/asm/sparsemem.h
++++ b/arch/mips/include/asm/sparsemem.h
+@@ -11,7 +11,11 @@
+ #else
+ # define SECTION_SIZE_BITS    28
+ #endif
+-#define MAX_PHYSMEM_BITS      48
++#if !defined(CONFIG_MACH_LOONGSON64) || !defined(CONFIG_CPU_LOONGSON2)        
/* Commit c461731836 broke Loongson2.  */
++# define MAX_PHYSMEM_BITS     48
++#else
++# define MAX_PHYSMEM_BITS     35
++#endif
+ 
+ #endif /* CONFIG_SPARSEMEM */
+ #endif /* _MIPS_SPARSEMEM_H */
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-mips-ftrace-fix.patch 
b/gnu/packages/patches/linux-libre-mips-ftrace-fix.patch
new file mode 100644
index 0000000..e439ae7
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-mips-ftrace-fix.patch
@@ -0,0 +1,85 @@
+From a5b566da301f670302930a0af4a8102a29d27f7f Mon Sep 17 00:00:00 2001
+From: Wu Zhangjin <address@hidden>
+Date: Wed, 20 Oct 2010 02:27:26 +0800
+Subject: [PATCH 7/9] MIPS: tracing/ftrace: Fixes mcount_regex for modules
+
+In some situations, the modules may have the same address space as the
+core kernel space, then, it should also match the regular R_MIPS_26
+string.
+
+Signed-off-by: Wu Zhangjin <address@hidden>
+---
+ scripts/recordmcount.pl | 46 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 29 insertions(+), 17 deletions(-)
+
+diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
+index 826470d..9e6dc30 100755
+--- a/scripts/recordmcount.pl
++++ b/scripts/recordmcount.pl
+@@ -309,14 +309,33 @@ if ($arch eq "x86_64") {
+     $cc .= " -m64";
+     $objcopy .= " -O elf64-sparc";
+ } elsif ($arch eq "mips") {
+-    # To enable module support, we need to enable the -mlong-calls option
+-    # of gcc for module, after using this option, we can not get the real
+-    # offset of the calling to _mcount, but the offset of the lui
+-    # instruction or the addiu one. herein, we record the address of the
+-    # first one, and then we can replace this instruction by a branch
+-    # instruction to jump over the profiling function to filter the
+-    # indicated functions, or swith back to the lui instruction to trace
+-    # them, which means dynamic tracing.
++    # <For kernel>
++    # To disable tracing, just replace "jal _mcount" with nop;
++    # to enable tracing, replace back. so, the offset 14 is
++    # needed to be recorded.
++    #
++    #     10:   03e0082d        move    at,ra
++    #   14:   0c000000        jal     0
++    #                    14: R_MIPS_26   _mcount
++    #                    14: R_MIPS_NONE *ABS*
++    #                    14: R_MIPS_NONE *ABS*
++    #  18:   00020021        nop
++    #
++    # <For module>
++    #
++    # If no long call(-mlong-calls), the same to kernel.
++    #
++    # If the module space differs from the kernel space, long
++    # call is needed, as a result, the address of _mcount is
++    # needed to be recorded in a register and then jump from
++    # module space to kernel space via "jalr <register>". To
++    # disable tracing, "jalr <register>" can be replaced by
++    # nop; to enable tracing, replace it back. Since the
++    # offset of "jalr <register>" is not easy to be matched,
++    # the offset of the 1st _mcount below is recorded and to
++    # disable tracing, "lui v1, 0x0" is substituted with "b
++    # label", which jumps over "jalr <register>"; to enable
++    # tracing, replace it back.
+     #
+     #       c:        3c030000        lui     v1,0x0
+     #                 c: R_MIPS_HI16  _mcount
+@@ -328,19 +347,12 @@ if ($arch eq "x86_64") {
+     #                 10: R_MIPS_NONE *ABS*
+     #      14:        03e0082d        move    at,ra
+     #      18:        0060f809        jalr    v1
++    #                     label:
+     #
+-    # for the kernel:
+-    #
+-    #     10:   03e0082d        move    at,ra
+-    #   14:   0c000000        jal     0 <loongson_halt>
+-    #                    14: R_MIPS_26   _mcount
+-    #                    14: R_MIPS_NONE *ABS*
+-    #                    14: R_MIPS_NONE *ABS*
+-    #  18:   00020021        nop
+     if ($is_module eq "0") {
+           $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$";
+     } else {
+-          $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
++          $mcount_regex = "^\\s*([0-9a-fA-F]+): 
R_MIPS_(HI16|26)\\s+_mcount\$";
+     }
+     $objdump .= " -Melf-trad".$endian."mips ";
+ 
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-mips-hugetlb-fix.patch 
b/gnu/packages/patches/linux-libre-mips-hugetlb-fix.patch
new file mode 100644
index 0000000..dcc7495
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-mips-hugetlb-fix.patch
@@ -0,0 +1,15 @@
+Fix Huge TLB support on some MIPS machines including Loongson 2F.
+
+Patch by Mark H Weaver <address@hidden>
+
+--- linux-4.1.6/arch/mips/include/asm/pgtable-bits.h   2015-08-16 
23:52:51.000000000 -0400
++++ linux-4.1.6/arch/mips/include/asm/pgtable-bits.h   2015-08-22 
16:42:06.589995600 -0400
+@@ -160,7 +160,7 @@
+ #define _PAGE_GLOBAL_SHIFT    (_PAGE_NO_READ_SHIFT + 1)
+ #define _PAGE_GLOBAL          (1 << _PAGE_GLOBAL_SHIFT)
+ 
+-#else /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */
++#elif !defined(CONFIG_64BIT) || !defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
+ #define _PAGE_GLOBAL_SHIFT    (_PAGE_MODIFIED_SHIFT + 1)
+ #define _PAGE_GLOBAL          (1 << _PAGE_GLOBAL_SHIFT)
+ #endif        /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
diff --git a/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt1.patch 
b/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt1.patch
new file mode 100644
index 0000000..c66e191
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt1.patch
@@ -0,0 +1,35 @@
+From 58f2873fbfd3b6734e4affedfcba569e3369f646 Mon Sep 17 00:00:00 2001
+From: Mark H Weaver <address@hidden>
+Date: Thu, 6 Aug 2015 01:22:42 -0400
+Subject: [PATCH 1/9] Don't process empty cause flags after simple fp move on
+ MIPS.
+
+---
+ arch/mips/math-emu/cp1emu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
+index 22b9b2c..139af11 100644
+--- a/arch/mips/math-emu/cp1emu.c
++++ b/arch/mips/math-emu/cp1emu.c
+@@ -1728,7 +1728,7 @@ static int fpu_emu(struct pt_regs *xcp, struct 
mips_fpu_struct *ctx,
+               case fmov_op:
+                       /* an easy one */
+                       SPFROMREG(rv.s, MIPSInst_FS(ir));
+-                      goto copcsr;
++                      break;
+ 
+                       /* binary op on handler */
+ scopbop:
+@@ -1925,7 +1925,7 @@ copcsr:
+               case fmov_op:
+                       /* an easy one */
+                       DPFROMREG(rv.d, MIPSInst_FS(ir));
+-                      goto copcsr;
++                      break;
+ 
+                       /* binary op on handler */
+ dcopbop:
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt2.patch 
b/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt2.patch
new file mode 100644
index 0000000..2f6b887
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-mips-math-emu-fix-pt2.patch
@@ -0,0 +1,66 @@
+From 5e207ff6fc01f129a3e0ef6c33b141e4315ac633 Mon Sep 17 00:00:00 2001
+From: Mark H Weaver <address@hidden>
+Date: Thu, 6 Aug 2015 01:25:50 -0400
+Subject: [PATCH 2/9] Fix handling of prefx instruction in mips/math-emu
+
+* Add prefx opcode.
+
+* Recognize the prefx instruction regardless of what bits happen to be
+  in bits 21-25, which is the format field of the floating-point ops,
+  but holds the base register of the prefx instruction.
+---
+ arch/mips/include/uapi/asm/inst.h | 3 ++-
+ arch/mips/math-emu/cp1emu.c       | 9 +++++++--
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/arch/mips/include/uapi/asm/inst.h 
b/arch/mips/include/uapi/asm/inst.h
+index fc0cf5a..9b6ccbd 100644
+--- a/arch/mips/include/uapi/asm/inst.h
++++ b/arch/mips/include/uapi/asm/inst.h
+@@ -180,7 +180,8 @@ enum cop1_sdw_func {
+ enum cop1x_func {
+       lwxc1_op     =  0x00, ldxc1_op     =  0x01,
+       swxc1_op     =  0x08, sdxc1_op     =  0x09,
+-      pfetch_op    =  0x0f, madd_s_op    =  0x20,
++      pfetch_op    =  0x0f,
++      prefx_op     =  0x17, madd_s_op    =  0x20,
+       madd_d_op    =  0x21, madd_e_op    =  0x22,
+       msub_s_op    =  0x28, msub_d_op    =  0x29,
+       msub_e_op    =  0x2a, nmadd_s_op   =  0x30,
+diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
+index 139af11..ed82f0e 100644
+--- a/arch/mips/math-emu/cp1emu.c
++++ b/arch/mips/math-emu/cp1emu.c
+@@ -1527,7 +1527,7 @@ static int fpux_emu(struct pt_regs *xcp, struct 
mips_fpu_struct *ctx,
+                       break;
+ 
+               default:
+-                      return SIGILL;
++                      goto SIGILL_unless_prefx_op;
+               }
+               break;
+       }
+@@ -1597,7 +1597,7 @@ static int fpux_emu(struct pt_regs *xcp, struct 
mips_fpu_struct *ctx,
+                       goto copcsr;
+ 
+               default:
+-                      return SIGILL;
++                      goto SIGILL_unless_prefx_op;
+               }
+               break;
+       }
+@@ -1610,6 +1610,11 @@ static int fpux_emu(struct pt_regs *xcp, struct 
mips_fpu_struct *ctx,
+               break;
+ 
+       default:
++            SIGILL_unless_prefx_op:
++              if (MIPSInst_FUNC(ir) == prefx_op) {
++                      /* ignore prefx operation */
++                      break;
++              }
+               return SIGILL;
+       }
+ 
+-- 
+2.4.3
+
diff --git a/gnu/packages/patches/linux-libre-yeeloong-rfkill-key-fix.patch 
b/gnu/packages/patches/linux-libre-yeeloong-rfkill-key-fix.patch
new file mode 100644
index 0000000..44f3d72
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-yeeloong-rfkill-key-fix.patch
@@ -0,0 +1,48 @@
+From c49e2c1b1dbe95821f8134a48ca747e5161e75a6 Mon Sep 17 00:00:00 2001
+From: Mark H Weaver <address@hidden>
+Date: Sun, 23 Aug 2015 17:06:18 -0400
+Subject: [PATCH] Yeeloong: Ignore the Fn + F5 (rfkill toggle) key combination.
+
+* drivers/platform/mips/yeeloong_laptop.c (yeeloong_keymap): Do not
+  generate a user-visible key press from the Fn + F5 key combination.
+---
+ drivers/platform/mips/yeeloong_laptop.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/mips/yeeloong_laptop.c 
b/drivers/platform/mips/yeeloong_laptop.c
+index 9f2d81b..6d7cde6 100644
+--- a/drivers/platform/mips/yeeloong_laptop.c
++++ b/drivers/platform/mips/yeeloong_laptop.c
+@@ -803,7 +803,28 @@ static const struct key_entry yeeloong_keymap[] = {
+       {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
+       {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */
+       {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */
+-      {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
++
++      /* XXX Fn + F5 is handled at a lower level (presumably by the
++         embedded controller) to toggle the state of the hardware
++         rfkill switch of the internal RTL8187B wireless adapter.
++
++         If we also map it to KEY_WLAN, as is done by the
++         loongson-community kernel as of August 2015, that causes
++         the generic rfkill input subsystem to toggle the state of
++         the software rfkill switch for all wireless devices.
++
++         At boot time, these two switch states start out
++         out-of-sync, so rfkill is always blocked by one or the
++         other: pressing Fn + F5 merely toggles whether it is the
++         software or hardware rfkill switch that's causing the
++         block.  Even if we arranged to start with these two switch
++         states in sync, they might possibly get out of sync at some
++         point.  It seems fragile.
++
++         So, instead, we simply avoid the dual meaning of this key,
++         by ignoring the key from software. */
++      {KE_IGNORE, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
++
+       {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */
+       {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + 
down */
+       {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */
+-- 
+2.5.0
+
diff --git 
a/gnu/packages/patches/linux-libre-yeeloong-silence-ec-messages.patch 
b/gnu/packages/patches/linux-libre-yeeloong-silence-ec-messages.patch
new file mode 100644
index 0000000..0be067c
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-yeeloong-silence-ec-messages.patch
@@ -0,0 +1,26 @@
+From 2db1cedcf67ef5e1703069bbbdbac8483cd002e1 Mon Sep 17 00:00:00 2001
+From: Mark H Weaver <address@hidden>
+Date: Sat, 5 Sep 2015 23:44:59 -0400
+Subject: [PATCH] yeeloong: Change "ec issued command" from KERN_INFO to
+ KERN_DEBUG.
+
+---
+ arch/mips/loongson64/lemote-2f/ec_kb3310b.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/mips/loongson64/lemote-2f/ec_kb3310b.c 
b/arch/mips/loongson64/lemote-2f/ec_kb3310b.c
+index 2b666d3..c5f4b82 100644
+--- a/arch/mips/loongson64/lemote-2f/ec_kb3310b.c
++++ b/arch/mips/loongson64/lemote-2f/ec_kb3310b.c
+@@ -79,7 +79,7 @@ int ec_query_seq(unsigned char cmd)
+               printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
+               ret = -EINVAL;
+       } else
+-              printk(KERN_INFO
++              printk(KERN_DEBUG
+                          "(%x/%d)ec issued command %d status : 0x%x\n",
+                          timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
+ 
+-- 
+2.5.0
+
diff --git a/gnu/packages/patches/linux-libre-yeeloong.patch 
b/gnu/packages/patches/linux-libre-yeeloong.patch
new file mode 100644
index 0000000..4dcf2d3
--- /dev/null
+++ b/gnu/packages/patches/linux-libre-yeeloong.patch
@@ -0,0 +1,3451 @@
+Add support for Lemote machines based on the Loongson 2F.  This selection of
+patches was derived from looking at the differences between the linux-stable
+and loongson-community git repositories.
+
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index f501665..a672872 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -359,7 +359,7 @@ config LASAT
+ 
+ config MACH_LOONGSON64
+       bool "Loongson-2/3 family of machines"
+-      select SYS_SUPPORTS_ZBOOT
++      select SYS_SUPPORTS_ZBOOT_UART16550
+       help
+         This enables the support of Loongson-2/3 family of machines.
+ 
+@@ -1725,6 +1725,7 @@ config CPU_LOONGSON2
+       select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HIGHMEM
+       select CPU_SUPPORTS_HUGEPAGES
++      select ARCH_WANT_OPTIONAL_GPIOLIB
+ 
+ config CPU_LOONGSON1
+       bool
+@@ -2397,7 +2398,7 @@ config CPU_SUPPORTS_MSA
+ 
+ config ARCH_FLATMEM_ENABLE
+       def_bool y
+-      depends on !NUMA && !CPU_LOONGSON2
++      depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION)
+ 
+ config ARCH_DISCONTIGMEM_ENABLE
+       bool
+diff --git a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536.h 
b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536.h
+index a0ee0cb..4e18add 100644
+--- a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536.h
++++ b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536.h
+@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo);
+ /* GPIO : I/O SPACE; REG : 32BITS */
+ #define GPIOL_OUT_VAL         0x00
+ #define GPIOL_OUT_EN          0x04
++#define GPIOL_OUT_AUX1_SEL    0x10
++/* SMB : I/O SPACE, REG : 8BITS WIDTH */
++#define       SMB_SDA                 0x00
++#define       SMB_STS                 0x01
++#define       SMB_STS_SLVSTP          (1 << 7)
++#define       SMB_STS_SDAST           (1 << 6)
++#define       SMB_STS_BER             (1 << 5)
++#define       SMB_STS_NEGACK          (1 << 4)
++#define       SMB_STS_STASTR          (1 << 3)
++#define       SMB_STS_NMATCH          (1 << 2)
++#define       SMB_STS_MASTER          (1 << 1)
++#define       SMB_STS_XMIT            (1 << 0)
++#define       SMB_CTRL_STS            0x02
++#define       SMB_CSTS_TGSTL          (1 << 5)
++#define       SMB_CSTS_TSDA           (1 << 4)
++#define       SMB_CSTS_GCMTCH         (1 << 3)
++#define       SMB_CSTS_MATCH          (1 << 2)
++#define       SMB_CSTS_BB             (1 << 1)
++#define       SMB_CSTS_BUSY           (1 << 0)
++#define       SMB_CTRL1               0x03
++#define       SMB_CTRL1_STASTRE       (1 << 7)
++#define       SMB_CTRL1_NMINTE        (1 << 6)
++#define       SMB_CTRL1_GCMEN         (1 << 5)
++#define       SMB_CTRL1_ACK           (1 << 4)
++#define       SMB_CTRL1_RSVD          (1 << 3)
++#define       SMB_CTRL1_INTEN         (1 << 2)
++#define       SMB_CTRL1_STOP          (1 << 1)
++#define       SMB_CTRL1_START         (1 << 0)
++#define       SMB_ADDR                0x04
++#define       SMB_ADDR_SAEN           (1 << 7)
++#define       SMB_CONTROLLER_ADDR     (0xef << 0)
++#define       SMB_CTRL2               0x05
++#define       SMB_FREQ                (0x20 << 1)
++#define       SMB_ENABLE              (0x01 << 0)
++#define       SMB_CTRL3               0x06
+ 
+ #endif                                /* _CS5536_H */
+diff --git a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_mfgpt.h 
b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_mfgpt.h
+index 021d017..50aafca 100644
+--- a/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_mfgpt.h
++++ b/arch/mips/include/asm/mach-loongson64/cs5536/cs5536_mfgpt.h
+@@ -28,8 +28,19 @@ static inline void __maybe_unused 
enable_mfgpt0_counter(void)
+ #define COMPARE        ((MFGPT_TICK_RATE + HZ/2) / HZ)
+ 
+ #define MFGPT_BASE    mfgpt_base
++#define MFGPT0_CMP1   (MFGPT_BASE + 0)
+ #define MFGPT0_CMP2   (MFGPT_BASE + 2)
+ #define MFGPT0_CNT    (MFGPT_BASE + 4)
+ #define MFGPT0_SETUP  (MFGPT_BASE + 6)
+ 
++#define MFGPT1_CMP1   (MFGPT_BASE + 0x08)
++#define MFGPT1_CMP2   (MFGPT_BASE + 0x0A)
++#define MFGPT1_CNT    (MFGPT_BASE + 0x0C)
++#define MFGPT1_SETUP  (MFGPT_BASE + 0x0E)
++
++#define MFGPT2_CMP1   (MFGPT_BASE + 0x10)
++#define MFGPT2_CMP2   (MFGPT_BASE + 0x12)
++#define MFGPT2_CNT    (MFGPT_BASE + 0x14)
++#define MFGPT2_SETUP  (MFGPT_BASE + 0x16)
++
+ #endif /*!_CS5536_MFGPT_H */
+diff --git a/arch/mips/include/asm/mach-loongson64/loongson.h 
b/arch/mips/include/asm/mach-loongson64/loongson.h
+index 9783103..e6febaf 100644
+--- a/arch/mips/include/asm/mach-loongson64/loongson.h
++++ b/arch/mips/include/asm/mach-loongson64/loongson.h
+@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void)
+ #endif
+ }
+ 
++/*
++ * Copy kernel command line from arcs_cmdline
++ */
++#include <asm/setup.h>
++extern char loongson_cmdline[COMMAND_LINE_SIZE];
++
+ /* irq operation functions */
+ extern void bonito_irqdispatch(void);
+ extern void __init bonito_irq_init(void);
+diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
+index 8d01709..9cd25da 100644
+--- a/arch/mips/kernel/time.c
++++ b/arch/mips/kernel/time.c
+@@ -119,6 +119,11 @@ static __init int cpu_has_mfc0_count_bug(void)
+ 
+ void __init time_init(void)
+ {
++#ifdef CONFIG_HR_SCHED_CLOCK
++      if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
++              write_c0_count(0);
++#endif
++
+       plat_time_init();
+ 
+       /*
+diff --git a/arch/mips/loongson64/Kconfig b/arch/mips/loongson64/Kconfig
+index 156de85..659ca91 100644
+--- a/arch/mips/loongson64/Kconfig
++++ b/arch/mips/loongson64/Kconfig
+@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E
+ 
+ config LEMOTE_MACH2F
+       bool "Lemote Loongson 2F family machines"
+-      select ARCH_SPARSEMEM_ENABLE
++      select ARCH_SPARSEMEM_ENABLE if HIBERNATION
+       select BOARD_SCACHE
+       select BOOT_ELF32
+       select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
+       select CPU_HAS_WB
+-      select CS5536
++      select CS5536 if PCI
+       select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
+       select DMA_NONCOHERENT
+       select GENERIC_ISA_DMA_SUPPORT_BROKEN
+@@ -45,14 +45,13 @@ config LEMOTE_MACH2F
+       select HW_HAS_PCI
+       select I8259
+       select IRQ_MIPS_CPU
+-      select ISA
+       select SYS_HAS_CPU_LOONGSON2F
+       select SYS_HAS_EARLY_PRINTK
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
+       select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+-      select LOONGSON_MC146818
++      select LOONGSON_MC146818 if RTC_DRV_CMOS
+       help
+         Lemote Loongson 2F family machines utilize the 2F revision of
+         Loongson processor and the AMD CS5536 south bridge.
+diff --git a/arch/mips/loongson64/common/cmdline.c 
b/arch/mips/loongson64/common/cmdline.c
+index 72fed00..679a18a 100644
+--- a/arch/mips/loongson64/common/cmdline.c
++++ b/arch/mips/loongson64/common/cmdline.c
+@@ -17,10 +17,15 @@
+  * Free Software Foundation;  either version 2 of the  License, or (at your
+  * option) any later version.
+  */
++#include <linux/module.h>
+ #include <asm/bootinfo.h>
+ 
+ #include <loongson.h>
+ 
++/* the kernel command line copied from arcs_cmdline */
++char loongson_cmdline[COMMAND_LINE_SIZE];
++EXPORT_SYMBOL(loongson_cmdline);
++
+ void __init prom_init_cmdline(void)
+ {
+       int prom_argc;
+@@ -45,4 +50,26 @@ void __init prom_init_cmdline(void)
+       }
+ 
+       prom_init_machtype();
++
++      /* append machine specific command line */
++      switch (mips_machtype) {
++      case MACH_LEMOTE_LL2F:
++              if ((strstr(arcs_cmdline, "video=")) == NULL)
++                      strcat(arcs_cmdline, " video=sisfb:address@hidden");
++              break;
++      case MACH_LEMOTE_FL2F:
++              if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL)
++                      strcat(arcs_cmdline, " ide_core.ignore_cable=0");
++              break;
++      case MACH_LEMOTE_ML2F7:
++              /* Mengloong-2F has a 800x480 screen */
++              if ((strstr(arcs_cmdline, "vga=")) == NULL)
++                      strcat(arcs_cmdline, " vga=0x313");
++              break;
++      default:
++              break;
++      }
++
++      /* copy arcs_cmdline into loongson_cmdline */
++      strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+diff --git a/arch/mips/loongson64/lemote-2f/Makefile 
b/arch/mips/loongson64/lemote-2f/Makefile
+index 4f9eaa3..f945bd7 100644
+--- a/arch/mips/loongson64/lemote-2f/Makefile
++++ b/arch/mips/loongson64/lemote-2f/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for lemote loongson2f family machines
+ #
+ 
+-obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o
++obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o
+ 
+ #
+ # Suspend Support
+diff --git a/arch/mips/loongson64/lemote-2f/platform.c 
b/arch/mips/loongson64/lemote-2f/platform.c
+new file mode 100644
+index 0000000..5316360
+--- /dev/null
++++ b/arch/mips/loongson64/lemote-2f/platform.c
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: Wu Zhangjin, address@hidden
++ *
++ * 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.
++ */
++
++#include <linux/err.h>
++#include <linux/platform_device.h>
++
++#include <asm/bootinfo.h>
++
++static struct platform_device yeeloong_pdev = {
++      .name = "yeeloong_laptop",
++      .id = -1,
++};
++
++static struct platform_device lynloong_pdev = {
++      .name = "lynloong_pc",
++      .id = -1,
++};
++
++static int __init lemote2f_platform_init(void)
++{
++      struct platform_device *pdev = NULL;
++
++      switch (mips_machtype) {
++      case MACH_LEMOTE_YL2F89:
++              pdev = &yeeloong_pdev;
++              break;
++      case MACH_LEMOTE_LL2F:
++              pdev = &lynloong_pdev;
++              break;
++      default:
++              break;
++
++      }
++
++      if (pdev != NULL)
++              return platform_device_register(pdev);
++
++      return -ENODEV;
++}
++
++arch_initcall(lemote2f_platform_init);
+diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
+index 376f2dc..b576801 100644
+--- a/drivers/ide/ide-iops.c
++++ b/drivers/ide/ide-iops.c
+@@ -27,6 +27,10 @@
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ 
++#ifdef CONFIG_LEMOTE_MACH2F
++#include <asm/bootinfo.h>
++#endif
++
+ void SELECT_MASK(ide_drive_t *drive, int mask)
+ {
+       const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive)
+ {
+       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+ 
++#ifdef CONFIG_LEMOTE_MACH2F
++      if (mips_machtype != MACH_LEMOTE_YL2F89)
++              return;
++#endif
++
+       for (list = nien_quirk_list; *list != NULL; list++)
+               if (strstr(m, *list) != NULL) {
+                       drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
+diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
+index 125e569..c80714b 100644
+--- a/drivers/platform/mips/Kconfig
++++ b/drivers/platform/mips/Kconfig
+@@ -15,6 +15,38 @@ menuconfig MIPS_PLATFORM_DEVICES
+ 
+ if MIPS_PLATFORM_DEVICES
+ 
++config LEMOTE_YEELOONG2F
++      tristate "Lemote YeeLoong Laptop"
++      depends on LEMOTE_MACH2F
++      select BACKLIGHT_LCD_SUPPORT
++      select LCD_CLASS_DEVICE
++      select BACKLIGHT_CLASS_DEVICE
++      select POWER_SUPPLY
++      select HWMON
++      select VIDEO_OUTPUT_CONTROL
++      select INPUT_SPARSEKMAP
++      select INPUT_EVDEV
++      depends on INPUT
++      default m
++      help
++        YeeLoong netbook is a mini laptop made by Lemote, which is basically
++        compatible to FuLoong2F mini PC, but it has an extra Embedded
++        Controller(kb3310b) for battery, hotkey, backlight, temperature and
++        fan management.
++
++config LEMOTE_LYNLOONG2F
++      tristate "Lemote LynLoong PC"
++      depends on LEMOTE_MACH2F
++      select BACKLIGHT_LCD_SUPPORT
++      select BACKLIGHT_CLASS_DEVICE
++      select VIDEO_OUTPUT_CONTROL
++      default m
++      help
++        LynLoong PC is an AllINONE machine made by Lemote, which is basically
++        compatible to FuLoong2F Mini PC, the only difference is that it has a
++        size-fixed screen: 1360x768 with sisfb video driver. and also, it has
++        its own specific suspend support.
++
+ config MIPS_ACPI
+       bool
+       default y if LOONGSON_MACH3X
+diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
+index 4341284..0e21bfb 100644
+--- a/drivers/platform/mips/Makefile
++++ b/drivers/platform/mips/Makefile
+@@ -1,2 +1,11 @@
++#
++# Makefile for MIPS Platform-Specific Drivers
++#
++
++obj-$(CONFIG_LEMOTE_YEELOONG2F)       += yeeloong_laptop.o # yeeloong_ecrom.o
++CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson64/lemote-2f
++
++obj-$(CONFIG_LEMOTE_LYNLOONG2F)       += lynloong_pc.o
++
+ obj-$(CONFIG_MIPS_ACPI) += acpi_init.o
+ obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o
+diff --git a/drivers/platform/mips/lynloong_pc.c 
b/drivers/platform/mips/lynloong_pc.c
+new file mode 100644
+index 0000000..68f29e4
+--- /dev/null
++++ b/drivers/platform/mips/lynloong_pc.c
+@@ -0,0 +1,515 @@
++/*
++ * Driver for LynLoong PC extras
++ *
++ *  Copyright (C) 2009 Lemote Inc.
++ *  Author: Wu Zhangjin <address@hidden>, Xiang Yu <address@hidden>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/backlight.h>  /* for backlight subdriver */
++#include <linux/fb.h>
++#include <linux/video_output.h>       /* for video output subdriver */
++#include <linux/delay.h>      /* for suspend support */
++
++#include <cs5536/cs5536.h>
++#include <cs5536/cs5536_mfgpt.h>
++
++#include <loongson.h>
++
++static u32 gpio_base, mfgpt_base;
++
++static void set_gpio_reg_high(int gpio, int reg)
++{
++      u32 val;
++
++      val = inl(gpio_base + reg);
++      val |= (1 << gpio);
++      val &= ~(1 << (16 + gpio));
++      outl(val, gpio_base + reg);
++      mmiowb();
++}
++
++static void set_gpio_reg_low(int gpio, int reg)
++{
++      u32 val;
++
++      val = inl(gpio_base + reg);
++      val |= (1 << (16 + gpio));
++      val &= ~(1 << gpio);
++      outl(val, gpio_base + reg);
++      mmiowb();
++}
++
++static void set_gpio_output_low(int gpio)
++{
++      set_gpio_reg_high(gpio, GPIOL_OUT_EN);
++      set_gpio_reg_low(gpio, GPIOL_OUT_VAL);
++}
++
++static void set_gpio_output_high(int gpio)
++{
++      set_gpio_reg_high(gpio, GPIOL_OUT_EN);
++      set_gpio_reg_high(gpio, GPIOL_OUT_VAL);
++}
++
++/* backlight subdriver */
++
++#define MAX_BRIGHTNESS 100
++#define DEFAULT_BRIGHTNESS 50
++#define MIN_BRIGHTNESS 0
++static unsigned int level;
++
++DEFINE_SPINLOCK(backlight_lock);
++/* Tune the brightness */
++static void setup_mfgpt2(void)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&backlight_lock, flags);
++
++      /* Set MFGPT2 comparator 1,2 */
++      outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1);
++      outw(MAX_BRIGHTNESS, MFGPT2_CMP2);
++      /* Clear MFGPT2 UP COUNTER */
++      outw(0, MFGPT2_CNT);
++      /* Enable counter, compare mode, 32k */
++      outw(0x8280, MFGPT2_SETUP);
++
++      spin_unlock_irqrestore(&backlight_lock, flags);
++}
++
++static int lynloong_set_brightness(struct backlight_device *bd)
++{
++      level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
++               bd->props.power == FB_BLANK_UNBLANK) ?
++          bd->props.brightness : 0;
++
++      if (level > MAX_BRIGHTNESS)
++              level = MAX_BRIGHTNESS;
++      else if (level < MIN_BRIGHTNESS)
++              level = MIN_BRIGHTNESS;
++
++      setup_mfgpt2();
++
++      return 0;
++}
++
++static int lynloong_get_brightness(struct backlight_device *bd)
++{
++      return level;
++}
++
++static struct backlight_ops backlight_ops = {
++      .get_brightness = lynloong_get_brightness,
++      .update_status = lynloong_set_brightness,
++};
++
++static struct backlight_device *lynloong_backlight_dev;
++
++static int lynloong_backlight_init(void)
++{
++      int ret;
++      u32 hi;
++      struct backlight_properties props;
++
++      /* Get gpio_base */
++      _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
++      /* Get mfgpt_base */
++      _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base);
++      /* Get gpio_base */
++      _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
++
++      /* Select for mfgpt */
++      set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL);
++      /* Enable brightness controlling */
++      set_gpio_output_high(7);
++
++      memset(&props, 0, sizeof(struct backlight_properties));
++      props.max_brightness = MAX_BRIGHTNESS;
++      props.type = BACKLIGHT_PLATFORM;
++      lynloong_backlight_dev = backlight_device_register("backlight0", NULL,
++                      NULL, &backlight_ops, &props);
++
++      if (IS_ERR(lynloong_backlight_dev)) {
++              ret = PTR_ERR(lynloong_backlight_dev);
++              return ret;
++      }
++
++      lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS;
++      backlight_update_status(lynloong_backlight_dev);
++
++      return 0;
++}
++
++static void lynloong_backlight_exit(void)
++{
++      if (lynloong_backlight_dev) {
++              backlight_device_unregister(lynloong_backlight_dev);
++              lynloong_backlight_dev = NULL;
++      }
++      /* Disable brightness controlling */
++      set_gpio_output_low(7);
++}
++
++/* video output driver */
++static int vo_status = 1;
++
++static int lcd_video_output_get(struct output_device *od)
++{
++      return vo_status;
++}
++
++static int lcd_video_output_set(struct output_device *od)
++{
++      int i;
++      unsigned long status;
++
++      status = !!od->request_state;
++
++      if (status == 0) {
++              /* Set the current status as off */
++              vo_status = 0;
++              /* Turn off the backlight */
++              set_gpio_output_low(11);
++              for (i = 0; i < 0x500; i++)
++                      delay();
++              /* Turn off the LCD */
++              set_gpio_output_high(8);
++      } else {
++              /* Turn on the LCD */
++              set_gpio_output_low(8);
++              for (i = 0; i < 0x500; i++)
++                      delay();
++              /* Turn on the backlight */
++              set_gpio_output_high(11);
++              /* Set the current status as on */
++              vo_status = 1;
++      }
++
++      return 0;
++}
++
++static struct output_properties lcd_output_properties = {
++      .set_state = lcd_video_output_set,
++      .get_status = lcd_video_output_get,
++};
++
++static struct output_device *lcd_output_dev;
++
++static void lynloong_lcd_vo_set(int status)
++{
++      lcd_output_dev->request_state = status;
++      lcd_video_output_set(lcd_output_dev);
++}
++
++static int lynloong_vo_init(void)
++{
++      int ret;
++
++      /* Register video output device: lcd */
++      lcd_output_dev = video_output_register("LCD", NULL, NULL,
++                      &lcd_output_properties);
++
++      if (IS_ERR(lcd_output_dev)) {
++              ret = PTR_ERR(lcd_output_dev);
++              lcd_output_dev = NULL;
++              return ret;
++      }
++      /* Ensure LCD is on by default */
++      lynloong_lcd_vo_set(1);
++
++      return 0;
++}
++
++static void lynloong_vo_exit(void)
++{
++      if (lcd_output_dev) {
++              video_output_unregister(lcd_output_dev);
++              lcd_output_dev = NULL;
++      }
++}
++
++/* suspend support */
++
++#ifdef CONFIG_PM
++
++static u32 smb_base;
++
++/* I2C operations */
++
++static int i2c_wait(void)
++{
++      char c;
++      int i;
++
++      udelay(1000);
++      for (i = 0; i < 20; i++) {
++              c = inb(smb_base | SMB_STS);
++              if (c & (SMB_STS_BER | SMB_STS_NEGACK))
++                      return -1;
++              if (c & SMB_STS_SDAST)
++                      return 0;
++              udelay(100);
++      }
++      return -2;
++}
++
++static void i2c_read_single(int addr, int regNo, char *value)
++{
++      unsigned char c;
++
++      /* Start condition */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++      i2c_wait();
++
++      /* Send slave address */
++      outb(addr & 0xfe, smb_base | SMB_SDA);
++      i2c_wait();
++
++      /* Acknowledge smbus */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++      /* Send register index */
++      outb(regNo, smb_base | SMB_SDA);
++      i2c_wait();
++
++      /* Acknowledge smbus */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++      /* Start condition again */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++      i2c_wait();
++
++      /* Send salve address again */
++      outb(1 | addr, smb_base | SMB_SDA);
++      i2c_wait();
++
++      /* Acknowledge smbus */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
++
++      /* Read data */
++      *value = inb(smb_base | SMB_SDA);
++
++      /* Stop condition */
++      outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
++      i2c_wait();
++}
++
++static void i2c_write_single(int addr, int regNo, char value)
++{
++      unsigned char c;
++
++      /* Start condition */
++      c = inb(smb_base | SMB_CTRL1);
++      outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
++      i2c_wait();
++      /* Send slave address */
++      outb(addr & 0xfe, smb_base | SMB_SDA);
++      i2c_wait();;
++
++      /* Send register index */
++      outb(regNo, smb_base | SMB_SDA);
++      i2c_wait();
++
++      /* Write data */
++      outb(value, smb_base | SMB_SDA);
++      i2c_wait();
++      /* Stop condition */
++      outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
++      i2c_wait();
++}
++
++static void stop_clock(int clk_reg, int clk_sel)
++{
++      u8 value;
++
++      i2c_read_single(0xd3, clk_reg, &value);
++      value &= ~(1 << clk_sel);
++      i2c_write_single(0xd2, clk_reg, value);
++}
++
++static void enable_clock(int clk_reg, int clk_sel)
++{
++      u8 value;
++
++      i2c_read_single(0xd3, clk_reg, &value);
++      value |= (1 << clk_sel);
++      i2c_write_single(0xd2, clk_reg, value);
++}
++
++static char cached_clk_freq;
++static char cached_pci_fixed_freq;
++
++static void decrease_clk_freq(void)
++{
++      char value;
++
++      i2c_read_single(0xd3, 1, &value);
++      cached_clk_freq = value;
++
++      /* Select frequency by software */
++      value |= (1 << 1);
++      /* CPU, 3V66, PCI : 100, 66, 33(1) */
++      value |= (1 << 2);
++      i2c_write_single(0xd2, 1, value);
++
++      /* Cache the pci frequency */
++      i2c_read_single(0xd3, 14, &value);
++      cached_pci_fixed_freq = value;
++
++      /* Enable PCI fix mode */
++      value |= (1 << 5);
++      /* 3V66, PCI : 64MHz, 32MHz */
++      value |= (1 << 3);
++      i2c_write_single(0xd2, 14, value);
++
++}
++
++static void resume_clk_freq(void)
++{
++      i2c_write_single(0xd2, 1, cached_clk_freq);
++      i2c_write_single(0xd2, 14, cached_pci_fixed_freq);
++}
++
++static void stop_clocks(void)
++{
++      /* CPU Clock Register */
++      stop_clock(2, 5);       /* not used */
++      stop_clock(2, 6);       /* not used */
++      stop_clock(2, 7);       /* not used */
++
++      /* PCI Clock Register */
++      stop_clock(3, 1);       /* 8100 */
++      stop_clock(3, 5);       /* SIS */
++      stop_clock(3, 0);       /* not used */
++      stop_clock(3, 6);       /* not used */
++
++      /* PCI 48M Clock Register */
++      stop_clock(4, 6);       /* USB grounding */
++      stop_clock(4, 5);       /* REF(5536_14M) */
++
++      /* 3V66 Control Register */
++      stop_clock(5, 0);       /* VCH_CLK..., grounding */
++}
++
++static void enable_clocks(void)
++{
++      enable_clock(3, 1);     /* 8100 */
++      enable_clock(3, 5);     /* SIS */
++
++      enable_clock(4, 6);
++      enable_clock(4, 5);     /* REF(5536_14M) */
++
++      enable_clock(5, 0);     /* VCH_CLOCK, grounding */
++}
++
++static int lynloong_suspend(struct device *dev)
++{
++      /* Disable AMP */
++      set_gpio_output_high(6);
++      /* Turn off LCD */
++      lynloong_lcd_vo_set(0);
++
++      /* Stop the clocks of some devices */
++      stop_clocks();
++
++      /* Decrease the external clock frequency */
++      decrease_clk_freq();
++
++      return 0;
++}
++
++static int lynloong_resume(struct device *dev)
++{
++      /* Turn on the LCD */
++      lynloong_lcd_vo_set(1);
++
++      /* Resume clock frequency, enable the relative clocks */
++      resume_clk_freq();
++      enable_clocks();
++
++      /* Enable AMP */
++      set_gpio_output_low(6);
++
++      return 0;
++}
++
++static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend,
++      lynloong_resume);
++#endif        /* !CONFIG_PM */
++
++static struct platform_device_id platform_device_ids[] = {
++      {
++              .name = "lynloong_pc",
++      },
++      {}
++};
++
++MODULE_DEVICE_TABLE(platform, platform_device_ids);
++
++static struct platform_driver platform_driver = {
++      .driver = {
++              .name = "lynloong_pc",
++              .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++              .pm = &lynloong_pm_ops,
++#endif
++      },
++      .id_table = platform_device_ids,
++};
++
++static int __init lynloong_init(void)
++{
++      int ret;
++
++      pr_info("LynLoong platform specific driver loaded.\n");
++
++      /* Register platform stuff */
++      ret = platform_driver_register(&platform_driver);
++      if (ret) {
++              pr_err("Failed to register LynLoong platform driver.\n");
++              return ret;
++      }
++
++      ret = lynloong_backlight_init();
++      if (ret) {
++              pr_err("Failed to register LynLoong backlight driver.\n");
++              return ret;
++      }
++
++      ret = lynloong_vo_init();
++      if (ret) {
++              pr_err("Failed to register LynLoong backlight driver.\n");
++              lynloong_vo_exit();
++              return ret;
++      }
++
++      return 0;
++}
++
++static void __exit lynloong_exit(void)
++{
++      lynloong_vo_exit();
++      lynloong_backlight_exit();
++      platform_driver_unregister(&platform_driver);
++
++      pr_info("LynLoong platform specific driver unloaded.\n");
++}
++
++module_init(lynloong_init);
++module_exit(lynloong_exit);
++
++MODULE_AUTHOR("Wu Zhangjin <address@hidden>; Xiang Yu <address@hidden>");
++MODULE_DESCRIPTION("LynLoong PC driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/platform/mips/yeeloong_ecrom.c 
b/drivers/platform/mips/yeeloong_ecrom.c
+new file mode 100644
+index 0000000..1bfe4cf
+--- /dev/null
++++ b/drivers/platform/mips/yeeloong_ecrom.c
+@@ -0,0 +1,944 @@
++/*
++ * Driver for flushing/dumping ROM of EC on YeeLoong laptop
++ *
++ * Copyright (C) 2009 Lemote Inc.
++ * Author: liujl <address@hidden>
++ *
++ * NOTE :
++ *    The EC resources accessing and programming are supported.
++ */
++
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <ec_kb3310b.h>
++
++#define       EC_MISC_DEV             "ec_misc"
++#define EC_IOC_MAGIC          'E'
++
++/* ec registers range */
++#define       EC_MAX_REGADDR  0xFFFF
++#define       EC_MIN_REGADDR  0xF000
++#define       EC_RAM_ADDR     0xF800
++
++/* version burned address */
++#define       VER_ADDR        0xf7a1
++#define       VER_MAX_SIZE    7
++#define       EC_ROM_MAX_SIZE 0x10000
++
++/* ec internal register */
++#define       REG_POWER_MODE          0xF710
++#define       FLAG_NORMAL_MODE        0x00
++#define       FLAG_IDLE_MODE          0x01
++#define       FLAG_RESET_MODE         0x02
++
++/* ec update program flag */
++#define       PROGRAM_FLAG_NONE       0x00
++#define       PROGRAM_FLAG_IE         0x01
++#define       PROGRAM_FLAG_ROM        0x02
++
++/* XBI relative registers */
++#define REG_XBISEG0     0xFEA0
++#define REG_XBISEG1     0xFEA1
++#define REG_XBIRSV2     0xFEA2
++#define REG_XBIRSV3     0xFEA3
++#define REG_XBIRSV4     0xFEA4
++#define REG_XBICFG      0xFEA5
++#define REG_XBICS       0xFEA6
++#define REG_XBIWE       0xFEA7
++#define REG_XBISPIA0    0xFEA8
++#define REG_XBISPIA1    0xFEA9
++#define REG_XBISPIA2    0xFEAA
++#define REG_XBISPIDAT   0xFEAB
++#define REG_XBISPICMD   0xFEAC
++#define REG_XBISPICFG   0xFEAD
++#define REG_XBISPIDATR  0xFEAE
++#define REG_XBISPICFG2  0xFEAF
++
++/* commands definition for REG_XBISPICMD */
++#define       SPICMD_WRITE_STATUS             0x01
++#define       SPICMD_BYTE_PROGRAM             0x02
++#define       SPICMD_READ_BYTE                0x03
++#define       SPICMD_WRITE_DISABLE    0x04
++#define       SPICMD_READ_STATUS              0x05
++#define       SPICMD_WRITE_ENABLE             0x06
++#define       SPICMD_HIGH_SPEED_READ  0x0B
++#define       SPICMD_POWER_DOWN               0xB9
++#define       SPICMD_SST_EWSR                 0x50
++#define       SPICMD_SST_SEC_ERASE    0x20
++#define       SPICMD_SST_BLK_ERASE    0x52
++#define       SPICMD_SST_CHIP_ERASE   0x60
++#define       SPICMD_FRDO                             0x3B
++#define       SPICMD_SEC_ERASE                0xD7
++#define       SPICMD_BLK_ERASE                0xD8
++#define SPICMD_CHIP_ERASE             0xC7
++
++/* bits definition for REG_XBISPICFG */
++#define       SPICFG_AUTO_CHECK               0x01
++#define       SPICFG_SPI_BUSY                 0x02
++#define       SPICFG_DUMMY_READ               0x04
++#define       SPICFG_EN_SPICMD                0x08
++#define       SPICFG_LOW_SPICS                0x10
++#define       SPICFG_EN_SHORT_READ    0x20
++#define       SPICFG_EN_OFFSET_READ   0x40
++#define       SPICFG_EN_FAST_READ             0x80
++
++/* watchdog timer registers */
++#define       REG_WDTCFG                              0xfe80
++#define       REG_WDTPF                               0xfe81
++#define REG_WDT                                       0xfe82
++
++/* lpc configure register */
++#define       REG_LPCCFG                              0xfe95
++
++/* 8051 reg */
++#define       REG_PXCFG                               0xff14
++
++/* Fan register in KB3310 */
++#define       REG_ECFAN_SPEED_LEVEL   0xf4e4
++#define       REG_ECFAN_SWITCH                0xf4d2
++
++/* the ec flash rom id number */
++#define       EC_ROM_PRODUCT_ID_SPANSION      0x01
++#define       EC_ROM_PRODUCT_ID_MXIC          0xC2
++#define       EC_ROM_PRODUCT_ID_AMIC          0x37
++#define       EC_ROM_PRODUCT_ID_EONIC         0x1C
++
++/* misc ioctl operations */
++#define       IOCTL_RDREG             _IOR(EC_IOC_MAGIC, 1, int)
++#define       IOCTL_WRREG             _IOW(EC_IOC_MAGIC, 2, int)
++#define       IOCTL_READ_EC           _IOR(EC_IOC_MAGIC, 3, int)
++#define       IOCTL_PROGRAM_IE        _IOW(EC_IOC_MAGIC, 4, int)
++#define       IOCTL_PROGRAM_EC        _IOW(EC_IOC_MAGIC, 5, int)
++
++/* start address for programming of EC content or IE */
++/*  ec running code start address */
++#define       EC_START_ADDR   0x00000000
++/*  ec information element storing address */
++#define       IE_START_ADDR   0x00020000
++
++/* EC state */
++#define       EC_STATE_IDLE   0x00    /*  ec in idle state */
++#define       EC_STATE_BUSY   0x01    /*  ec in busy state */
++
++/* timeout value for programming */
++#define       EC_FLASH_TIMEOUT        0x1000  /*  ec program timeout */
++/* command checkout timeout including cmd to port or state flag check */
++#define       EC_CMD_TIMEOUT          0x1000
++#define       EC_SPICMD_STANDARD_TIMEOUT      (4 * 1000)      /*  unit : us */
++#define       EC_MAX_DELAY_UNIT       (10)    /*  every time for polling */
++#define       SPI_FINISH_WAIT_TIME    10
++/* EC content max size */
++#define       EC_CONTENT_MAX_SIZE     (64 * 1024)
++#define       IE_CONTENT_MAX_SIZE     (0x100000 - IE_START_ADDR)
++
++/* the register operation access struct */
++struct ec_reg {
++      u32 addr;               /* the address of kb3310 registers */
++      u8 val;                 /* the register value */
++};
++
++struct ec_info {
++      u32 start_addr;
++      u32 size;
++      u8 *buf;
++};
++
++/* open for using rom protection action */
++#define       EC_ROM_PROTECTION
++
++/* enable the chip reset mode */
++static int ec_init_reset_mode(void)
++{
++      int timeout;
++      unsigned char status = 0;
++      int ret = 0;
++
++      /* make chip goto reset mode */
++      ret = ec_query_seq(CMD_INIT_RESET_MODE);
++      if (ret < 0) {
++              printk(KERN_ERR "ec init reset mode failed.\n");
++              goto out;
++      }
++
++      /* make the action take active */
++      timeout = EC_CMD_TIMEOUT;
++      status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
++      while (timeout--) {
++              if (status) {
++                      udelay(EC_REG_DELAY);
++                      break;
++              }
++              status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
++              udelay(EC_REG_DELAY);
++      }
++      if (timeout <= 0) {
++              printk(KERN_ERR "ec rom fixup : can't check reset status.\n");
++              ret = -EINVAL;
++      } else
++              printk(KERN_INFO "(%d/%d)reset 0xf710 :  0x%x\n", timeout,
++                         EC_CMD_TIMEOUT - timeout, status);
++
++      /* set MCU to reset mode */
++      udelay(EC_REG_DELAY);
++      status = ec_read(REG_PXCFG);
++      status |= (1 << 0);
++      ec_write(REG_PXCFG, status);
++      udelay(EC_REG_DELAY);
++
++      /* disable FWH/LPC */
++      udelay(EC_REG_DELAY);
++      status = ec_read(REG_LPCCFG);
++      status &= ~(1 << 7);
++      ec_write(REG_LPCCFG, status);
++      udelay(EC_REG_DELAY);
++
++      printk(KERN_INFO "entering reset mode ok..............\n");
++
++ out:
++      return ret;
++}
++
++/* make ec exit from reset mode */
++static void ec_exit_reset_mode(void)
++{
++      unsigned char regval;
++
++      udelay(EC_REG_DELAY);
++      regval = ec_read(REG_LPCCFG);
++      regval |= (1 << 7);
++      ec_write(REG_LPCCFG, regval);
++      regval = ec_read(REG_PXCFG);
++      regval &= ~(1 << 0);
++      ec_write(REG_PXCFG, regval);
++      printk(KERN_INFO "exit reset mode ok..................\n");
++
++      return;
++}
++
++/* make ec disable WDD */
++static void ec_disable_WDD(void)
++{
++      unsigned char status;
++
++      udelay(EC_REG_DELAY);
++      status = ec_read(REG_WDTCFG);
++      ec_write(REG_WDTPF, 0x03);
++      ec_write(REG_WDTCFG, (status & 0x80) | 0x48);
++      printk(KERN_INFO "Disable WDD ok..................\n");
++
++      return;
++}
++
++/* make ec enable WDD */
++static void ec_enable_WDD(void)
++{
++      unsigned char status;
++
++      udelay(EC_REG_DELAY);
++      status = ec_read(REG_WDTCFG);
++      ec_write(REG_WDT, 0x28);        /* set WDT 5sec(0x28) */
++      ec_write(REG_WDTCFG, (status & 0x80) | 0x03);
++      printk(KERN_INFO "Enable WDD ok..................\n");
++
++      return;
++}
++
++/* make ec goto idle mode */
++static int ec_init_idle_mode(void)
++{
++      int timeout;
++      unsigned char status = 0;
++      int ret = 0;
++
++      ec_query_seq(CMD_INIT_IDLE_MODE);
++
++      /* make the action take active */
++      timeout = EC_CMD_TIMEOUT;
++      status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
++      while (timeout--) {
++              if (status) {
++                      udelay(EC_REG_DELAY);
++                      break;
++              }
++              status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
++              udelay(EC_REG_DELAY);
++      }
++      if (timeout <= 0) {
++              printk(KERN_ERR "ec rom fixup : can't check out the status.\n");
++              ret = -EINVAL;
++      } else
++              printk(KERN_INFO "(%d/%d)0xf710 :  0x%x\n", timeout,
++                         EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE));
++
++      printk(KERN_INFO "entering idle mode ok...................\n");
++
++      return ret;
++}
++
++/* make ec exit from idle mode */
++static int ec_exit_idle_mode(void)
++{
++
++      ec_query_seq(CMD_EXIT_IDLE_MODE);
++
++      printk(KERN_INFO "exit idle mode ok...................\n");
++
++      return 0;
++}
++
++static int ec_instruction_cycle(void)
++{
++      unsigned long timeout;
++      int ret = 0;
++
++      timeout = EC_FLASH_TIMEOUT;
++      while (timeout-- >= 0) {
++              if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY))
++                      break;
++      }
++      if (timeout <= 0) {
++              printk(KERN_ERR
++                     "EC_INSTRUCTION_CYCLE : timeout for check flag.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++ out:
++      return ret;
++}
++
++/* To see if the ec is in busy state or not. */
++static inline int ec_flash_busy(unsigned long timeout)
++{
++      /* assurance the first command be going to rom */
++      if (ec_instruction_cycle() < 0)
++              return EC_STATE_BUSY;
++#if 1
++      timeout = timeout / EC_MAX_DELAY_UNIT;
++      while (timeout-- > 0) {
++              /* check the rom's status of busy flag */
++              ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++              if (ec_instruction_cycle() < 0)
++                      return EC_STATE_BUSY;
++              if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
++                      return EC_STATE_IDLE;
++              udelay(EC_MAX_DELAY_UNIT);
++      }
++      if (timeout <= 0) {
++              printk(KERN_ERR
++                     "EC_FLASH_BUSY : timeout for check rom flag.\n");
++              return EC_STATE_BUSY;
++      }
++#else
++      /* check the rom's status of busy flag */
++      ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++      if (ec_instruction_cycle() < 0)
++              return EC_STATE_BUSY;
++
++      timeout = timeout / EC_MAX_DELAY_UNIT;
++      while (timeout-- > 0) {
++              if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
++                      return EC_STATE_IDLE;
++              udelay(EC_MAX_DELAY_UNIT);
++      }
++      if (timeout <= 0) {
++              printk(KERN_ERR
++                     "EC_FLASH_BUSY : timeout for check rom flag.\n");
++              return EC_STATE_BUSY;
++      }
++#endif
++
++      return EC_STATE_IDLE;
++}
++
++static int rom_instruction_cycle(unsigned char cmd)
++{
++      unsigned long timeout = 0;
++
++      switch (cmd) {
++      case SPICMD_READ_STATUS:
++      case SPICMD_WRITE_ENABLE:
++      case SPICMD_WRITE_DISABLE:
++      case SPICMD_READ_BYTE:
++      case SPICMD_HIGH_SPEED_READ:
++              timeout = 0;
++              break;
++      case SPICMD_WRITE_STATUS:
++              timeout = 300 * 1000;
++              break;
++      case SPICMD_BYTE_PROGRAM:
++              timeout = 5 * 1000;
++              break;
++      case SPICMD_SST_SEC_ERASE:
++      case SPICMD_SEC_ERASE:
++              timeout = 1000 * 1000;
++              break;
++      case SPICMD_SST_BLK_ERASE:
++      case SPICMD_BLK_ERASE:
++              timeout = 3 * 1000 * 1000;
++              break;
++      case SPICMD_SST_CHIP_ERASE:
++      case SPICMD_CHIP_ERASE:
++              timeout = 20 * 1000 * 1000;
++              break;
++      default:
++              timeout = EC_SPICMD_STANDARD_TIMEOUT;
++      }
++      if (timeout == 0)
++              return ec_instruction_cycle();
++      if (timeout < EC_SPICMD_STANDARD_TIMEOUT)
++              timeout = EC_SPICMD_STANDARD_TIMEOUT;
++
++      return ec_flash_busy(timeout);
++}
++
++/* delay for start/stop action */
++static void delay_spi(int n)
++{
++      while (n--)
++              inb(EC_IO_PORT_HIGH);
++}
++
++/* start the action to spi rom function */
++static void ec_start_spi(void)
++{
++      unsigned char val;
++
++      delay_spi(SPI_FINISH_WAIT_TIME);
++      val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK;
++      ec_write(REG_XBISPICFG, val);
++      delay_spi(SPI_FINISH_WAIT_TIME);
++}
++
++/* stop the action to spi rom function */
++static void ec_stop_spi(void)
++{
++      unsigned char val;
++
++      delay_spi(SPI_FINISH_WAIT_TIME);
++      val =
++          ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK));
++      ec_write(REG_XBISPICFG, val);
++      delay_spi(SPI_FINISH_WAIT_TIME);
++}
++
++/* read one byte from xbi interface */
++static int ec_read_byte(unsigned int addr, unsigned char *byte)
++{
++      int ret = 0;
++
++      /* enable spicmd writing. */
++      ec_start_spi();
++
++      /* enable write spi flash */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++      /* write the address */
++      ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
++      ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
++      ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
++      /* start action */
++      ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ);
++      if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++      *byte = ec_read(REG_XBISPIDAT);
++
++ out:
++      /* disable spicmd writing. */
++      ec_stop_spi();
++
++      return ret;
++}
++
++/* write one byte to ec rom */
++static int ec_write_byte(unsigned int addr, unsigned char byte)
++{
++      int ret = 0;
++
++      /* enable spicmd writing. */
++      ec_start_spi();
++
++      /* enable write spi flash */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++      /* write the address */
++      ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
++      ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
++      ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
++      ec_write(REG_XBISPIDAT, byte);
++      /* start action */
++      ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM);
++      if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++ out:
++      /* disable spicmd writing. */
++      ec_stop_spi();
++
++      return ret;
++}
++
++/* unprotect SPI ROM */
++/* EC_ROM_unprotect function code */
++static int EC_ROM_unprotect(void)
++{
++      unsigned char status;
++
++      /* enable write spi flash */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
++              return 1;
++      }
++
++      /* unprotect the status register of rom */
++      ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++      if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
++              printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n");
++              return 1;
++      }
++      status = ec_read(REG_XBISPIDAT);
++      ec_write(REG_XBISPIDAT, status & 0x02);
++      if (ec_instruction_cycle() < 0) {
++              printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n");
++              return 1;
++      }
++
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
++      if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n");
++              return 1;
++      }
++
++      /* enable write spi flash */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
++              return 1;
++      }
++
++      return 0;
++}
++
++/* erase one block or chip or sector as needed */
++static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr)
++{
++      unsigned char status;
++      int ret = 0, i = 0;
++      int unprotect_count = 3;
++      int check_flag = 0;
++
++      /* enable spicmd writing. */
++      ec_start_spi();
++
++#ifdef EC_ROM_PROTECTION
++      /* added for re-check SPICMD_READ_STATUS */
++      while (unprotect_count-- > 0) {
++              if (EC_ROM_unprotect()) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              /* first time:500ms --> 5.5sec -->10.5sec */
++              for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++)
++                      udelay(50000);
++              ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++              if (rom_instruction_cycle(SPICMD_READ_STATUS)
++                              == EC_STATE_BUSY) {
++                      printk(KERN_ERR
++                             "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
++              } else {
++                      status = ec_read(REG_XBISPIDAT);
++                      printk(KERN_INFO "Read unprotect status : 0x%x\n",
++                                 status);
++                      if ((status & 0x1C) == 0x00) {
++                              printk(KERN_INFO
++                                         "Read unprotect status OK1 : 0x%x\n",
++                                         status & 0x1C);
++                              check_flag = 1;
++                              break;
++                      }
++              }
++      }
++
++      if (!check_flag) {
++              printk(KERN_INFO "SPI ROM unprotect fail.\n");
++              return 1;
++      }
++#endif
++
++      /* block address fill */
++      if (erase_cmd == SPICMD_BLK_ERASE) {
++              ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16);
++              ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8);
++              ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0);
++      }
++
++      /* erase the whole chip first */
++      ec_write(REG_XBISPICMD, erase_cmd);
++      if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) {
++              printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n");
++              ret = -EINVAL;
++              goto out;
++      }
++
++ out:
++      /* disable spicmd writing. */
++      ec_stop_spi();
++
++      return ret;
++}
++
++/* update the whole rom content with H/W mode
++ * PLEASE USING ec_unit_erase() FIRSTLY
++ */
++static int ec_program_rom(struct ec_info *info, int flag)
++{
++      unsigned int addr = 0;
++      unsigned long size = 0;
++      unsigned char *ptr = NULL;
++      unsigned char data;
++      unsigned char val = 0;
++      int ret = 0;
++      int i, j;
++      unsigned char status;
++
++      /* modify for program serial No.
++       * set IE_START_ADDR & use idle mode,
++       * disable WDD
++       */
++      if (flag == PROGRAM_FLAG_ROM) {
++              ret = ec_init_reset_mode();
++              addr = info->start_addr + EC_START_ADDR;
++              printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n");
++      } else if (flag == PROGRAM_FLAG_IE) {
++              ret = ec_init_idle_mode();
++              ec_disable_WDD();
++              addr = info->start_addr + IE_START_ADDR;
++              printk(KERN_INFO "PROGRAM_FLAG_IE..............\n");
++      } else {
++              return 0;
++      }
++
++      if (ret < 0) {
++              if (flag == PROGRAM_FLAG_IE)
++                      ec_enable_WDD();
++              return ret;
++      }
++
++      size = info->size;
++      ptr = info->buf;
++      printk(KERN_INFO "starting update ec ROM..............\n");
++
++      ret = ec_unit_erase(SPICMD_BLK_ERASE, addr);
++      if (ret) {
++              printk(KERN_ERR "program ec : erase block failed.\n");
++              goto out;
++      }
++      printk(KERN_ERR "program ec : erase block OK.\n");
++
++      i = 0;
++      while (i < size) {
++              data = *(ptr + i);
++              ec_write_byte(addr, data);
++              ec_read_byte(addr, &val);
++              if (val != data) {
++                      ec_write_byte(addr, data);
++                      ec_read_byte(addr, &val);
++                      if (val != data) {
++                              printk(KERN_INFO
++                              "EC : Second flash program failed at:\t");
++                              printk(KERN_INFO
++                              "addr : 0x%x, source : 0x%x, dest: 0x%x\n",
++                                   addr, data, val);
++                              printk(KERN_INFO "This should not happen... 
STOP\n");
++                              break;
++                      }
++              }
++              i++;
++              addr++;
++      }
++
++#ifdef        EC_ROM_PROTECTION
++      /* we should start spi access firstly */
++      ec_start_spi();
++
++      /* enable write spi flash */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n");
++              goto out1;
++      }
++
++      /* protect the status register of rom */
++      ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
++      if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
++              goto out1;
++      }
++      status = ec_read(REG_XBISPIDAT);
++
++      ec_write(REG_XBISPIDAT, status | 0x1C);
++      if (ec_instruction_cycle() < 0) {
++              printk(KERN_ERR
++                     "EC_PROGRAM_ROM : write status value failed.\n");
++              goto out1;
++      }
++
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
++      if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n");
++              goto out1;
++      }
++#endif
++
++      /* disable the write action to spi rom */
++      ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE);
++      if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) {
++              printk(KERN_ERR
++                     "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n");
++              goto out1;
++      }
++
++ out1:
++      /* we should stop spi access firstly */
++      ec_stop_spi();
++ out:
++      /* for security */
++      for (j = 0; j < 2000; j++)
++              udelay(1000);
++
++      /* modify for program serial No.
++       * after program No exit idle mode
++       * and enable WDD
++       */
++      if (flag == PROGRAM_FLAG_ROM) {
++              /* exit from the reset mode */
++              ec_exit_reset_mode();
++      } else {
++              /* ec exit from idle mode */
++              ret = ec_exit_idle_mode();
++              ec_enable_WDD();
++              if (ret < 0)
++                      return ret;
++      }
++
++      return 0;
++}
++
++/* ioctl  */
++static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd,
++                    u_long arg)
++{
++      struct ec_info ecinfo;
++      void __user *ptr = (void __user *)arg;
++      struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
++      int ret = 0;
++
++      switch (cmd) {
++      case IOCTL_RDREG:
++              ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++              if (ret) {
++                      printk(KERN_ERR "reg read : copy from user error.\n");
++                      return -EFAULT;
++              }
++              if ((ecreg->addr > EC_MAX_REGADDR)
++                  || (ecreg->addr < EC_MIN_REGADDR)) {
++                      printk(KERN_ERR
++                             "reg read : out of register address range.\n");
++                      return -EINVAL;
++              }
++              ecreg->val = ec_read(ecreg->addr);
++              ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
++              if (ret) {
++                      printk(KERN_ERR "reg read : copy to user error.\n");
++                      return -EFAULT;
++              }
++              break;
++      case IOCTL_WRREG:
++              ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++              if (ret) {
++                      printk(KERN_ERR "reg write : copy from user error.\n");
++                      return -EFAULT;
++              }
++              if ((ecreg->addr > EC_MAX_REGADDR)
++                  || (ecreg->addr < EC_MIN_REGADDR)) {
++                      printk(KERN_ERR
++                             "reg write : out of register address range.\n");
++                      return -EINVAL;
++              }
++              ec_write(ecreg->addr, ecreg->val);
++              break;
++      case IOCTL_READ_EC:
++              ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
++              if (ret) {
++                      printk(KERN_ERR "spi read : copy from user error.\n");
++                      return -EFAULT;
++              }
++              if ((ecreg->addr > EC_RAM_ADDR)
++                  && (ecreg->addr < EC_MAX_REGADDR)) {
++                      printk(KERN_ERR
++                             "spi read : out of register address range.\n");
++                      return -EINVAL;
++              }
++              ec_read_byte(ecreg->addr, &(ecreg->val));
++              ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
++              if (ret) {
++                      printk(KERN_ERR "spi read : copy to user error.\n");
++                      return -EFAULT;
++              }
++              break;
++      case IOCTL_PROGRAM_IE:
++              ecinfo.start_addr = EC_START_ADDR;
++              ecinfo.size = EC_CONTENT_MAX_SIZE;
++              ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
++              if (ecinfo.buf == NULL) {
++                      printk(KERN_ERR "program ie : kmalloc failed.\n");
++                      return -ENOMEM;
++              }
++              ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size);
++              if (ret) {
++                      printk(KERN_ERR "program ie : copy from user error.\n");
++                      kfree(ecinfo.buf);
++                      ecinfo.buf = NULL;
++                      return -EFAULT;
++              }
++
++              /* use ec_program_rom to write serial No */
++              ec_program_rom(&ecinfo, PROGRAM_FLAG_IE);
++
++              kfree(ecinfo.buf);
++              ecinfo.buf = NULL;
++              break;
++      case IOCTL_PROGRAM_EC:
++              ecinfo.start_addr = EC_START_ADDR;
++              if (get_user((ecinfo.size), (u32 *) ptr)) {
++                      printk(KERN_ERR "program ec : get user error.\n");
++                      return -EFAULT;
++              }
++              if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) {
++                      printk(KERN_ERR "program ec : size out of limited.\n");
++                      return -EINVAL;
++              }
++              ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
++              if (ecinfo.buf == NULL) {
++                      printk(KERN_ERR "program ec : kmalloc failed.\n");
++                      return -ENOMEM;
++              }
++              ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size);
++              if (ret) {
++                      printk(KERN_ERR "program ec : copy from user error.\n");
++                      kfree(ecinfo.buf);
++                      ecinfo.buf = NULL;
++                      return -EFAULT;
++              }
++
++              ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM);
++
++              kfree(ecinfo.buf);
++              ecinfo.buf = NULL;
++              break;
++
++      default:
++              break;
++      }
++
++      return 0;
++}
++
++static long misc_compat_ioctl(struct file *file, unsigned int cmd,
++                            unsigned long arg)
++{
++      return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg);
++}
++
++static int misc_open(struct inode *inode, struct file *filp)
++{
++      struct ec_reg *ecreg = NULL;
++      ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL);
++      if (ecreg)
++              filp->private_data = ecreg;
++
++      return ecreg ? 0 : -ENOMEM;
++}
++
++static int misc_release(struct inode *inode, struct file *filp)
++{
++      struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
++
++      filp->private_data = NULL;
++      kfree(ecreg);
++
++      return 0;
++}
++
++static const struct file_operations ecmisc_fops = {
++      .open = misc_open,
++      .release = misc_release,
++      .read = NULL,
++      .write = NULL,
++#ifdef        CONFIG_64BIT
++      .compat_ioctl = misc_compat_ioctl,
++#else
++      .ioctl = misc_ioctl,
++#endif
++};
++
++static struct miscdevice ecmisc_device = {
++      .minor = MISC_DYNAMIC_MINOR,
++      .name = EC_MISC_DEV,
++      .fops = &ecmisc_fops
++};
++
++static int __init ecmisc_init(void)
++{
++      int ret;
++
++      printk(KERN_INFO "EC misc device init.\n");
++      ret = misc_register(&ecmisc_device);
++
++      return ret;
++}
++
++static void __exit ecmisc_exit(void)
++{
++      printk(KERN_INFO "EC misc device exit.\n");
++      misc_deregister(&ecmisc_device);
++}
++
++module_init(ecmisc_init);
++module_exit(ecmisc_exit);
++
++MODULE_AUTHOR("liujl <address@hidden>");
++MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong 
laptop");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/platform/mips/yeeloong_laptop.c 
b/drivers/platform/mips/yeeloong_laptop.c
+new file mode 100644
+index 0000000..9f2d81b
+--- /dev/null
++++ b/drivers/platform/mips/yeeloong_laptop.c
+@@ -0,0 +1,1368 @@
++/*
++ * Driver for YeeLoong laptop extras
++ *
++ *  Copyright (C) 2009 Lemote Inc.
++ *  Author: Wu Zhangjin <address@hidden>, Liu Junliang <address@hidden>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/backlight.h>  /* for backlight subdriver */
++#include <linux/fb.h>
++#include <linux/hwmon.h>      /* for hwmon subdriver */
++#include <linux/hwmon-sysfs.h>
++#include <linux/video_output.h>       /* for video output subdriver */
++#include <linux/lcd.h>                /* for lcd output subdriver */
++#include <linux/input.h>      /* for hotkey subdriver */
++#include <linux/input/sparse-keymap.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/power_supply.h>       /* for AC & Battery subdriver */
++#include <linux/reboot.h>     /* for register_reboot_notifier */
++#include <linux/suspend.h>    /* for register_pm_notifier */
++
++#include <cs5536/cs5536.h>
++
++#include <loongson.h>         /* for loongson_cmdline */
++#include <ec_kb3310b.h>
++
++#define ON    1
++#define OFF   0
++#define EVENT_START EVENT_LID
++
++/* common function */
++#define EC_VER_LEN 64
++
++static int ec_version_before(char *version)
++{
++      char *p, ec_ver[EC_VER_LEN];
++
++      p = strstr(loongson_cmdline, "EC_VER=");
++      if (!p)
++              memset(ec_ver, 0, EC_VER_LEN);
++      else {
++              strncpy(ec_ver, p, EC_VER_LEN);
++              p = strstr(ec_ver, " ");
++              if (p)
++                      *p = '\0';
++      }
++
++      return (strncasecmp(ec_ver, version, 64) < 0);
++}
++
++/* backlight subdriver */
++#define MIN_BRIGHTNESS        1
++#define MAX_BRIGHTNESS        8
++
++static int yeeloong_set_brightness(struct backlight_device *bd)
++{
++      unsigned char level;
++      static unsigned char old_level;
++
++      level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
++               bd->props.power == FB_BLANK_UNBLANK) ?
++          bd->props.brightness : 0;
++
++      level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
++
++      /* Avoid to modify the brightness when EC is tuning it */
++      if (old_level != level) {
++              if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level)
++                      ec_write(REG_DISPLAY_BRIGHTNESS, level);
++              old_level = level;
++      }
++
++      return 0;
++}
++
++static int yeeloong_get_brightness(struct backlight_device *bd)
++{
++      return ec_read(REG_DISPLAY_BRIGHTNESS);
++}
++
++static struct backlight_ops backlight_ops = {
++      .get_brightness = yeeloong_get_brightness,
++      .update_status = yeeloong_set_brightness,
++};
++
++static struct backlight_device *yeeloong_backlight_dev;
++
++static int yeeloong_backlight_init(void)
++{
++      int ret;
++      struct backlight_properties props;
++
++      memset(&props, 0, sizeof(struct backlight_properties));
++      props.max_brightness = MAX_BRIGHTNESS;
++      props.type = BACKLIGHT_PLATFORM;
++      yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
++                      NULL, &backlight_ops, &props);
++
++      if (IS_ERR(yeeloong_backlight_dev)) {
++              ret = PTR_ERR(yeeloong_backlight_dev);
++              yeeloong_backlight_dev = NULL;
++              return ret;
++      }
++
++      yeeloong_backlight_dev->props.brightness =
++              yeeloong_get_brightness(yeeloong_backlight_dev);
++      backlight_update_status(yeeloong_backlight_dev);
++
++      return 0;
++}
++
++static void yeeloong_backlight_exit(void)
++{
++      if (yeeloong_backlight_dev) {
++              backlight_device_unregister(yeeloong_backlight_dev);
++              yeeloong_backlight_dev = NULL;
++      }
++}
++
++/* AC & Battery subdriver */
++
++static struct power_supply_desc yeeloong_ac_desc, yeeloong_bat_desc;
++
++#define RET (val->intval)
++
++#define BAT_CAP_CRITICAL 5
++#define BAT_CAP_HIGH     95
++
++#define get_bat(type) \
++      ec_read(REG_BAT_##type)
++
++#define get_bat_l(type) \
++      ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW))
++
++static int yeeloong_get_ac_props(struct power_supply *psy,
++                              enum power_supply_property psp,
++                              union power_supply_propval *val)
++{
++      if (psp == POWER_SUPPLY_PROP_ONLINE)
++              RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN);
++
++      return 0;
++}
++
++static enum power_supply_property yeeloong_ac_props[] = {
++      POWER_SUPPLY_PROP_ONLINE,
++};
++
++static struct power_supply_desc yeeloong_ac_desc = {
++      .name = "yeeloong-ac",
++      .type = POWER_SUPPLY_TYPE_MAINS,
++      .properties = yeeloong_ac_props,
++      .num_properties = ARRAY_SIZE(yeeloong_ac_props),
++      .get_property = yeeloong_get_ac_props,
++};
++
++static inline bool is_bat_in(void)
++{
++      return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN);
++}
++
++static int get_bat_temp(void)
++{
++      return get_bat_l(TEMPERATURE) * 10;
++}
++
++static int get_bat_current(void)
++{
++      return -(s16)get_bat_l(CURRENT);
++}
++
++static int get_bat_voltage(void)
++{
++      return get_bat_l(VOLTAGE);
++}
++
++static char *get_manufacturer(void)
++{
++      return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO";
++}
++
++static int get_relative_cap(void)
++{
++      /*
++       * When the relative capacity becomes 2, the hardware is observed to
++       * have been turned off forcely. so, we must tune it be suitable to
++       * make the software do related actions.
++       */
++      int tmp = get_bat_l(RELATIVE_CAP);
++
++      if (tmp <= (BAT_CAP_CRITICAL * 2))
++              tmp -= 3;
++
++      return tmp;
++}
++
++static int yeeloong_get_bat_props(struct power_supply *psy,
++                                   enum power_supply_property psp,
++                                   union power_supply_propval *val)
++{
++      switch (psp) {
++      /* Fixed information */
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++              /* mV -> µV */
++              RET = get_bat_l(DESIGN_VOL) * 1000;
++              break;
++      case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
++              /* mAh->µAh */
++              RET = get_bat_l(DESIGN_CAP) * 1000;
++              break;
++      case POWER_SUPPLY_PROP_CHARGE_FULL:
++              /* µAh */
++              RET = get_bat_l(FULLCHG_CAP) * 1000;
++              break;
++      case POWER_SUPPLY_PROP_MANUFACTURER:
++              val->strval = get_manufacturer();
++              break;
++      /* Dynamic information */
++      case POWER_SUPPLY_PROP_PRESENT:
++              RET = is_bat_in();
++              break;
++      case POWER_SUPPLY_PROP_CURRENT_NOW:
++              /* mA -> µA */
++              RET = is_bat_in() ? get_bat_current() * 1000 : 0;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++              /* mV -> µV */
++              RET = is_bat_in() ? get_bat_voltage() * 1000 : 0;
++              break;
++      case POWER_SUPPLY_PROP_TEMP:
++              /* Celcius */
++              RET = is_bat_in() ? get_bat_temp() : 0;
++              break;
++      case POWER_SUPPLY_PROP_CAPACITY:
++              RET = is_bat_in() ? get_relative_cap() : 0;
++              break;
++      case POWER_SUPPLY_PROP_CAPACITY_LEVEL: {
++              int status;
++
++              if (!is_bat_in()) {
++                      RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
++                      break;
++              }
++
++              status = get_bat(STATUS);
++              RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
++
++              if (unlikely(status & BIT_BAT_STATUS_DESTROY)) {
++                      RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
++                      break;
++              }
++
++              if (status & BIT_BAT_STATUS_FULL)
++                      RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
++              else {
++                      int curr_cap = get_relative_cap();
++
++                      if (status & BIT_BAT_STATUS_LOW) {
++                              RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
++                              if (curr_cap <= BAT_CAP_CRITICAL)
++                                      RET = 
POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
++                      } else if (curr_cap >= BAT_CAP_HIGH)
++                              RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
++              }
++      } break;
++      case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
++              /* seconds */
++              RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0;
++              break;
++      case POWER_SUPPLY_PROP_STATUS: {
++                      int charge = get_bat(CHARGE);
++
++                      RET = POWER_SUPPLY_STATUS_UNKNOWN;
++                      if (charge & FLAG_BAT_CHARGE_DISCHARGE)
++                              RET = POWER_SUPPLY_STATUS_DISCHARGING;
++                      else if (charge & FLAG_BAT_CHARGE_CHARGE)
++                              RET = POWER_SUPPLY_STATUS_CHARGING;
++      } break;
++      case POWER_SUPPLY_PROP_HEALTH: {
++                      int status;
++
++                      if (!is_bat_in()) {
++                              RET = POWER_SUPPLY_HEALTH_UNKNOWN;
++                              break;
++                      }
++
++                      status = get_bat(STATUS);
++                      RET = POWER_SUPPLY_HEALTH_GOOD;
++
++                      if (status & (BIT_BAT_STATUS_DESTROY |
++                                              BIT_BAT_STATUS_LOW))
++                              RET = POWER_SUPPLY_HEALTH_DEAD;
++                      if (get_bat(CHARGE_STATUS) &
++                                      BIT_BAT_CHARGE_STATUS_OVERTEMP)
++                              RET = POWER_SUPPLY_HEALTH_OVERHEAT;
++      } break;
++      case POWER_SUPPLY_PROP_CHARGE_NOW:      /* 1/100(%)*1000 µAh */
++              RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10;
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++#undef RET
++
++static enum power_supply_property yeeloong_bat_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_PRESENT,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
++      POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
++      POWER_SUPPLY_PROP_CHARGE_FULL,
++      POWER_SUPPLY_PROP_CHARGE_NOW,
++      POWER_SUPPLY_PROP_CURRENT_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_HEALTH,
++      POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
++      POWER_SUPPLY_PROP_CAPACITY,
++      POWER_SUPPLY_PROP_CAPACITY_LEVEL,
++      POWER_SUPPLY_PROP_TEMP,
++      POWER_SUPPLY_PROP_MANUFACTURER,
++};
++
++static struct power_supply_desc yeeloong_bat_desc = {
++      .name = "yeeloong-bat",
++      .type = POWER_SUPPLY_TYPE_BATTERY,
++      .properties = yeeloong_bat_props,
++      .num_properties = ARRAY_SIZE(yeeloong_bat_props),
++      .get_property = yeeloong_get_bat_props,
++};
++
++static struct power_supply *yeeloong_ac, *yeeloong_bat;
++
++static int yeeloong_bat_init(void)
++{
++      struct power_supply *ac, *bat;
++
++      ac = power_supply_register(NULL, &yeeloong_ac_desc, NULL);
++      if (IS_ERR(ac))
++              return PTR_ERR(ac);
++      
++      bat = power_supply_register(NULL, &yeeloong_bat_desc, NULL);
++      if (IS_ERR(bat)) {
++              power_supply_unregister(ac);
++              return PTR_ERR(bat);
++      }
++
++      yeeloong_ac = ac;
++      yeeloong_bat = bat;
++
++      return 0;
++}
++
++static void yeeloong_bat_exit(void)
++{
++      struct power_supply *temp;
++
++      temp = yeeloong_ac;
++      yeeloong_ac = NULL;
++      power_supply_unregister(temp);
++
++      temp = yeeloong_bat;
++      yeeloong_bat = NULL;
++      power_supply_unregister(temp);
++}
++/* hwmon subdriver */
++
++#define MIN_FAN_SPEED 0
++#define MAX_FAN_SPEED 3
++
++#define get_fan(type) \
++      ec_read(REG_FAN_##type)
++
++#define set_fan(type, val) \
++      ec_write(REG_FAN_##type, val)
++
++static inline int get_fan_speed_level(void)
++{
++      return get_fan(SPEED_LEVEL);
++}
++static inline void set_fan_speed_level(int speed)
++{
++      set_fan(SPEED_LEVEL, speed);
++}
++
++static inline int get_fan_mode(void)
++{
++      return get_fan(AUTO_MAN_SWITCH);
++}
++static inline void set_fan_mode(int mode)
++{
++      set_fan(AUTO_MAN_SWITCH, mode);
++}
++
++/*
++ * 3 different modes: Full speed(0); manual mode(1); auto mode(2)
++ */
++static int get_fan_pwm_enable(void)
++{
++      return (get_fan_mode() == BIT_FAN_AUTO) ? 2 :
++              (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1;
++}
++
++static void set_fan_pwm_enable(int mode)
++{
++      set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL);
++      if (mode == 0)
++              set_fan_speed_level(MAX_FAN_SPEED);
++}
++
++static int get_fan_pwm(void)
++{
++      return get_fan_speed_level();
++}
++
++static void set_fan_pwm(int value)
++{
++      if (get_fan_mode() != BIT_FAN_MANUAL)
++              return;
++
++      value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED);
++
++      /* We must ensure the fan is on */
++      if (value > 0)
++              set_fan(CONTROL, ON);
++
++      set_fan_speed_level(value);
++}
++
++static inline int get_fan_speed(void)
++{
++      return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW);
++}
++
++static int get_fan_rpm(void)
++{
++      return FAN_SPEED_DIVIDER / get_fan_speed();
++}
++
++static int get_cpu_temp(void)
++{
++      return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000;
++}
++
++static int get_cpu_temp_max(void)
++{
++      return 60 * 1000;
++}
++
++static int get_bat_temp_alarm(void)
++{
++      return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP);
++}
++
++static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t 
count)
++{
++      int ret;
++      unsigned long value;
++
++      if (!count)
++              return 0;
++
++      ret = kstrtoul(buf, 10, &value);
++      if (ret)
++              return ret;
++
++      set(value);
++
++      return count;
++}
++
++static ssize_t show_sys_hwmon(int (*get) (void), char *buf)
++{
++      return sprintf(buf, "%d\n", get());
++}
++
++#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get)          \
++      static ssize_t show_##_name(struct device *dev,                 \
++                                  struct device_attribute *attr,      \
++                                  char *buf)                          \
++      {                                                               \
++              return show_sys_hwmon(_set, buf);                       \
++      }                                                               \
++      static ssize_t store_##_name(struct device *dev,                \
++                                   struct device_attribute *attr,     \
++                                   const char *buf, size_t count)     \
++      {                                                               \
++              return store_sys_hwmon(_get, buf, count);               \
++      }                                                               \
++      static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
++
++CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
++CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm);
++CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable,
++              set_fan_pwm_enable);
++CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL);
++CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL);
++CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL);
++CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL);
++CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL);
++CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL);
++
++static ssize_t
++show_name(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      return sprintf(buf, "yeeloong\n");
++}
++
++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
++
++static struct attribute *hwmon_attributes[] = {
++      &sensor_dev_attr_pwm1.dev_attr.attr,
++      &sensor_dev_attr_pwm1_enable.dev_attr.attr,
++      &sensor_dev_attr_fan1_input.dev_attr.attr,
++      &sensor_dev_attr_temp1_input.dev_attr.attr,
++      &sensor_dev_attr_temp1_max.dev_attr.attr,
++      &sensor_dev_attr_temp2_input.dev_attr.attr,
++      &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
++      &sensor_dev_attr_curr1_input.dev_attr.attr,
++      &sensor_dev_attr_in1_input.dev_attr.attr,
++      &sensor_dev_attr_name.dev_attr.attr,
++      NULL
++};
++
++static struct attribute_group hwmon_attribute_group = {
++      .attrs = hwmon_attributes
++};
++
++static struct device *yeeloong_hwmon_dev;
++
++static int yeeloong_hwmon_init(void)
++{
++      int ret;
++
++      yeeloong_hwmon_dev = hwmon_device_register(NULL);
++      if (IS_ERR(yeeloong_hwmon_dev)) {
++              yeeloong_hwmon_dev = NULL;
++              return PTR_ERR(yeeloong_hwmon_dev);
++      }
++      ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj,
++                               &hwmon_attribute_group);
++      if (ret) {
++              hwmon_device_unregister(yeeloong_hwmon_dev);
++              yeeloong_hwmon_dev = NULL;
++              return ret;
++      }
++      /* ensure fan is set to auto mode */
++      set_fan_pwm_enable(2);
++
++      return 0;
++}
++
++static void yeeloong_hwmon_exit(void)
++{
++      if (yeeloong_hwmon_dev) {
++              sysfs_remove_group(&yeeloong_hwmon_dev->kobj,
++                                 &hwmon_attribute_group);
++              hwmon_device_unregister(yeeloong_hwmon_dev);
++              yeeloong_hwmon_dev = NULL;
++      }
++}
++
++/* video output subdriver */
++
++#define LCD   0
++#define CRT   1
++#define VOD_NUM       2       /* The total number of video output device*/
++
++static struct output_device *vod[VOD_NUM];
++
++static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT};
++
++static int get_vo_dev(struct output_device *od)
++{
++      int i, dev;
++
++      dev = -1;
++      for (i = 0; i < VOD_NUM; i++)
++              if (od == vod[i])
++                      dev = i;
++
++      return dev;
++}
++
++static int vo_get_status(int dev)
++{
++      return ec_read(vor[dev]);
++}
++
++static int yeeloong_vo_get_status(struct output_device *od)
++{
++      int vd;
++
++      vd = get_vo_dev(od);
++      if (vd != -1)
++              return vo_get_status(vd);
++
++      return -ENODEV;
++}
++
++static void vo_set_state(int dev, int state)
++{
++      int addr;
++      unsigned long value;
++
++      switch (dev) {
++      case LCD:
++              addr = 0x31;
++              break;
++      case CRT:
++              addr = 0x21;
++              break;
++      default:
++              /* return directly if the wrong video output device */
++              return;
++      }
++
++      outb(addr, 0x3c4);
++      value = inb(0x3c5);
++
++      switch (dev) {
++      case LCD:
++              value |= (state ? 0x03 : 0x02);
++              break;
++      case CRT:
++              if (state)
++                      clear_bit(7, &value);
++              else
++                      set_bit(7, &value);
++              break;
++      default:
++              break;
++      }
++
++      outb(addr, 0x3c4);
++      outb(value, 0x3c5);
++
++      if (dev == LCD)
++              ec_write(REG_BACKLIGHT_CTRL, state);
++}
++
++static int yeeloong_vo_set_state(struct output_device *od)
++{
++      int vd;
++
++      vd = get_vo_dev(od);
++      if (vd == -1)
++              return -ENODEV;
++
++      if (vd == CRT && !vo_get_status(vd))
++              return 0;
++
++      vo_set_state(vd, !!od->request_state);
++
++      return 0;
++}
++
++static struct output_properties vop = {
++      .set_state = yeeloong_vo_set_state,
++      .get_status = yeeloong_vo_get_status,
++};
++
++static int yeeloong_vo_init(void)
++{
++      int ret, i;
++      char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
++
++      /* Register video output device: lcd, crt */
++      for (i = 0; i < VOD_NUM; i++) {
++              vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop);
++              if (IS_ERR(vod[i])) {
++                      if (i != 0)
++                              video_output_unregister(vod[i-1]);
++                      ret = PTR_ERR(vod[i]);
++                      vod[i] = NULL;
++                      return ret;
++              }
++      }
++      /* Ensure LCD is on by default */
++      vo_set_state(LCD, ON);
++
++      /*
++       * Turn off CRT by default, and will be enabled when the CRT
++       * connectting event reported by SCI
++       */
++      vo_set_state(CRT, OFF);
++
++      return 0;
++}
++
++static void yeeloong_vo_exit(void)
++{
++      int i;
++
++      for (i = 0; i < VOD_NUM; i++) {
++              if (vod[i]) {
++                      video_output_unregister(vod[i]);
++                      vod[i] = NULL;
++              }
++      }
++}
++
++/* lcd subdriver */
++
++struct lcd_device *lcd[VOD_NUM];
++
++static int get_lcd_dev(struct lcd_device *ld)
++{
++      int i, dev;
++
++      dev = -1;
++      for (i = 0; i < VOD_NUM; i++)
++              if (ld == lcd[i])
++                      dev = i;
++
++      return dev;
++}
++
++static int yeeloong_lcd_set_power(struct lcd_device *ld, int power)
++{
++      int dev = get_lcd_dev(ld);
++
++      if (power == FB_BLANK_UNBLANK)
++              vo_set_state(dev, ON);
++      if (power == FB_BLANK_POWERDOWN)
++              vo_set_state(dev, OFF);
++
++      return 0;
++}
++
++static int yeeloong_lcd_get_power(struct lcd_device *ld)
++{
++      return vo_get_status(get_lcd_dev(ld));
++}
++
++static struct lcd_ops lcd_ops = {
++      .set_power = yeeloong_lcd_set_power,
++      .get_power = yeeloong_lcd_get_power,
++};
++
++static int yeeloong_lcd_init(void)
++{
++      int ret, i;
++      char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
++
++      /* Register video output device: lcd, crt */
++      for (i = 0; i < VOD_NUM; i++) {
++              lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops);
++              if (IS_ERR(lcd[i])) {
++                      if (i != 0)
++                              lcd_device_unregister(lcd[i-1]);
++                      ret = PTR_ERR(lcd[i]);
++                      lcd[i] = NULL;
++                      return ret;
++              }
++      }
++#if 0
++      /* This has been done by the vide output driver */
++
++      /* Ensure LCD is on by default */
++      vo_set_state(LCD, ON);
++
++      /*
++       * Turn off CRT by default, and will be enabled when the CRT
++       * connectting event reported by SCI
++       */
++      vo_set_state(CRT, OFF);
++#endif
++      return 0;
++}
++
++static void yeeloong_lcd_exit(void)
++{
++      int i;
++
++      for (i = 0; i < VOD_NUM; i++) {
++              if (lcd[i]) {
++                      lcd_device_unregister(lcd[i]);
++                      lcd[i] = NULL;
++              }
++      }
++}
++
++/* hotkey subdriver */
++
++static struct input_dev *yeeloong_hotkey_dev;
++
++static atomic_t reboot_flag, sleep_flag;
++#define in_sleep() (&sleep_flag)
++#define in_reboot() (&reboot_flag)
++
++static const struct key_entry yeeloong_keymap[] = {
++      {KE_SW, EVENT_LID, { SW_LID } },
++      {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */
++      {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */
++      {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
++      {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */
++      {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */
++      {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
++      {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */
++      {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + 
down */
++      {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */
++      {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */
++      {KE_END, 0}
++};
++
++static int is_fake_event(u16 keycode)
++{
++      switch (keycode) {
++      case KEY_SLEEP:
++      case SW_LID:
++              return atomic_read(in_sleep()) | atomic_read(in_reboot());
++              break;
++      default:
++              break;
++      }
++      return 0;
++}
++
++static struct key_entry *get_event_key_entry(int event, int status)
++{
++      struct key_entry *ke;
++      static int old_brightness_status = -1;
++      static int old_volume_status = -1;
++
++      ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event);
++      if (!ke)
++              return NULL;
++
++      switch (event) {
++      case EVENT_DISPLAY_BRIGHTNESS:
++              /* current status > old one, means up */
++              if ((status < old_brightness_status) || (0 == status))
++                      ke++;
++              old_brightness_status = status;
++              break;
++      case EVENT_AUDIO_VOLUME:
++              if ((status < old_volume_status) || (0 == status))
++                      ke++;
++              old_volume_status = status;
++              break;
++      default:
++              break;
++      }
++
++      return ke;
++}
++
++static int report_lid_switch(int status)
++{
++      static int old_status;
++
++      /*
++       * LID is a switch button, so, two continuous same status should be
++       * ignored
++       */
++      if (old_status != status) {
++              input_report_switch(yeeloong_hotkey_dev, SW_LID, !status);
++              input_sync(yeeloong_hotkey_dev);
++      }
++      old_status = status;
++
++      return status;
++}
++
++static int crt_detect_handler(int status)
++{
++      /*
++       * When CRT is inserted, enable its output and disable the LCD output,
++       * otherwise, do reversely.
++       */
++      vo_set_state(CRT, status);
++      vo_set_state(LCD, !status);
++
++      return status;
++}
++
++static int displaytoggle_handler(int status)
++{
++      /* EC(>=PQ1D26) does this job for us, we can not do it again,
++       * otherwise, the brightness will not resume to the normal level! */
++      if (ec_version_before("EC_VER=PQ1D26"))
++              vo_set_state(LCD, status);
++
++      return status;
++}
++
++static int mypow(int x, int y)
++{
++      int i, j = x;
++
++      for (i = 1; i < y; i++)
++              j *= j;
++
++      return j;
++}
++
++static int switchvideomode_handler(int status)
++{
++      /* Default status: CRT|LCD = 0|1 = 1 */
++      static int bin_state = 1;
++      int i;
++
++      /*
++       * Only enable switch video output button
++       * when CRT is connected
++       */
++      if (!vo_get_status(CRT))
++              return 0;
++      /*
++       * 2. no CRT connected: LCD on, CRT off
++       * 3. BOTH on
++       * 0. BOTH off
++       * 1. LCD off, CRT on
++       */
++
++      bin_state++;
++      if (bin_state > mypow(2, VOD_NUM) - 1)
++              bin_state = 0;
++      
++      for (i = 0; i < VOD_NUM; i++)
++              vo_set_state(i, bin_state & (1 << i));
++
++      return bin_state;
++}
++
++static int camera_handler(int status)
++{
++      int value;
++
++      value = ec_read(REG_CAMERA_CONTROL);
++      ec_write(REG_CAMERA_CONTROL, value | (1 << 1));
++
++      return status;
++}
++
++static int usb2_handler(int status)
++{
++      pr_emerg("USB2 Over Current occurred\n");
++
++      return status;
++}
++
++static int usb0_handler(int status)
++{
++      pr_emerg("USB0 Over Current occurred\n");
++
++      return status;
++}
++
++static int ac_bat_handler(int status)
++{
++      if (yeeloong_ac)
++              power_supply_changed(yeeloong_ac);
++      if (yeeloong_bat)
++              power_supply_changed(yeeloong_bat);
++
++      return status;
++}
++
++struct sci_event {
++      int reg;
++      sci_handler handler;
++};
++
++static const struct sci_event se[] = {
++      [EVENT_AC_BAT] = {0, ac_bat_handler},
++      [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL},
++      [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL},
++      [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler},
++      [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler},
++      [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler},
++      [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL},
++      [EVENT_LID] = {REG_LID_DETECT, NULL},
++      [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler},
++      [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler},
++      [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler},
++      [EVENT_WLAN] = {REG_WLAN, NULL},
++};
++
++static void do_event_action(int event)
++{
++      int status = -1;
++      struct key_entry *ke;
++      struct sci_event *sep;
++
++      sep = (struct sci_event *)&se[event];
++
++      if (sep->reg != 0)
++              status = ec_read(sep->reg);
++
++      if (status == -1) {
++              /* ec_read hasn't been called, status is invalid */
++              return;
++      }
++
++      if (sep->handler != NULL)
++              status = sep->handler(status);
++
++      pr_debug("%s: event: %d status: %d\n", __func__, event, status);
++
++      /* Report current key to user-space */
++      ke = get_event_key_entry(event, status);
++
++      /*
++       * Ignore the LID and SLEEP event when we are already in sleep or
++       * reboot state, this will avoid the recursive pm operations. but note:
++       * the report_lid_switch() called in arch/mips/loongson64/lemote-2f/pm.c
++       * is necessary, because it is used to wake the system from sleep
++       * state. In the future, perhaps SW_LID should works like SLEEP, no
++       * need to function as a SWITCH, just report the state when the LID is
++       * closed is enough, this event can tell the software to "SLEEP", no
++       * need to tell the softwares when we are resuming from "SLEEP".
++       */
++      if (ke && !is_fake_event(ke->keycode)) {
++              if (ke->keycode == SW_LID)
++                      report_lid_switch(status);
++              else
++                      sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1,
++                                      true);
++      }
++}
++
++/*
++ * SCI(system control interrupt) main interrupt routine
++ *
++ * We will do the query and get event number together so the interrupt routine
++ * should be longer than 120us now at least 3ms elpase for it.
++ */
++static irqreturn_t sci_irq_handler(int irq, void *dev_id)
++{
++      int ret, event;
++
++      if (SCI_IRQ_NUM != irq)
++              return IRQ_NONE;
++
++      /* Query the event number */
++      ret = ec_query_event_num();
++      if (ret < 0)
++              return IRQ_NONE;
++
++      event = ec_get_event_num();
++      if (event < EVENT_START || event > EVENT_END)
++              return IRQ_NONE;
++
++      /* Execute corresponding actions */
++      do_event_action(event);
++
++      return IRQ_HANDLED;
++}
++
++/*
++ * Config and init some msr and gpio register properly.
++ */
++static int sci_irq_init(void)
++{
++      u32 hi, lo;
++      u32 gpio_base;
++      unsigned long flags;
++      int ret;
++
++      /* Get gpio base */
++      _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
++      gpio_base = lo & 0xff00;
++
++      /* Filter the former kb3310 interrupt for security */
++      ret = ec_query_event_num();
++      if (ret)
++              return ret;
++
++      /* For filtering next number interrupt */
++      udelay(10000);
++
++      /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN
++       * gpio :
++       *      input, pull-up, no-invert, event-count and value 0,
++       *      no-filter, no edge mode
++       *      gpio27 map to Virtual gpio0
++       * msr :
++       *      no primary and lpc
++       *      Unrestricted Z input to IG10 from Virtual gpio 0.
++       */
++      local_irq_save(flags);
++      _rdmsr(0x80000024, &hi, &lo);
++      lo &= ~(1 << 10);
++      _wrmsr(0x80000024, hi, lo);
++      _rdmsr(0x80000025, &hi, &lo);
++      lo &= ~(1 << 10);
++      _wrmsr(0x80000025, hi, lo);
++      _rdmsr(0x80000023, &hi, &lo);
++      lo |= (0x0a << 0);
++      _wrmsr(0x80000023, hi, lo);
++      local_irq_restore(flags);
++
++      /* Set gpio27 as sci interrupt
++       *
++       * input, pull-up, no-fliter, no-negedge, invert
++       * the sci event is just about 120us
++       */
++      asm(".set noreorder\n");
++      /*  input enable */
++      outl(0x00000800, (gpio_base | 0xA0));
++      /*  revert the input */
++      outl(0x00000800, (gpio_base | 0xA4));
++      /*  event-int enable */
++      outl(0x00000800, (gpio_base | 0xB8));
++      asm(".set reorder\n");
++
++      return 0;
++}
++
++static int notify_reboot(struct notifier_block *nb, unsigned long event, void 
*buf)
++{
++      switch (event) {
++      case SYS_RESTART:
++      case SYS_HALT:
++      case SYS_POWER_OFF:
++              atomic_set(in_reboot(), 1);
++              break;
++      default:
++              return NOTIFY_DONE;
++      }
++
++      return NOTIFY_OK;
++}
++
++static int notify_pm(struct notifier_block *nb, unsigned long event, void 
*buf)
++{
++      switch (event) {
++      case PM_HIBERNATION_PREPARE:
++      case PM_SUSPEND_PREPARE:
++              atomic_inc(in_sleep());
++              break;
++      case PM_POST_HIBERNATION:
++      case PM_POST_SUSPEND:
++      case PM_RESTORE_PREPARE:        /* do we need this ?? */
++              atomic_dec(in_sleep());
++              break;
++      default:
++              return NOTIFY_DONE;
++      }
++
++      pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event,
++                      atomic_read(in_sleep()));
++
++      return NOTIFY_OK;
++}
++
++static struct notifier_block reboot_notifier = {
++      .notifier_call = notify_reboot,
++};
++
++static struct notifier_block pm_notifier = {
++      .notifier_call = notify_pm,
++};
++
++static int yeeloong_hotkey_init(void)
++{
++      int ret = 0;
++
++      ret = register_reboot_notifier(&reboot_notifier);
++      if (ret) {
++              pr_err("Can't register reboot notifier\n");
++              goto end;
++      }
++
++      ret = register_pm_notifier(&pm_notifier);
++      if (ret) {
++              pr_err("Can't register pm notifier\n");
++              goto free_reboot_notifier;
++      }
++
++      ret = sci_irq_init();
++      if (ret) {
++              pr_err("Can't init SCI interrupt\n");
++              goto free_pm_notifier;
++      }
++
++      ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler,
++                      IRQF_ONESHOT, "sci", NULL);
++      if (ret) {
++              pr_err("Can't thread SCI interrupt handler\n");
++              goto free_pm_notifier;
++      }
++
++      yeeloong_hotkey_dev = input_allocate_device();
++
++      if (!yeeloong_hotkey_dev) {
++              ret = -ENOMEM;
++              goto free_irq;
++      }
++
++      yeeloong_hotkey_dev->name = "HotKeys";
++      yeeloong_hotkey_dev->phys = "button/input0";
++      yeeloong_hotkey_dev->id.bustype = BUS_HOST;
++      yeeloong_hotkey_dev->dev.parent = NULL;
++
++      ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL);
++      if (ret) {
++              pr_err("Failed to setup input device keymap\n");
++              goto free_dev;
++      }
++
++      ret = input_register_device(yeeloong_hotkey_dev);
++      if (ret)
++              goto free_keymap;
++
++      /* Update the current status of LID */
++      report_lid_switch(ON);
++
++#ifdef CONFIG_LOONGSON_SUSPEND
++      /* Install the real yeeloong_report_lid_status for pm.c */
++      yeeloong_report_lid_status = report_lid_switch;
++#endif
++      return 0;
++
++free_keymap:
++      sparse_keymap_free(yeeloong_hotkey_dev);
++free_dev:
++      input_free_device(yeeloong_hotkey_dev);
++free_irq:
++      free_irq(SCI_IRQ_NUM, NULL);
++free_pm_notifier:
++      unregister_pm_notifier(&pm_notifier);
++free_reboot_notifier:
++      unregister_reboot_notifier(&reboot_notifier);
++end:
++      return ret;
++}
++
++static void yeeloong_hotkey_exit(void)
++{
++      /* Free irq */
++      free_irq(SCI_IRQ_NUM, NULL);
++
++#ifdef CONFIG_LOONGSON_SUSPEND
++      /* Uninstall yeeloong_report_lid_status for pm.c */
++      if (yeeloong_report_lid_status == report_lid_switch)
++              yeeloong_report_lid_status = NULL;
++#endif
++
++      if (yeeloong_hotkey_dev) {
++              sparse_keymap_free(yeeloong_hotkey_dev);
++              input_unregister_device(yeeloong_hotkey_dev);
++              yeeloong_hotkey_dev = NULL;
++      }
++}
++
++#ifdef CONFIG_PM
++static void usb_ports_set(int status)
++{
++      status = !!status;
++
++      ec_write(REG_USB0_FLAG, status);
++      ec_write(REG_USB1_FLAG, status);
++      ec_write(REG_USB2_FLAG, status);
++}
++
++static int yeeloong_suspend(struct device *dev)
++
++{
++      if (ec_version_before("EC_VER=PQ1D27"))
++              vo_set_state(LCD, OFF);
++      vo_set_state(CRT, OFF);
++      usb_ports_set(OFF);
++
++      return 0;
++}
++
++static int yeeloong_resume(struct device *dev)
++{
++      int ret;
++
++      if (ec_version_before("EC_VER=PQ1D27"))
++              vo_set_state(LCD, ON);
++      vo_set_state(CRT, ON);
++      usb_ports_set(ON);
++
++      ret = sci_irq_init();
++      if (ret)
++              return -EFAULT;
++
++      return 0;
++}
++
++static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend,
++      yeeloong_resume);
++#endif
++
++static struct platform_device_id platform_device_ids[] = {
++      {
++              .name = "yeeloong_laptop",
++      },
++      {}
++};
++
++MODULE_DEVICE_TABLE(platform, platform_device_ids);
++
++static struct platform_driver platform_driver = {
++      .driver = {
++              .name = "yeeloong_laptop",
++              .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++              .pm = &yeeloong_pm_ops,
++#endif
++      },
++      .id_table = platform_device_ids,
++};
++
++static int __init yeeloong_init(void)
++{
++      int ret;
++
++      pr_info("YeeLoong Laptop platform specific driver loaded.\n");
++
++      /* Register platform stuff */
++      ret = platform_driver_register(&platform_driver);
++      if (ret) {
++              pr_err("Failed to register YeeLoong platform driver.\n");
++              return ret;
++      }
++
++#define yeeloong_init_drv(drv, alias) do {                    \
++      pr_info("Registered YeeLoong " alias " driver.\n");     \
++      ret = yeeloong_ ## drv ## _init();                      \
++      if (ret) {                                              \
++              pr_err("Failed to register YeeLoong " alias " driver.\n");      
\
++              yeeloong_ ## drv ## _exit();                    \
++              return ret;                                     \
++      }                                                       \
++} while (0)
++
++      yeeloong_init_drv(backlight, "backlight");
++      yeeloong_init_drv(bat, "battery and AC");
++      yeeloong_init_drv(hwmon, "hardware monitor");
++      yeeloong_init_drv(vo, "video output");
++      yeeloong_init_drv(lcd, "lcd output");
++      yeeloong_init_drv(hotkey, "hotkey input");
++
++      return 0;
++}
++
++static void __exit yeeloong_exit(void)
++{
++      yeeloong_hotkey_exit();
++      yeeloong_lcd_exit();
++      yeeloong_vo_exit();
++      yeeloong_hwmon_exit();
++      yeeloong_bat_exit();
++      yeeloong_backlight_exit();
++      platform_driver_unregister(&platform_driver);
++
++      pr_info("YeeLoong platform specific driver unloaded.\n");
++}
++
++module_init(yeeloong_init);
++module_exit(yeeloong_exit);
++
++MODULE_AUTHOR("Wu Zhangjin <address@hidden>; Liu Junliang <address@hidden>");
++MODULE_DESCRIPTION("YeeLoong laptop driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 8bf495f..f6a15b6 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -36,6 +36,12 @@ config VGASTATE
+        tristate
+        default n
+ 
++config VIDEO_OUTPUT_CONTROL
++      tristate "Lowlevel video output switch controls"
++      help
++        This framework adds support for low-level control of the video 
++        output switch.
++
+ config VIDEOMODE_HELPERS
+       bool
+ 
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 9ad3c17..3d869d9 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -7,6 +7,8 @@ obj-y                            += backlight/
+ 
+ obj-y                           += fbdev/
+ 
++#video output switch sysfs driver
++obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
+ ifeq ($(CONFIG_OF),y)
+ obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
+diff --git a/drivers/video/output.c b/drivers/video/output.c
+new file mode 100644
+index 0000000..1446c49
+--- /dev/null
++++ b/drivers/video/output.c
+@@ -0,0 +1,133 @@
++/*
++ *  output.c - Display Output Switch driver
++ *
++ *  Copyright (C) 2006 Luming Yu <address@hidden>
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *  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.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++#include <linux/module.h>
++#include <linux/video_output.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/ctype.h>
++
++
++MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Luming Yu <address@hidden>");
++
++static ssize_t state_show(struct device *dev, struct device_attribute *attr,
++                        char *buf)
++{
++      ssize_t ret_size = 0;
++      struct output_device *od = to_output_device(dev);
++      if (od->props)
++              ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
++      return ret_size;
++}
++
++static ssize_t state_store(struct device *dev, struct device_attribute *attr,
++                         const char *buf,size_t count)
++{
++      char *endp;
++      struct output_device *od = to_output_device(dev);
++      int request_state = simple_strtoul(buf,&endp,0);
++      size_t size = endp - buf;
++
++      if (isspace(*endp))
++              size++;
++      if (size != count)
++              return -EINVAL;
++
++      if (od->props) {
++              od->request_state = request_state;
++              od->props->set_state(od);
++      }
++      return count;
++}
++static DEVICE_ATTR_RW(state);
++
++static void video_output_release(struct device *dev)
++{
++      struct output_device *od = to_output_device(dev);
++      kfree(od);
++}
++
++static struct attribute *video_output_attrs[] = {
++      &dev_attr_state.attr,
++      NULL,
++};
++ATTRIBUTE_GROUPS(video_output);
++
++static struct class video_output_class = {
++      .name = "video_output",
++      .dev_release = video_output_release,
++      .dev_groups = video_output_groups,
++};
++
++struct output_device *video_output_register(const char *name,
++      struct device *dev,
++      void *devdata,
++      struct output_properties *op)
++{
++      struct output_device *new_dev;
++      int ret_code = 0;
++
++      new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
++      if (!new_dev) {
++              ret_code = -ENOMEM;
++              goto error_return;
++      }
++      new_dev->props = op;
++      new_dev->dev.class = &video_output_class;
++      new_dev->dev.parent = dev;
++      dev_set_name(&new_dev->dev, "%s", name);
++      dev_set_drvdata(&new_dev->dev, devdata);
++      ret_code = device_register(&new_dev->dev);
++      if (ret_code) {
++              kfree(new_dev);
++              goto error_return;
++      }
++      return new_dev;
++
++error_return:
++      return ERR_PTR(ret_code);
++}
++EXPORT_SYMBOL(video_output_register);
++
++void video_output_unregister(struct output_device *dev)
++{
++      if (!dev)
++              return;
++      device_unregister(&dev->dev);
++}
++EXPORT_SYMBOL(video_output_unregister);
++
++static void __exit video_output_class_exit(void)
++{
++      class_unregister(&video_output_class);
++}
++
++static int __init video_output_class_init(void)
++{
++      return class_register(&video_output_class);
++}
++
++postcore_initcall(video_output_class_init);
++module_exit(video_output_class_exit);
+diff --git a/include/linux/video_output.h b/include/linux/video_output.h
+new file mode 100644
+index 0000000..ed5cdeb
+--- /dev/null
++++ b/include/linux/video_output.h
+@@ -0,0 +1,57 @@
++/*
++ *
++ *  Copyright (C) 2006 Luming Yu <address@hidden>
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *  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.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++#ifndef _LINUX_VIDEO_OUTPUT_H
++#define _LINUX_VIDEO_OUTPUT_H
++#include <linux/device.h>
++#include <linux/err.h>
++struct output_device;
++struct output_properties {
++      int (*set_state)(struct output_device *);
++      int (*get_status)(struct output_device *);
++};
++struct output_device {
++      int request_state;
++      struct output_properties *props;
++      struct device dev;
++};
++#define to_output_device(obj) container_of(obj, struct output_device, dev)
++#if   defined(CONFIG_VIDEO_OUTPUT_CONTROL) || 
defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE)
++struct output_device *video_output_register(const char *name,
++      struct device *dev,
++      void *devdata,
++      struct output_properties *op);
++void video_output_unregister(struct output_device *dev);
++#else
++static struct output_device *video_output_register(const char *name,
++        struct device *dev,
++        void *devdata,
++        struct output_properties *op)
++{
++      return ERR_PTR(-ENODEV);
++}
++static void video_output_unregister(struct output_device *dev)
++{
++      return;
++}
++#endif
++#endif
+-- 
+2.4.3
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]