From 54f11edb92dc05fd8cd187467bfffc069349a52d Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 23 Jul 2009 16:15:58 +0200 Subject: update to latest 2.1 rc --- package/openvpn/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/openvpn/Makefile b/package/openvpn/Makefile index c88869999..93482c9e9 100644 --- a/package/openvpn/Makefile +++ b/package/openvpn/Makefile @@ -4,9 +4,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:= openvpn -PKG_VERSION:= 2.0.9 -PKG_RELEASE:= 7 -PKG_MD5SUM:= 60745008b90b7dbe25fe8337c550fec6 +PKG_VERSION:= 2.1_rc19 +PKG_RELEASE:= 1 +PKG_MD5SUM:= ba2ee667a8b7606b125b7d32f47ca578 PKG_DESCR:= Open Source VPN solution using SSL PKG_SECTION:= net PKG_DEPENDS:= kmod-tun -- cgit v1.2.3 From eb567614643eb1d3cacdbe8ad7ed86ebb43467cb Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 23 Jul 2009 16:17:45 +0200 Subject: update to 2.6.30.1 --- target/rb532/device.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/rb532/device.mk b/target/rb532/device.mk index 926e4b9c6..6f5553ffa 100644 --- a/target/rb532/device.mk +++ b/target/rb532/device.mk @@ -1,7 +1,7 @@ ARCH:= mips CPU_ARCH:= mipsel -KERNEL_VERSION:= 2.6.30 +KERNEL_VERSION:= 2.6.30.1 KERNEL_RELEASE:= 1 -KERNEL_MD5SUM:= 7a80058a6382e5108cdb5554d1609615 +KERNEL_MD5SUM:= 7da2e2e31f1c00f2673d2dc50de76b33 TARGET_OPTIMIZATION:= -O2 -pipe TARGET_CFLAGS_ARCH:= -march=mips32 -- cgit v1.2.3 From ef487ad89a9cc183ff23d28fc99c26af695c6a18 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 23 Jul 2009 16:18:20 +0200 Subject: add 2.6.30.1 patches --- target/linux/config/Config.in.kernel | 12 + target/linux/patches/2.6.30.1/cygwin-compat.patch | 66 + target/linux/patches/2.6.30.1/freebsd-compat.patch | 11 + target/linux/patches/2.6.30.1/mips-delay-fix.patch | 27 + target/linux/patches/2.6.30.1/mtd-root.patch | 62 + target/linux/patches/2.6.30.1/ocf.patch | 23653 +++++++++++++++++++ target/linux/patches/2.6.30.1/swconfig.patch | 1075 + target/linux/patches/2.6.30.1/yaffs2.patch | 15066 ++++++++++++ 8 files changed, 39972 insertions(+) create mode 100644 target/linux/patches/2.6.30.1/cygwin-compat.patch create mode 100644 target/linux/patches/2.6.30.1/freebsd-compat.patch create mode 100644 target/linux/patches/2.6.30.1/mips-delay-fix.patch create mode 100644 target/linux/patches/2.6.30.1/mtd-root.patch create mode 100644 target/linux/patches/2.6.30.1/ocf.patch create mode 100644 target/linux/patches/2.6.30.1/swconfig.patch create mode 100644 target/linux/patches/2.6.30.1/yaffs2.patch diff --git a/target/linux/config/Config.in.kernel b/target/linux/config/Config.in.kernel index 6b34b2448..659e7e052 100644 --- a/target/linux/config/Config.in.kernel +++ b/target/linux/config/Config.in.kernel @@ -1,3 +1,15 @@ +config ADK_KERNEL_BLK_DEV_INITRD + bool + default n + +config ADK_KERNEL_RD_LZMA + bool + default n + +config ADK_KERNEL_INITRAMFS_SOURCE + string + default "" + config ADK_KERNEL_ETRAX_MTD_SIZE hex depends on ADK_LINUX_CRIS_FOXBOARD_CLASSIC || ADK_LINUX_CRIS_FOXBOARD_LX diff --git a/target/linux/patches/2.6.30.1/cygwin-compat.patch b/target/linux/patches/2.6.30.1/cygwin-compat.patch new file mode 100644 index 000000000..8d087dddf --- /dev/null +++ b/target/linux/patches/2.6.30.1/cygwin-compat.patch @@ -0,0 +1,66 @@ +diff -Nur linux-2.6.30.orig/scripts/mod/file2alias.c linux-2.6.30/scripts/mod/file2alias.c +--- linux-2.6.30.orig/scripts/mod/file2alias.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/scripts/mod/file2alias.c 2009-06-11 09:17:10.000000000 +0200 +@@ -29,7 +29,11 @@ + + #include + ++#ifdef __CYGWIN__ ++typedef __uint32_t __u32; ++#else + typedef uint32_t __u32; ++#endif + typedef uint16_t __u16; + typedef unsigned char __u8; + +diff -Nur linux-2.6.30.orig/scripts/mod/modpost.h linux-2.6.30/scripts/mod/modpost.h +--- linux-2.6.30.orig/scripts/mod/modpost.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/scripts/mod/modpost.h 2009-06-11 09:17:10.000000000 +0200 +@@ -9,6 +9,11 @@ + #include + #include + ++#ifdef __CYGWIN__ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++#endif ++ + #include "elfconfig.h" + + #if KERNEL_ELFCLASS == ELFCLASS32 +@@ -19,13 +24,17 @@ + #define Elf_Addr Elf32_Addr + #define Elf_Sword Elf64_Sword + #define Elf_Section Elf32_Half ++#ifndef __CYGWIN__ + #define ELF_ST_BIND ELF32_ST_BIND + #define ELF_ST_TYPE ELF32_ST_TYPE ++#endif + + #define Elf_Rel Elf32_Rel + #define Elf_Rela Elf32_Rela ++#ifndef __CYGWIN__ + #define ELF_R_SYM ELF32_R_SYM + #define ELF_R_TYPE ELF32_R_TYPE ++#endif + #else + + #define Elf_Ehdr Elf64_Ehdr +@@ -43,6 +52,17 @@ + #define ELF_R_TYPE ELF64_R_TYPE + #endif + ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++ + /* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ + typedef struct + { diff --git a/target/linux/patches/2.6.30.1/freebsd-compat.patch b/target/linux/patches/2.6.30.1/freebsd-compat.patch new file mode 100644 index 000000000..051fdc63e --- /dev/null +++ b/target/linux/patches/2.6.30.1/freebsd-compat.patch @@ -0,0 +1,11 @@ +diff -Nur linux-2.6.30.orig/arch/x86/boot/tools/build.c linux-2.6.30/arch/x86/boot/tools/build.c +--- linux-2.6.30.orig/arch/x86/boot/tools/build.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/arch/x86/boot/tools/build.c 2009-06-11 09:18:50.000000000 +0200 +@@ -29,7 +29,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/patches/2.6.30.1/mips-delay-fix.patch b/target/linux/patches/2.6.30.1/mips-delay-fix.patch new file mode 100644 index 000000000..128ed54ec --- /dev/null +++ b/target/linux/patches/2.6.30.1/mips-delay-fix.patch @@ -0,0 +1,27 @@ +From: Atsushi Nemoto +Subject: [PATCH] fix __ndelay build error and add 'ull' suffix for 32-bit kernel + +Signed-off-by: Atsushi Nemoto +--- + arch/mips/lib/delay.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/mips/lib/delay.c ++++ b/arch/mips/lib/delay.c +@@ -43,7 +43,7 @@ void __udelay(unsigned long us) + { + unsigned int lpj = current_cpu_data.udelay_val; + +- __delay((us * 0x000010c7 * HZ * lpj) >> 32); ++ __delay((us * 0x000010c7ull * HZ * lpj) >> 32); + } + EXPORT_SYMBOL(__udelay); + +@@ -51,6 +51,6 @@ void __ndelay(unsigned long ns) + { + unsigned int lpj = current_cpu_data.udelay_val; + +- __delay((us * 0x00000005 * HZ * lpj) >> 32); ++ __delay((ns * 0x00000005ull * HZ * lpj) >> 32); + } + EXPORT_SYMBOL(__ndelay); diff --git a/target/linux/patches/2.6.30.1/mtd-root.patch b/target/linux/patches/2.6.30.1/mtd-root.patch new file mode 100644 index 000000000..3576848be --- /dev/null +++ b/target/linux/patches/2.6.30.1/mtd-root.patch @@ -0,0 +1,62 @@ +diff -Nur linux-2.6.29.1.orig/drivers/mtd/Kconfig linux-2.6.29.1/drivers/mtd/Kconfig +--- linux-2.6.29.1.orig/drivers/mtd/Kconfig 2009-04-02 22:55:27.000000000 +0200 ++++ linux-2.6.29.1/drivers/mtd/Kconfig 2009-05-02 19:24:14.444062164 +0200 +@@ -53,6 +53,11 @@ + should normally be compiled as kernel modules. The modules perform + various checks and verifications when loaded. + ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ depends on MTD_PARTITIONS ++ default y ++ + config MTD_REDBOOT_PARTS + tristate "RedBoot partition table parsing" + depends on MTD_PARTITIONS +diff -Nur linux-2.6.29.1.orig/drivers/mtd/mtdpart.c linux-2.6.29.1/drivers/mtd/mtdpart.c +--- linux-2.6.29.1.orig/drivers/mtd/mtdpart.c 2009-04-02 22:55:27.000000000 +0200 ++++ linux-2.6.29.1/drivers/mtd/mtdpart.c 2009-05-02 19:26:39.038093851 +0200 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -37,7 +38,7 @@ + * the pointer to that structure with this macro. + */ + #define PART(x) ((struct mtd_part *)(x)) +- ++#define IS_PART(mtd) (mtd->read == part_read) + + /* + * MTD methods which simply translate the effective address and pass through +@@ -502,14 +503,23 @@ + { + struct mtd_part *slave; + uint64_t cur_offset = 0; +- int i; ++ int i, j, ret; + + printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); + +- for (i = 0; i < nbparts; i++) { +- slave = add_one_partition(master, parts + i, i, cur_offset); ++ for (i = 0, j = 0; i < nbparts; i++) { ++ slave = add_one_partition(master, parts + i, j++, cur_offset); + if (!slave) + return -ENOMEM; ++ if (!strcmp(parts[i].name, "rootfs") && slave->registered) { ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (ROOT_DEV == 0) { ++ printk(KERN_NOTICE "mtd: partition \"rootfs\" " ++ "set to be root filesystem\n"); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index); ++ } ++#endif ++ } + cur_offset = slave->offset + slave->mtd.size; + } + diff --git a/target/linux/patches/2.6.30.1/ocf.patch b/target/linux/patches/2.6.30.1/ocf.patch new file mode 100644 index 000000000..64c5eeb0f --- /dev/null +++ b/target/linux/patches/2.6.30.1/ocf.patch @@ -0,0 +1,23653 @@ +diff -Nur linux-2.6.30.orig/crypto/Kconfig linux-2.6.30/crypto/Kconfig +--- linux-2.6.30.orig/crypto/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/crypto/Kconfig 2009-06-11 10:55:27.000000000 +0200 +@@ -781,3 +781,5 @@ + source "drivers/crypto/Kconfig" + + endif # if CRYPTO ++ ++source "crypto/ocf/Kconfig" +diff -Nur linux-2.6.30.orig/crypto/Makefile linux-2.6.30/crypto/Makefile +--- linux-2.6.30.orig/crypto/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/crypto/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -84,6 +84,8 @@ + obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o + obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + ++obj-$(CONFIG_OCF_OCF) += ocf/ ++ + # + # generic algorithms and the async_tx api + # +diff -Nur linux-2.6.30.orig/crypto/ocf/Config.in linux-2.6.30/crypto/ocf/Config.in +--- linux-2.6.30.orig/crypto/ocf/Config.in 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Config.in 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,34 @@ ++############################################################################# ++ ++mainmenu_option next_comment ++comment 'OCF Configuration' ++tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF ++dep_mbool ' enable fips RNG checks (fips check on RNG data before use)' \ ++ CONFIG_OCF_FIPS $CONFIG_OCF_OCF ++dep_mbool ' enable harvesting entropy for /dev/random' \ ++ CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF ++dep_tristate ' cryptodev (user space support)' \ ++ CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF ++dep_tristate ' cryptosoft (software crypto engine)' \ ++ CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF ++dep_tristate ' safenet (HW crypto engine)' \ ++ CONFIG_OCF_SAFE $CONFIG_OCF_OCF ++dep_tristate ' IXP4xx (HW crypto engine)' \ ++ CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF ++dep_mbool ' Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \ ++ CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX ++dep_tristate ' hifn (HW crypto engine)' \ ++ CONFIG_OCF_HIFN $CONFIG_OCF_OCF ++dep_tristate ' talitos (HW crypto engine)' \ ++ CONFIG_OCF_TALITOS $CONFIG_OCF_OCF ++dep_tristate ' pasemi (HW crypto engine)' \ ++ CONFIG_OCF_PASEMI $CONFIG_OCF_OCF ++dep_tristate ' ep80579 (HW crypto engine)' \ ++ CONFIG_OCF_EP80579 $CONFIG_OCF_OCF ++dep_tristate ' ocfnull (does no crypto)' \ ++ CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF ++dep_tristate ' ocf-bench (HW crypto in-kernel benchmark)' \ ++ CONFIG_OCF_BENCH $CONFIG_OCF_OCF ++endmenu ++ ++############################################################################# +diff -Nur linux-2.6.30.orig/crypto/ocf/criov.c linux-2.6.30/crypto/ocf/criov.c +--- linux-2.6.30.orig/crypto/ocf/criov.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/criov.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,215 @@ ++/* $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $ */ ++ ++/* ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 1999 Theo de Raadt ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* ++ * This macro is only for avoiding code duplication, as we need to skip ++ * given number of bytes in the same way in three functions below. ++ */ ++#define CUIO_SKIP() do { \ ++ KASSERT(off >= 0, ("%s: off %d < 0", __func__, off)); \ ++ KASSERT(len >= 0, ("%s: len %d < 0", __func__, len)); \ ++ while (off > 0) { \ ++ KASSERT(iol >= 0, ("%s: empty in skip", __func__)); \ ++ if (off < iov->iov_len) \ ++ break; \ ++ off -= iov->iov_len; \ ++ iol--; \ ++ iov++; \ ++ } \ ++} while (0) ++ ++void ++cuio_copydata(struct uio* uio, int off, int len, caddr_t cp) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ unsigned count; ++ ++ CUIO_SKIP(); ++ while (len > 0) { ++ KASSERT(iol >= 0, ("%s: empty", __func__)); ++ count = min((int)(iov->iov_len - off), len); ++ memcpy(cp, ((caddr_t)iov->iov_base) + off, count); ++ len -= count; ++ cp += count; ++ off = 0; ++ iol--; ++ iov++; ++ } ++} ++ ++void ++cuio_copyback(struct uio* uio, int off, int len, caddr_t cp) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ unsigned count; ++ ++ CUIO_SKIP(); ++ while (len > 0) { ++ KASSERT(iol >= 0, ("%s: empty", __func__)); ++ count = min((int)(iov->iov_len - off), len); ++ memcpy(((caddr_t)iov->iov_base) + off, cp, count); ++ len -= count; ++ cp += count; ++ off = 0; ++ iol--; ++ iov++; ++ } ++} ++ ++/* ++ * Return a pointer to iov/offset of location in iovec list. ++ */ ++struct iovec * ++cuio_getptr(struct uio *uio, int loc, int *off) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ ++ while (loc >= 0) { ++ /* Normal end of search */ ++ if (loc < iov->iov_len) { ++ *off = loc; ++ return (iov); ++ } ++ ++ loc -= iov->iov_len; ++ if (iol == 0) { ++ if (loc == 0) { ++ /* Point at the end of valid data */ ++ *off = iov->iov_len; ++ return (iov); ++ } else ++ return (NULL); ++ } else { ++ iov++, iol--; ++ } ++ } ++ ++ return (NULL); ++} ++ ++EXPORT_SYMBOL(cuio_copyback); ++EXPORT_SYMBOL(cuio_copydata); ++EXPORT_SYMBOL(cuio_getptr); ++ ++ ++static void ++skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len) ++{ ++ int i; ++ if (offset < skb_headlen(skb)) { ++ memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len)); ++ len -= skb_headlen(skb); ++ cp += skb_headlen(skb); ++ } ++ offset -= skb_headlen(skb); ++ for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) { ++ if (offset < skb_shinfo(skb)->frags[i].size) { ++ memcpy(page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ cp, min_t(int, skb_shinfo(skb)->frags[i].size, len)); ++ len -= skb_shinfo(skb)->frags[i].size; ++ cp += skb_shinfo(skb)->frags[i].size; ++ } ++ offset -= skb_shinfo(skb)->frags[i].size; ++ } ++} ++ ++void ++crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in) ++{ ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ skb_copy_bits_back((struct sk_buff *)buf, off, in, size); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ cuio_copyback((struct uio *)buf, off, size, in); ++ else ++ bcopy(in, buf + off, size); ++} ++ ++void ++crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out) ++{ ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ skb_copy_bits((struct sk_buff *)buf, off, out, size); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ cuio_copydata((struct uio *)buf, off, size, out); ++ else ++ bcopy(buf + off, out, size); ++} ++ ++int ++crypto_apply(int flags, caddr_t buf, int off, int len, ++ int (*f)(void *, void *, u_int), void *arg) ++{ ++#if 0 ++ int error; ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ error = XXXXXX((struct mbuf *)buf, off, len, f, arg); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ error = cuio_apply((struct uio *)buf, off, len, f, arg); ++ else ++ error = (*f)(arg, buf + off, len); ++ return (error); ++#else ++ KASSERT(0, ("crypto_apply not implemented!\n")); ++#endif ++ return 0; ++} ++ ++EXPORT_SYMBOL(crypto_copyback); ++EXPORT_SYMBOL(crypto_copydata); ++EXPORT_SYMBOL(crypto_apply); ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/crypto.c linux-2.6.30/crypto/ocf/crypto.c +--- linux-2.6.30.orig/crypto/ocf/crypto.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/crypto.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1741 @@ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * Copyright (c) 2002-2006 Sam Leffler. All rights reserved. ++ * ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $"); ++#endif ++ ++/* ++ * Cryptographic Subsystem. ++ * ++ * This code is derived from the Openbsd Cryptographic Framework (OCF) ++ * that has the copyright shown below. Very little of the original ++ * code remains. ++ */ ++/*- ++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * ++ * This code was written by Angelos D. Keromytis in Athens, Greece, in ++ * February 2000. Network Security Technologies Inc. (NSTI) kindly ++ * supported the development of this code. ++ * ++ * Copyright (c) 2000, 2001 Angelos D. Keromytis ++ * ++ * Permission to use, copy, and modify this software with or without fee ++ * is hereby granted, provided that this entire notice is included in ++ * all source code copies of any software which is or includes a copy or ++ * modification of this software. ++ * ++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY ++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE ++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR ++ * PURPOSE. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $"); ++ */ ++ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * keep track of whether or not we have been initialised, a big ++ * issue if we are linked into the kernel and a driver gets started before ++ * us ++ */ ++static int crypto_initted = 0; ++ ++/* ++ * Crypto drivers register themselves by allocating a slot in the ++ * crypto_drivers table with crypto_get_driverid() and then registering ++ * each algorithm they support with crypto_register() and crypto_kregister(). ++ */ ++ ++/* ++ * lock on driver table ++ * we track its state as spin_is_locked does not do anything on non-SMP boxes ++ */ ++static spinlock_t crypto_drivers_lock; ++static int crypto_drivers_locked; /* for non-SMP boxes */ ++ ++#define CRYPTO_DRIVER_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_drivers_lock, d_flags); \ ++ crypto_drivers_locked = 1; \ ++ dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_DRIVER_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \ ++ crypto_drivers_locked = 0; \ ++ spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \ ++ }) ++#define CRYPTO_DRIVER_ASSERT() \ ++ ({ \ ++ if (!crypto_drivers_locked) { \ ++ dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \ ++ } \ ++ }) ++ ++/* ++ * Crypto device/driver capabilities structure. ++ * ++ * Synchronization: ++ * (d) - protected by CRYPTO_DRIVER_LOCK() ++ * (q) - protected by CRYPTO_Q_LOCK() ++ * Not tagged fields are read-only. ++ */ ++struct cryptocap { ++ device_t cc_dev; /* (d) device/driver */ ++ u_int32_t cc_sessions; /* (d) # of sessions */ ++ u_int32_t cc_koperations; /* (d) # os asym operations */ ++ /* ++ * Largest possible operator length (in bits) for each type of ++ * encryption algorithm. XXX not used ++ */ ++ u_int16_t cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1]; ++ u_int8_t cc_alg[CRYPTO_ALGORITHM_MAX + 1]; ++ u_int8_t cc_kalg[CRK_ALGORITHM_MAX + 1]; ++ ++ int cc_flags; /* (d) flags */ ++#define CRYPTOCAP_F_CLEANUP 0x80000000 /* needs resource cleanup */ ++ int cc_qblocked; /* (q) symmetric q blocked */ ++ int cc_kqblocked; /* (q) asymmetric q blocked */ ++}; ++static struct cryptocap *crypto_drivers = NULL; ++static int crypto_drivers_num = 0; ++ ++/* ++ * There are two queues for crypto requests; one for symmetric (e.g. ++ * cipher) operations and one for asymmetric (e.g. MOD)operations. ++ * A single mutex is used to lock access to both queues. We could ++ * have one per-queue but having one simplifies handling of block/unblock ++ * operations. ++ */ ++static int crp_sleep = 0; ++static LIST_HEAD(crp_q); /* request queues */ ++static LIST_HEAD(crp_kq); ++ ++static spinlock_t crypto_q_lock; ++ ++int crypto_all_qblocked = 0; /* protect with Q_LOCK */ ++module_param(crypto_all_qblocked, int, 0444); ++MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked"); ++ ++int crypto_all_kqblocked = 0; /* protect with Q_LOCK */ ++module_param(crypto_all_kqblocked, int, 0444); ++MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked"); ++ ++#define CRYPTO_Q_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_q_lock, q_flags); \ ++ dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_Q_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \ ++ spin_unlock_irqrestore(&crypto_q_lock, q_flags); \ ++ }) ++ ++/* ++ * There are two queues for processing completed crypto requests; one ++ * for the symmetric and one for the asymmetric ops. We only need one ++ * but have two to avoid type futzing (cryptop vs. cryptkop). A single ++ * mutex is used to lock access to both queues. Note that this lock ++ * must be separate from the lock on request queues to insure driver ++ * callbacks don't generate lock order reversals. ++ */ ++static LIST_HEAD(crp_ret_q); /* callback queues */ ++static LIST_HEAD(crp_ret_kq); ++ ++static spinlock_t crypto_ret_q_lock; ++#define CRYPTO_RETQ_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \ ++ dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_RETQ_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \ ++ spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \ ++ }) ++#define CRYPTO_RETQ_EMPTY() (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq)) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static kmem_cache_t *cryptop_zone; ++static kmem_cache_t *cryptodesc_zone; ++#else ++static struct kmem_cache *cryptop_zone; ++static struct kmem_cache *cryptodesc_zone; ++#endif ++ ++#define debug crypto_debug ++int crypto_debug = 0; ++module_param(crypto_debug, int, 0644); ++MODULE_PARM_DESC(crypto_debug, "Enable debug"); ++EXPORT_SYMBOL(crypto_debug); ++ ++/* ++ * Maximum number of outstanding crypto requests before we start ++ * failing requests. We need this to prevent DOS when too many ++ * requests are arriving for us to keep up. Otherwise we will ++ * run the system out of memory. Since crypto is slow, we are ++ * usually the bottleneck that needs to say, enough is enough. ++ * ++ * We cannot print errors when this condition occurs, we are already too ++ * slow, printing anything will just kill us ++ */ ++ ++static int crypto_q_cnt = 0; ++module_param(crypto_q_cnt, int, 0444); ++MODULE_PARM_DESC(crypto_q_cnt, ++ "Current number of outstanding crypto requests"); ++ ++static int crypto_q_max = 1000; ++module_param(crypto_q_max, int, 0644); ++MODULE_PARM_DESC(crypto_q_max, ++ "Maximum number of outstanding crypto requests"); ++ ++#define bootverbose crypto_verbose ++static int crypto_verbose = 0; ++module_param(crypto_verbose, int, 0644); ++MODULE_PARM_DESC(crypto_verbose, ++ "Enable verbose crypto startup"); ++ ++int crypto_usercrypto = 1; /* userland may do crypto reqs */ ++module_param(crypto_usercrypto, int, 0644); ++MODULE_PARM_DESC(crypto_usercrypto, ++ "Enable/disable user-mode access to crypto support"); ++ ++int crypto_userasymcrypto = 1; /* userland may do asym crypto reqs */ ++module_param(crypto_userasymcrypto, int, 0644); ++MODULE_PARM_DESC(crypto_userasymcrypto, ++ "Enable/disable user-mode access to asymmetric crypto support"); ++ ++int crypto_devallowsoft = 0; /* only use hardware crypto */ ++module_param(crypto_devallowsoft, int, 0644); ++MODULE_PARM_DESC(crypto_devallowsoft, ++ "Enable/disable use of software crypto support"); ++ ++static pid_t cryptoproc = (pid_t) -1; ++static struct completion cryptoproc_exited; ++static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait); ++static pid_t cryptoretproc = (pid_t) -1; ++static struct completion cryptoretproc_exited; ++static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait); ++ ++static int crypto_proc(void *arg); ++static int crypto_ret_proc(void *arg); ++static int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint); ++static int crypto_kinvoke(struct cryptkop *krp, int flags); ++static void crypto_exit(void); ++static int crypto_init(void); ++ ++static struct cryptostats cryptostats; ++ ++static struct cryptocap * ++crypto_checkdriver(u_int32_t hid) ++{ ++ if (crypto_drivers == NULL) ++ return NULL; ++ return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]); ++} ++ ++/* ++ * Compare a driver's list of supported algorithms against another ++ * list; return non-zero if all algorithms are supported. ++ */ ++static int ++driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri) ++{ ++ const struct cryptoini *cr; ++ ++ /* See if all the algorithms are supported. */ ++ for (cr = cri; cr; cr = cr->cri_next) ++ if (cap->cc_alg[cr->cri_alg] == 0) ++ return 0; ++ return 1; ++} ++ ++/* ++ * Select a driver for a new session that supports the specified ++ * algorithms and, optionally, is constrained according to the flags. ++ * The algorithm we use here is pretty stupid; just use the ++ * first driver that supports all the algorithms we need. If there ++ * are multiple drivers we choose the driver with the fewest active ++ * sessions. We prefer hardware-backed drivers to software ones. ++ * ++ * XXX We need more smarts here (in real life too, but that's ++ * XXX another story altogether). ++ */ ++static struct cryptocap * ++crypto_select_driver(const struct cryptoini *cri, int flags) ++{ ++ struct cryptocap *cap, *best; ++ int match, hid; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ /* ++ * Look first for hardware crypto devices if permitted. ++ */ ++ if (flags & CRYPTOCAP_F_HARDWARE) ++ match = CRYPTOCAP_F_HARDWARE; ++ else ++ match = CRYPTOCAP_F_SOFTWARE; ++ best = NULL; ++again: ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ cap = &crypto_drivers[hid]; ++ /* ++ * If it's not initialized, is in the process of ++ * going away, or is not appropriate (hardware ++ * or software based on match), then skip. ++ */ ++ if (cap->cc_dev == NULL || ++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || ++ (cap->cc_flags & match) == 0) ++ continue; ++ ++ /* verify all the algorithms are supported. */ ++ if (driver_suitable(cap, cri)) { ++ if (best == NULL || ++ cap->cc_sessions < best->cc_sessions) ++ best = cap; ++ } ++ } ++ if (best != NULL) ++ return best; ++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { ++ /* sort of an Algol 68-style for loop */ ++ match = CRYPTOCAP_F_SOFTWARE; ++ goto again; ++ } ++ return best; ++} ++ ++/* ++ * Create a new session. The crid argument specifies a crypto ++ * driver to use or constraints on a driver to select (hardware ++ * only, software only, either). Whatever driver is selected ++ * must be capable of the requested crypto algorithms. ++ */ ++int ++crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid) ++{ ++ struct cryptocap *cap; ++ u_int32_t hid, lid; ++ int err; ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ /* ++ * Use specified driver; verify it is capable. ++ */ ++ cap = crypto_checkdriver(crid); ++ if (cap != NULL && !driver_suitable(cap, cri)) ++ cap = NULL; ++ } else { ++ /* ++ * No requested driver; select based on crid flags. ++ */ ++ cap = crypto_select_driver(cri, crid); ++ /* ++ * if NULL then can't do everything in one session. ++ * XXX Fix this. We need to inject a "virtual" session ++ * XXX layer right about here. ++ */ ++ } ++ if (cap != NULL) { ++ /* Call the driver initialization routine. */ ++ hid = cap - crypto_drivers; ++ lid = hid; /* Pass the driver ID. */ ++ cap->cc_sessions++; ++ CRYPTO_DRIVER_UNLOCK(); ++ err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri); ++ CRYPTO_DRIVER_LOCK(); ++ if (err == 0) { ++ (*sid) = (cap->cc_flags & 0xff000000) ++ | (hid & 0x00ffffff); ++ (*sid) <<= 32; ++ (*sid) |= (lid & 0xffffffff); ++ } else ++ cap->cc_sessions--; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++static void ++crypto_remove(struct cryptocap *cap) ++{ ++ CRYPTO_DRIVER_ASSERT(); ++ if (cap->cc_sessions == 0 && cap->cc_koperations == 0) ++ bzero(cap, sizeof(*cap)); ++} ++ ++/* ++ * Delete an existing session (or a reserved session on an unregistered ++ * driver). ++ */ ++int ++crypto_freesession(u_int64_t sid) ++{ ++ struct cryptocap *cap; ++ u_int32_t hid; ++ int err = 0; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ if (crypto_drivers == NULL) { ++ err = EINVAL; ++ goto done; ++ } ++ ++ /* Determine two IDs. */ ++ hid = CRYPTO_SESID2HID(sid); ++ ++ if (hid >= crypto_drivers_num) { ++ dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid); ++ err = ENOENT; ++ goto done; ++ } ++ cap = &crypto_drivers[hid]; ++ ++ if (cap->cc_dev) { ++ CRYPTO_DRIVER_UNLOCK(); ++ /* Call the driver cleanup routine, if available, unlocked. */ ++ err = CRYPTODEV_FREESESSION(cap->cc_dev, sid); ++ CRYPTO_DRIVER_LOCK(); ++ } ++ ++ if (cap->cc_sessions) ++ cap->cc_sessions--; ++ ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ++ crypto_remove(cap); ++ ++done: ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Return an unused driver id. Used by drivers prior to registering ++ * support for the algorithms they handle. ++ */ ++int32_t ++crypto_get_driverid(device_t dev, int flags) ++{ ++ struct cryptocap *newdrv; ++ int i; ++ unsigned long d_flags; ++ ++ if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ printf("%s: no flags specified when registering driver\n", ++ device_get_nameunit(dev)); ++ return -1; ++ } ++ ++ CRYPTO_DRIVER_LOCK(); ++ ++ for (i = 0; i < crypto_drivers_num; i++) { ++ if (crypto_drivers[i].cc_dev == NULL && ++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) { ++ break; ++ } ++ } ++ ++ /* Out of entries, allocate some more. */ ++ if (i == crypto_drivers_num) { ++ /* Be careful about wrap-around. */ ++ if (2 * crypto_drivers_num <= crypto_drivers_num) { ++ CRYPTO_DRIVER_UNLOCK(); ++ printk("crypto: driver count wraparound!\n"); ++ return -1; ++ } ++ ++ newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap), ++ GFP_KERNEL); ++ if (newdrv == NULL) { ++ CRYPTO_DRIVER_UNLOCK(); ++ printk("crypto: no space to expand driver table!\n"); ++ return -1; ++ } ++ ++ memcpy(newdrv, crypto_drivers, ++ crypto_drivers_num * sizeof(struct cryptocap)); ++ memset(&newdrv[crypto_drivers_num], 0, ++ crypto_drivers_num * sizeof(struct cryptocap)); ++ ++ crypto_drivers_num *= 2; ++ ++ kfree(crypto_drivers); ++ crypto_drivers = newdrv; ++ } ++ ++ /* NB: state is zero'd on free */ ++ crypto_drivers[i].cc_sessions = 1; /* Mark */ ++ crypto_drivers[i].cc_dev = dev; ++ crypto_drivers[i].cc_flags = flags; ++ if (bootverbose) ++ printf("crypto: assign %s driver id %u, flags %u\n", ++ device_get_nameunit(dev), i, flags); ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ return i; ++} ++ ++/* ++ * Lookup a driver by name. We match against the full device ++ * name and unit, and against just the name. The latter gives ++ * us a simple widlcarding by device name. On success return the ++ * driver/hardware identifier; otherwise return -1. ++ */ ++int ++crypto_find_driver(const char *match) ++{ ++ int i, len = strlen(match); ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ for (i = 0; i < crypto_drivers_num; i++) { ++ device_t dev = crypto_drivers[i].cc_dev; ++ if (dev == NULL || ++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP)) ++ continue; ++ if (strncmp(match, device_get_nameunit(dev), len) == 0 || ++ strncmp(match, device_get_name(dev), len) == 0) ++ break; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ return i < crypto_drivers_num ? i : -1; ++} ++ ++/* ++ * Return the device_t for the specified driver or NULL ++ * if the driver identifier is invalid. ++ */ ++device_t ++crypto_find_device_byhid(int hid) ++{ ++ struct cryptocap *cap = crypto_checkdriver(hid); ++ return cap != NULL ? cap->cc_dev : NULL; ++} ++ ++/* ++ * Return the device/driver capabilities. ++ */ ++int ++crypto_getcaps(int hid) ++{ ++ struct cryptocap *cap = crypto_checkdriver(hid); ++ return cap != NULL ? cap->cc_flags : 0; ++} ++ ++/* ++ * Register support for a key-related algorithm. This routine ++ * is called once for each algorithm supported a driver. ++ */ ++int ++crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL && ++ (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) { ++ /* ++ * XXX Do some performance testing to determine placing. ++ * XXX We probably need an auxiliary data structure that ++ * XXX describes relative performances. ++ */ ++ ++ cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; ++ if (bootverbose) ++ printf("crypto: %s registers key alg %u flags %u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , kalg ++ , flags ++ ); ++ err = 0; ++ } else ++ err = EINVAL; ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Register support for a non-key-related algorithm. This routine ++ * is called once for each such algorithm supported by a driver. ++ */ ++int ++crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, ++ u_int32_t flags) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__, ++ driverid, alg, maxoplen, flags); ++ ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ /* NB: algorithms are in the range [1..max] */ ++ if (cap != NULL && ++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) { ++ /* ++ * XXX Do some performance testing to determine placing. ++ * XXX We probably need an auxiliary data structure that ++ * XXX describes relative performances. ++ */ ++ ++ cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; ++ cap->cc_max_op_len[alg] = maxoplen; ++ if (bootverbose) ++ printf("crypto: %s registers alg %u flags %u maxoplen %u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , alg ++ , flags ++ , maxoplen ++ ); ++ cap->cc_sessions = 0; /* Unmark */ ++ err = 0; ++ } else ++ err = EINVAL; ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++static void ++driver_finis(struct cryptocap *cap) ++{ ++ u_int32_t ses, kops; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ ses = cap->cc_sessions; ++ kops = cap->cc_koperations; ++ bzero(cap, sizeof(*cap)); ++ if (ses != 0 || kops != 0) { ++ /* ++ * If there are pending sessions, ++ * just mark as invalid. ++ */ ++ cap->cc_flags |= CRYPTOCAP_F_CLEANUP; ++ cap->cc_sessions = ses; ++ cap->cc_koperations = kops; ++ } ++} ++ ++/* ++ * Unregister a crypto driver. If there are pending sessions using it, ++ * leave enough information around so that subsequent calls using those ++ * sessions will correctly detect the driver has been unregistered and ++ * reroute requests. ++ */ ++int ++crypto_unregister(u_int32_t driverid, int alg) ++{ ++ struct cryptocap *cap; ++ int i, err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL && ++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) && ++ cap->cc_alg[alg] != 0) { ++ cap->cc_alg[alg] = 0; ++ cap->cc_max_op_len[alg] = 0; ++ ++ /* Was this the last algorithm ? */ ++ for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) ++ if (cap->cc_alg[i] != 0) ++ break; ++ ++ if (i == CRYPTO_ALGORITHM_MAX + 1) ++ driver_finis(cap); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Unregister all algorithms associated with a crypto driver. ++ * If there are pending sessions using it, leave enough information ++ * around so that subsequent calls using those sessions will ++ * correctly detect the driver has been unregistered and reroute ++ * requests. ++ */ ++int ++crypto_unregister_all(u_int32_t driverid) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL) { ++ driver_finis(cap); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ return err; ++} ++ ++/* ++ * Clear blockage on a driver. The what parameter indicates whether ++ * the driver is now ready for cryptop's and/or cryptokop's. ++ */ ++int ++crypto_unblock(u_int32_t driverid, int what) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long q_flags; ++ ++ CRYPTO_Q_LOCK(); ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL) { ++ if (what & CRYPTO_SYMQ) { ++ cap->cc_qblocked = 0; ++ crypto_all_qblocked = 0; ++ } ++ if (what & CRYPTO_ASYMQ) { ++ cap->cc_kqblocked = 0; ++ crypto_all_kqblocked = 0; ++ } ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock ++ ++ return err; ++} ++ ++/* ++ * Add a crypto request to a queue, to be processed by the kernel thread. ++ */ ++int ++crypto_dispatch(struct cryptop *crp) ++{ ++ struct cryptocap *cap; ++ int result = -1; ++ unsigned long q_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ cryptostats.cs_ops++; ++ ++ CRYPTO_Q_LOCK(); ++ if (crypto_q_cnt >= crypto_q_max) { ++ CRYPTO_Q_UNLOCK(); ++ cryptostats.cs_drops++; ++ return ENOMEM; ++ } ++ crypto_q_cnt++; ++ ++ /* ++ * Caller marked the request to be processed immediately; dispatch ++ * it directly to the driver unless the driver is currently blocked. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) { ++ int hid = CRYPTO_SESID2HID(crp->crp_sid); ++ cap = crypto_checkdriver(hid); ++ /* Driver cannot disappear when there is an active session. */ ++ KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__)); ++ if (!cap->cc_qblocked) { ++ crypto_all_qblocked = 0; ++ crypto_drivers[hid].cc_qblocked = 1; ++ CRYPTO_Q_UNLOCK(); ++ result = crypto_invoke(cap, crp, 0); ++ CRYPTO_Q_LOCK(); ++ if (result != ERESTART) ++ crypto_drivers[hid].cc_qblocked = 0; ++ } ++ } ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ list_add(&crp->crp_next, &crp_q); ++ cryptostats.cs_blocks++; ++ } else if (result == -1) { ++ TAILQ_INSERT_TAIL(&crp_q, crp, crp_next); ++ } ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_Q_UNLOCK(); ++ return 0; ++} ++ ++/* ++ * Add an asymetric crypto request to a queue, ++ * to be processed by the kernel thread. ++ */ ++int ++crypto_kdispatch(struct cryptkop *krp) ++{ ++ int error; ++ unsigned long q_flags; ++ ++ cryptostats.cs_kops++; ++ ++ error = crypto_kinvoke(krp, krp->krp_crid); ++ if (error == ERESTART) { ++ CRYPTO_Q_LOCK(); ++ TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next); ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_Q_UNLOCK(); ++ error = 0; ++ } ++ return error; ++} ++ ++/* ++ * Verify a driver is suitable for the specified operation. ++ */ ++static __inline int ++kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp) ++{ ++ return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0; ++} ++ ++/* ++ * Select a driver for an asym operation. The driver must ++ * support the necessary algorithm. The caller can constrain ++ * which device is selected with the flags parameter. The ++ * algorithm we use here is pretty stupid; just use the first ++ * driver that supports the algorithms we need. If there are ++ * multiple suitable drivers we choose the driver with the ++ * fewest active operations. We prefer hardware-backed ++ * drivers to software ones when either may be used. ++ */ ++static struct cryptocap * ++crypto_select_kdriver(const struct cryptkop *krp, int flags) ++{ ++ struct cryptocap *cap, *best, *blocked; ++ int match, hid; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ /* ++ * Look first for hardware crypto devices if permitted. ++ */ ++ if (flags & CRYPTOCAP_F_HARDWARE) ++ match = CRYPTOCAP_F_HARDWARE; ++ else ++ match = CRYPTOCAP_F_SOFTWARE; ++ best = NULL; ++ blocked = NULL; ++again: ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ cap = &crypto_drivers[hid]; ++ /* ++ * If it's not initialized, is in the process of ++ * going away, or is not appropriate (hardware ++ * or software based on match), then skip. ++ */ ++ if (cap->cc_dev == NULL || ++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || ++ (cap->cc_flags & match) == 0) ++ continue; ++ ++ /* verify all the algorithms are supported. */ ++ if (kdriver_suitable(cap, krp)) { ++ if (best == NULL || ++ cap->cc_koperations < best->cc_koperations) ++ best = cap; ++ } ++ } ++ if (best != NULL) ++ return best; ++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { ++ /* sort of an Algol 68-style for loop */ ++ match = CRYPTOCAP_F_SOFTWARE; ++ goto again; ++ } ++ return best; ++} ++ ++/* ++ * Dispatch an assymetric crypto request. ++ */ ++static int ++crypto_kinvoke(struct cryptkop *krp, int crid) ++{ ++ struct cryptocap *cap = NULL; ++ int error; ++ unsigned long d_flags; ++ ++ KASSERT(krp != NULL, ("%s: krp == NULL", __func__)); ++ KASSERT(krp->krp_callback != NULL, ++ ("%s: krp->crp_callback == NULL", __func__)); ++ ++ CRYPTO_DRIVER_LOCK(); ++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ cap = crypto_checkdriver(crid); ++ if (cap != NULL) { ++ /* ++ * Driver present, it must support the necessary ++ * algorithm and, if s/w drivers are excluded, ++ * it must be registered as hardware-backed. ++ */ ++ if (!kdriver_suitable(cap, krp) || ++ (!crypto_devallowsoft && ++ (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0)) ++ cap = NULL; ++ } ++ } else { ++ /* ++ * No requested driver; select based on crid flags. ++ */ ++ if (!crypto_devallowsoft) /* NB: disallow s/w drivers */ ++ crid &= ~CRYPTOCAP_F_SOFTWARE; ++ cap = crypto_select_kdriver(krp, crid); ++ } ++ if (cap != NULL && !cap->cc_kqblocked) { ++ krp->krp_hid = cap - crypto_drivers; ++ cap->cc_koperations++; ++ CRYPTO_DRIVER_UNLOCK(); ++ error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0); ++ CRYPTO_DRIVER_LOCK(); ++ if (error == ERESTART) { ++ cap->cc_koperations--; ++ CRYPTO_DRIVER_UNLOCK(); ++ return (error); ++ } ++ /* return the actual device used */ ++ krp->krp_crid = krp->krp_hid; ++ } else { ++ /* ++ * NB: cap is !NULL if device is blocked; in ++ * that case return ERESTART so the operation ++ * is resubmitted if possible. ++ */ ++ error = (cap == NULL) ? ENODEV : ERESTART; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ if (error) { ++ krp->krp_status = error; ++ crypto_kdone(krp); ++ } ++ return 0; ++} ++ ++ ++/* ++ * Dispatch a crypto request to the appropriate crypto devices. ++ */ ++static int ++crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint) ++{ ++ KASSERT(crp != NULL, ("%s: crp == NULL", __func__)); ++ KASSERT(crp->crp_callback != NULL, ++ ("%s: crp->crp_callback == NULL", __func__)); ++ KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__)); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++#ifdef CRYPTO_TIMING ++ if (crypto_timing) ++ crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp); ++#endif ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) { ++ struct cryptodesc *crd; ++ u_int64_t nid; ++ ++ /* ++ * Driver has unregistered; migrate the session and return ++ * an error to the caller so they'll resubmit the op. ++ * ++ * XXX: What if there are more already queued requests for this ++ * session? ++ */ ++ crypto_freesession(crp->crp_sid); ++ ++ for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) ++ crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); ++ ++ /* XXX propagate flags from initial session? */ ++ if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), ++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0) ++ crp->crp_sid = nid; ++ ++ crp->crp_etype = EAGAIN; ++ crypto_done(crp); ++ return 0; ++ } else { ++ /* ++ * Invoke the driver to process the request. ++ */ ++ return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint); ++ } ++} ++ ++/* ++ * Release a set of crypto descriptors. ++ */ ++void ++crypto_freereq(struct cryptop *crp) ++{ ++ struct cryptodesc *crd; ++ ++ if (crp == NULL) ++ return; ++ ++#ifdef DIAGNOSTIC ++ { ++ struct cryptop *crp2; ++ unsigned long q_flags; ++ ++ CRYPTO_Q_LOCK(); ++ TAILQ_FOREACH(crp2, &crp_q, crp_next) { ++ KASSERT(crp2 != crp, ++ ("Freeing cryptop from the crypto queue (%p).", ++ crp)); ++ } ++ CRYPTO_Q_UNLOCK(); ++ CRYPTO_RETQ_LOCK(); ++ TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) { ++ KASSERT(crp2 != crp, ++ ("Freeing cryptop from the return queue (%p).", ++ crp)); ++ } ++ CRYPTO_RETQ_UNLOCK(); ++ } ++#endif ++ ++ while ((crd = crp->crp_desc) != NULL) { ++ crp->crp_desc = crd->crd_next; ++ kmem_cache_free(cryptodesc_zone, crd); ++ } ++ kmem_cache_free(cryptop_zone, crp); ++} ++ ++/* ++ * Acquire a set of crypto descriptors. ++ */ ++struct cryptop * ++crypto_getreq(int num) ++{ ++ struct cryptodesc *crd; ++ struct cryptop *crp; ++ ++ crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC); ++ if (crp != NULL) { ++ memset(crp, 0, sizeof(*crp)); ++ INIT_LIST_HEAD(&crp->crp_next); ++ init_waitqueue_head(&crp->crp_waitq); ++ while (num--) { ++ crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC); ++ if (crd == NULL) { ++ crypto_freereq(crp); ++ return NULL; ++ } ++ memset(crd, 0, sizeof(*crd)); ++ crd->crd_next = crp->crp_desc; ++ crp->crp_desc = crd; ++ } ++ } ++ return crp; ++} ++ ++/* ++ * Invoke the callback on behalf of the driver. ++ */ ++void ++crypto_done(struct cryptop *crp) ++{ ++ unsigned long q_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if ((crp->crp_flags & CRYPTO_F_DONE) == 0) { ++ crp->crp_flags |= CRYPTO_F_DONE; ++ CRYPTO_Q_LOCK(); ++ crypto_q_cnt--; ++ CRYPTO_Q_UNLOCK(); ++ } else ++ printk("crypto: crypto_done op already done, flags 0x%x", ++ crp->crp_flags); ++ if (crp->crp_etype != 0) ++ cryptostats.cs_errs++; ++ /* ++ * CBIMM means unconditionally do the callback immediately; ++ * CBIFSYNC means do the callback immediately only if the ++ * operation was done synchronously. Both are used to avoid ++ * doing extraneous context switches; the latter is mostly ++ * used with the software crypto driver. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_CBIMM) || ++ ((crp->crp_flags & CRYPTO_F_CBIFSYNC) && ++ (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) { ++ /* ++ * Do the callback directly. This is ok when the ++ * callback routine does very little (e.g. the ++ * /dev/crypto callback method just does a wakeup). ++ */ ++ crp->crp_callback(crp); ++ } else { ++ unsigned long r_flags; ++ /* ++ * Normal case; queue the callback for the thread. ++ */ ++ CRYPTO_RETQ_LOCK(); ++ if (CRYPTO_RETQ_EMPTY()) ++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ ++ TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next); ++ CRYPTO_RETQ_UNLOCK(); ++ } ++} ++ ++/* ++ * Invoke the callback on behalf of the driver. ++ */ ++void ++crypto_kdone(struct cryptkop *krp) ++{ ++ struct cryptocap *cap; ++ unsigned long d_flags; ++ ++ if ((krp->krp_flags & CRYPTO_KF_DONE) != 0) ++ printk("crypto: crypto_kdone op already done, flags 0x%x", ++ krp->krp_flags); ++ krp->krp_flags |= CRYPTO_KF_DONE; ++ if (krp->krp_status != 0) ++ cryptostats.cs_kerrs++; ++ ++ CRYPTO_DRIVER_LOCK(); ++ /* XXX: What if driver is loaded in the meantime? */ ++ if (krp->krp_hid < crypto_drivers_num) { ++ cap = &crypto_drivers[krp->krp_hid]; ++ cap->cc_koperations--; ++ KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0")); ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ++ crypto_remove(cap); ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ /* ++ * CBIMM means unconditionally do the callback immediately; ++ * This is used to avoid doing extraneous context switches ++ */ ++ if ((krp->krp_flags & CRYPTO_KF_CBIMM)) { ++ /* ++ * Do the callback directly. This is ok when the ++ * callback routine does very little (e.g. the ++ * /dev/crypto callback method just does a wakeup). ++ */ ++ krp->krp_callback(krp); ++ } else { ++ unsigned long r_flags; ++ /* ++ * Normal case; queue the callback for the thread. ++ */ ++ CRYPTO_RETQ_LOCK(); ++ if (CRYPTO_RETQ_EMPTY()) ++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ ++ TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next); ++ CRYPTO_RETQ_UNLOCK(); ++ } ++} ++ ++int ++crypto_getfeat(int *featp) ++{ ++ int hid, kalg, feat = 0; ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ const struct cryptocap *cap = &crypto_drivers[hid]; ++ ++ if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) && ++ !crypto_devallowsoft) { ++ continue; ++ } ++ for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++) ++ if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED) ++ feat |= 1 << kalg; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ *featp = feat; ++ return (0); ++} ++ ++/* ++ * Crypto thread, dispatches crypto requests. ++ */ ++static int ++crypto_proc(void *arg) ++{ ++ struct cryptop *crp, *submit; ++ struct cryptkop *krp, *krpp; ++ struct cryptocap *cap; ++ u_int32_t hid; ++ int result, hint; ++ unsigned long q_flags; ++ ++ ocf_daemonize("crypto"); ++ ++ CRYPTO_Q_LOCK(); ++ for (;;) { ++ /* ++ * we need to make sure we don't get into a busy loop with nothing ++ * to do, the two crypto_all_*blocked vars help us find out when ++ * we are all full and can do nothing on any driver or Q. If so we ++ * wait for an unblock. ++ */ ++ crypto_all_qblocked = !list_empty(&crp_q); ++ ++ /* ++ * Find the first element in the queue that can be ++ * processed and look-ahead to see if multiple ops ++ * are ready for the same driver. ++ */ ++ submit = NULL; ++ hint = 0; ++ list_for_each_entry(crp, &crp_q, crp_next) { ++ hid = CRYPTO_SESID2HID(crp->crp_sid); ++ cap = crypto_checkdriver(hid); ++ /* ++ * Driver cannot disappear when there is an active ++ * session. ++ */ ++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.", ++ __func__, __LINE__)); ++ if (cap == NULL || cap->cc_dev == NULL) { ++ /* Op needs to be migrated, process it. */ ++ if (submit == NULL) ++ submit = crp; ++ break; ++ } ++ if (!cap->cc_qblocked) { ++ if (submit != NULL) { ++ /* ++ * We stop on finding another op, ++ * regardless whether its for the same ++ * driver or not. We could keep ++ * searching the queue but it might be ++ * better to just use a per-driver ++ * queue instead. ++ */ ++ if (CRYPTO_SESID2HID(submit->crp_sid) == hid) ++ hint = CRYPTO_HINT_MORE; ++ break; ++ } else { ++ submit = crp; ++ if ((submit->crp_flags & CRYPTO_F_BATCH) == 0) ++ break; ++ /* keep scanning for more are q'd */ ++ } ++ } ++ } ++ if (submit != NULL) { ++ hid = CRYPTO_SESID2HID(submit->crp_sid); ++ crypto_all_qblocked = 0; ++ list_del(&submit->crp_next); ++ crypto_drivers[hid].cc_qblocked = 1; ++ cap = crypto_checkdriver(hid); ++ CRYPTO_Q_UNLOCK(); ++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.", ++ __func__, __LINE__)); ++ result = crypto_invoke(cap, submit, hint); ++ CRYPTO_Q_LOCK(); ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ /* XXX validate sid again? */ ++ list_add(&submit->crp_next, &crp_q); ++ cryptostats.cs_blocks++; ++ } else ++ crypto_drivers[hid].cc_qblocked=0; ++ } ++ ++ crypto_all_kqblocked = !list_empty(&crp_kq); ++ ++ /* As above, but for key ops */ ++ krp = NULL; ++ list_for_each_entry(krpp, &crp_kq, krp_next) { ++ cap = crypto_checkdriver(krpp->krp_hid); ++ if (cap == NULL || cap->cc_dev == NULL) { ++ /* ++ * Operation needs to be migrated, invalidate ++ * the assigned device so it will reselect a ++ * new one below. Propagate the original ++ * crid selection flags if supplied. ++ */ ++ krp->krp_hid = krp->krp_crid & ++ (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE); ++ if (krp->krp_hid == 0) ++ krp->krp_hid = ++ CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE; ++ break; ++ } ++ if (!cap->cc_kqblocked) { ++ krp = krpp; ++ break; ++ } ++ } ++ if (krp != NULL) { ++ crypto_all_kqblocked = 0; ++ list_del(&krp->krp_next); ++ crypto_drivers[krp->krp_hid].cc_kqblocked = 1; ++ CRYPTO_Q_UNLOCK(); ++ result = crypto_kinvoke(krp, krp->krp_hid); ++ CRYPTO_Q_LOCK(); ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptkop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ /* XXX validate sid again? */ ++ list_add(&krp->krp_next, &crp_kq); ++ cryptostats.cs_kblocks++; ++ } else ++ crypto_drivers[krp->krp_hid].cc_kqblocked = 0; ++ } ++ ++ if (submit == NULL && krp == NULL) { ++ /* ++ * Nothing more to be processed. Sleep until we're ++ * woken because there are more ops to process. ++ * This happens either by submission or by a driver ++ * becoming unblocked and notifying us through ++ * crypto_unblock. Note that when we wakeup we ++ * start processing each queue again from the ++ * front. It's not clear that it's important to ++ * preserve this ordering since ops may finish ++ * out of order if dispatched to different devices ++ * and some become blocked while others do not. ++ */ ++ dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n", ++ __FUNCTION__, ++ list_empty(&crp_q), crypto_all_qblocked, ++ list_empty(&crp_kq), crypto_all_kqblocked); ++ CRYPTO_Q_UNLOCK(); ++ crp_sleep = 1; ++ wait_event_interruptible(cryptoproc_wait, ++ !(list_empty(&crp_q) || crypto_all_qblocked) || ++ !(list_empty(&crp_kq) || crypto_all_kqblocked) || ++ cryptoproc == (pid_t) -1); ++ crp_sleep = 0; ++ if (signal_pending (current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ CRYPTO_Q_LOCK(); ++ dprintk("%s - awake\n", __FUNCTION__); ++ if (cryptoproc == (pid_t) -1) ++ break; ++ cryptostats.cs_intrs++; ++ } ++ } ++ CRYPTO_Q_UNLOCK(); ++ complete_and_exit(&cryptoproc_exited, 0); ++} ++ ++/* ++ * Crypto returns thread, does callbacks for processed crypto requests. ++ * Callbacks are done here, rather than in the crypto drivers, because ++ * callbacks typically are expensive and would slow interrupt handling. ++ */ ++static int ++crypto_ret_proc(void *arg) ++{ ++ struct cryptop *crpt; ++ struct cryptkop *krpt; ++ unsigned long r_flags; ++ ++ ocf_daemonize("crypto_ret"); ++ ++ CRYPTO_RETQ_LOCK(); ++ for (;;) { ++ /* Harvest return q's for completed ops */ ++ crpt = NULL; ++ if (!list_empty(&crp_ret_q)) ++ crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next); ++ if (crpt != NULL) ++ list_del(&crpt->crp_next); ++ ++ krpt = NULL; ++ if (!list_empty(&crp_ret_kq)) ++ krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next); ++ if (krpt != NULL) ++ list_del(&krpt->krp_next); ++ ++ if (crpt != NULL || krpt != NULL) { ++ CRYPTO_RETQ_UNLOCK(); ++ /* ++ * Run callbacks unlocked. ++ */ ++ if (crpt != NULL) ++ crpt->crp_callback(crpt); ++ if (krpt != NULL) ++ krpt->krp_callback(krpt); ++ CRYPTO_RETQ_LOCK(); ++ } else { ++ /* ++ * Nothing more to be processed. Sleep until we're ++ * woken because there are more returns to process. ++ */ ++ dprintk("%s - sleeping\n", __FUNCTION__); ++ CRYPTO_RETQ_UNLOCK(); ++ wait_event_interruptible(cryptoretproc_wait, ++ cryptoretproc == (pid_t) -1 || ++ !list_empty(&crp_ret_q) || ++ !list_empty(&crp_ret_kq)); ++ if (signal_pending (current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ CRYPTO_RETQ_LOCK(); ++ dprintk("%s - awake\n", __FUNCTION__); ++ if (cryptoretproc == (pid_t) -1) { ++ dprintk("%s - EXITING!\n", __FUNCTION__); ++ break; ++ } ++ cryptostats.cs_rets++; ++ } ++ } ++ CRYPTO_RETQ_UNLOCK(); ++ complete_and_exit(&cryptoretproc_exited, 0); ++} ++ ++ ++#if 0 /* should put this into /proc or something */ ++static void ++db_show_drivers(void) ++{ ++ int hid; ++ ++ db_printf("%12s %4s %4s %8s %2s %2s\n" ++ , "Device" ++ , "Ses" ++ , "Kops" ++ , "Flags" ++ , "QB" ++ , "KB" ++ ); ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ const struct cryptocap *cap = &crypto_drivers[hid]; ++ if (cap->cc_dev == NULL) ++ continue; ++ db_printf("%-12s %4u %4u %08x %2u %2u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , cap->cc_sessions ++ , cap->cc_koperations ++ , cap->cc_flags ++ , cap->cc_qblocked ++ , cap->cc_kqblocked ++ ); ++ } ++} ++ ++DB_SHOW_COMMAND(crypto, db_show_crypto) ++{ ++ struct cryptop *crp; ++ ++ db_show_drivers(); ++ db_printf("\n"); ++ ++ db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n", ++ "HID", "Caps", "Ilen", "Olen", "Etype", "Flags", ++ "Desc", "Callback"); ++ TAILQ_FOREACH(crp, &crp_q, crp_next) { ++ db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n" ++ , (int) CRYPTO_SESID2HID(crp->crp_sid) ++ , (int) CRYPTO_SESID2CAPS(crp->crp_sid) ++ , crp->crp_ilen, crp->crp_olen ++ , crp->crp_etype ++ , crp->crp_flags ++ , crp->crp_desc ++ , crp->crp_callback ++ ); ++ } ++ if (!TAILQ_EMPTY(&crp_ret_q)) { ++ db_printf("\n%4s %4s %4s %8s\n", ++ "HID", "Etype", "Flags", "Callback"); ++ TAILQ_FOREACH(crp, &crp_ret_q, crp_next) { ++ db_printf("%4u %4u %04x %8p\n" ++ , (int) CRYPTO_SESID2HID(crp->crp_sid) ++ , crp->crp_etype ++ , crp->crp_flags ++ , crp->crp_callback ++ ); ++ } ++ } ++} ++ ++DB_SHOW_COMMAND(kcrypto, db_show_kcrypto) ++{ ++ struct cryptkop *krp; ++ ++ db_show_drivers(); ++ db_printf("\n"); ++ ++ db_printf("%4s %5s %4s %4s %8s %4s %8s\n", ++ "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback"); ++ TAILQ_FOREACH(krp, &crp_kq, krp_next) { ++ db_printf("%4u %5u %4u %4u %08x %4u %8p\n" ++ , krp->krp_op ++ , krp->krp_status ++ , krp->krp_iparams, krp->krp_oparams ++ , krp->krp_crid, krp->krp_hid ++ , krp->krp_callback ++ ); ++ } ++ if (!TAILQ_EMPTY(&crp_ret_q)) { ++ db_printf("%4s %5s %8s %4s %8s\n", ++ "Op", "Status", "CRID", "HID", "Callback"); ++ TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) { ++ db_printf("%4u %5u %08x %4u %8p\n" ++ , krp->krp_op ++ , krp->krp_status ++ , krp->krp_crid, krp->krp_hid ++ , krp->krp_callback ++ ); ++ } ++ } ++} ++#endif ++ ++ ++static int ++crypto_init(void) ++{ ++ int error; ++ ++ dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init); ++ ++ if (crypto_initted) ++ return 0; ++ crypto_initted = 1; ++ ++ spin_lock_init(&crypto_drivers_lock); ++ spin_lock_init(&crypto_q_lock); ++ spin_lock_init(&crypto_ret_q_lock); ++ ++ cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop), ++ 0, SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ ++ cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc), ++ 0, SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ ++ if (cryptodesc_zone == NULL || cryptop_zone == NULL) { ++ printk("crypto: crypto_init cannot setup crypto zones\n"); ++ error = ENOMEM; ++ goto bad; ++ } ++ ++ crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; ++ crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap), ++ GFP_KERNEL); ++ if (crypto_drivers == NULL) { ++ printk("crypto: crypto_init cannot setup crypto drivers\n"); ++ error = ENOMEM; ++ goto bad; ++ } ++ ++ memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap)); ++ ++ init_completion(&cryptoproc_exited); ++ init_completion(&cryptoretproc_exited); ++ ++ cryptoproc = 0; /* to avoid race condition where proc runs first */ ++ cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (cryptoproc < 0) { ++ error = cryptoproc; ++ printk("crypto: crypto_init cannot start crypto thread; error %d", ++ error); ++ goto bad; ++ } ++ ++ cryptoretproc = 0; /* to avoid race condition where proc runs first */ ++ cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (cryptoretproc < 0) { ++ error = cryptoretproc; ++ printk("crypto: crypto_init cannot start cryptoret thread; error %d", ++ error); ++ goto bad; ++ } ++ ++ return 0; ++bad: ++ crypto_exit(); ++ return error; ++} ++ ++ ++static void ++crypto_exit(void) ++{ ++ pid_t p; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* ++ * Terminate any crypto threads. ++ */ ++ ++ CRYPTO_DRIVER_LOCK(); ++ p = cryptoproc; ++ cryptoproc = (pid_t) -1; ++ kill_pid(p, SIGTERM, 1); ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ wait_for_completion(&cryptoproc_exited); ++ ++ CRYPTO_DRIVER_LOCK(); ++ p = cryptoretproc; ++ cryptoretproc = (pid_t) -1; ++ kill_pid(p, SIGTERM, 1); ++ wake_up_interruptible(&cryptoretproc_wait); ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ wait_for_completion(&cryptoretproc_exited); ++ ++ /* XXX flush queues??? */ ++ ++ /* ++ * Reclaim dynamically allocated resources. ++ */ ++ if (crypto_drivers != NULL) ++ kfree(crypto_drivers); ++ ++ if (cryptodesc_zone != NULL) ++ kmem_cache_destroy(cryptodesc_zone); ++ if (cryptop_zone != NULL) ++ kmem_cache_destroy(cryptop_zone); ++} ++ ++ ++EXPORT_SYMBOL(crypto_newsession); ++EXPORT_SYMBOL(crypto_freesession); ++EXPORT_SYMBOL(crypto_get_driverid); ++EXPORT_SYMBOL(crypto_kregister); ++EXPORT_SYMBOL(crypto_register); ++EXPORT_SYMBOL(crypto_unregister); ++EXPORT_SYMBOL(crypto_unregister_all); ++EXPORT_SYMBOL(crypto_unblock); ++EXPORT_SYMBOL(crypto_dispatch); ++EXPORT_SYMBOL(crypto_kdispatch); ++EXPORT_SYMBOL(crypto_freereq); ++EXPORT_SYMBOL(crypto_getreq); ++EXPORT_SYMBOL(crypto_done); ++EXPORT_SYMBOL(crypto_kdone); ++EXPORT_SYMBOL(crypto_getfeat); ++EXPORT_SYMBOL(crypto_userasymcrypto); ++EXPORT_SYMBOL(crypto_getcaps); ++EXPORT_SYMBOL(crypto_find_driver); ++EXPORT_SYMBOL(crypto_find_device_byhid); ++ ++module_init(crypto_init); ++module_exit(crypto_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptodev.c linux-2.6.30/crypto/ocf/cryptodev.c +--- linux-2.6.30.orig/crypto/ocf/cryptodev.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptodev.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1048 @@ ++/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ ++ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2001 Theo de Raadt ++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++extern asmlinkage long sys_dup(unsigned int fildes); ++ ++#define debug cryptodev_debug ++int cryptodev_debug = 0; ++module_param(cryptodev_debug, int, 0644); ++MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug"); ++ ++struct csession_info { ++ u_int16_t blocksize; ++ u_int16_t minkey, maxkey; ++ ++ u_int16_t keysize; ++ /* u_int16_t hashsize; */ ++ u_int16_t authsize; ++ /* u_int16_t ctxsize; */ ++}; ++ ++struct csession { ++ struct list_head list; ++ u_int64_t sid; ++ u_int32_t ses; ++ ++ wait_queue_head_t waitq; ++ ++ u_int32_t cipher; ++ ++ u_int32_t mac; ++ ++ caddr_t key; ++ int keylen; ++ u_char tmp_iv[EALG_MAX_BLOCK_LEN]; ++ ++ caddr_t mackey; ++ int mackeylen; ++ ++ struct csession_info info; ++ ++ struct iovec iovec; ++ struct uio uio; ++ int error; ++}; ++ ++struct fcrypt { ++ struct list_head csessions; ++ int sesn; ++}; ++ ++static struct csession *csefind(struct fcrypt *, u_int); ++static int csedelete(struct fcrypt *, struct csession *); ++static struct csession *cseadd(struct fcrypt *, struct csession *); ++static struct csession *csecreate(struct fcrypt *, u_int64_t, ++ struct cryptoini *crie, struct cryptoini *cria, struct csession_info *); ++static int csefree(struct csession *); ++ ++static int cryptodev_op(struct csession *, struct crypt_op *); ++static int cryptodev_key(struct crypt_kop *); ++static int cryptodev_find(struct crypt_find_op *); ++ ++static int cryptodev_cb(void *); ++static int cryptodev_open(struct inode *inode, struct file *filp); ++ ++/* ++ * Check a crypto identifier to see if it requested ++ * a valid crid and it's capabilities match. ++ */ ++static int ++checkcrid(int crid) ++{ ++ int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); ++ int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); ++ int caps = 0; ++ ++ /* if the user hasn't selected a driver, then just call newsession */ ++ if (hid == 0 && typ != 0) ++ return 0; ++ ++ caps = crypto_getcaps(hid); ++ ++ /* didn't find anything with capabilities */ ++ if (caps == 0) { ++ dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ); ++ return EINVAL; ++ } ++ ++ /* the user didn't specify SW or HW, so the driver is ok */ ++ if (typ == 0) ++ return 0; ++ ++ /* if the type specified didn't match */ ++ if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) { ++ dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__, ++ hid, typ, caps); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++cryptodev_op(struct csession *cse, struct crypt_op *cop) ++{ ++ struct cryptop *crp = NULL; ++ struct cryptodesc *crde = NULL, *crda = NULL; ++ int error = 0; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (cop->len > CRYPTO_MAX_DATA_LEN) { ++ dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN); ++ return (E2BIG); ++ } ++ ++ if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) { ++ dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize, ++ cop->len); ++ return (EINVAL); ++ } ++ ++ cse->uio.uio_iov = &cse->iovec; ++ cse->uio.uio_iovcnt = 1; ++ cse->uio.uio_offset = 0; ++#if 0 ++ cse->uio.uio_resid = cop->len; ++ cse->uio.uio_segflg = UIO_SYSSPACE; ++ cse->uio.uio_rw = UIO_WRITE; ++ cse->uio.uio_td = td; ++#endif ++ cse->uio.uio_iov[0].iov_len = cop->len; ++ if (cse->info.authsize) ++ cse->uio.uio_iov[0].iov_len += cse->info.authsize; ++ cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len, ++ GFP_KERNEL); ++ ++ if (cse->uio.uio_iov[0].iov_base == NULL) { ++ dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__, ++ cse->uio.uio_iov[0].iov_len); ++ return (ENOMEM); ++ } ++ ++ crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0)); ++ if (crp == NULL) { ++ dprintk("%s: ENOMEM\n", __FUNCTION__); ++ error = ENOMEM; ++ goto bail; ++ } ++ ++ if (cse->info.authsize) { ++ crda = crp->crp_desc; ++ if (cse->info.blocksize) ++ crde = crda->crd_next; ++ } else { ++ if (cse->info.blocksize) ++ crde = crp->crp_desc; ++ else { ++ dprintk("%s: bad request\n", __FUNCTION__); ++ error = EINVAL; ++ goto bail; ++ } ++ } ++ ++ if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src, ++ cop->len))) { ++ dprintk("%s: bad copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (crda) { ++ crda->crd_skip = 0; ++ crda->crd_len = cop->len; ++ crda->crd_inject = cop->len; ++ ++ crda->crd_alg = cse->mac; ++ crda->crd_key = cse->mackey; ++ crda->crd_klen = cse->mackeylen * 8; ++ } ++ ++ if (crde) { ++ if (cop->op == COP_ENCRYPT) ++ crde->crd_flags |= CRD_F_ENCRYPT; ++ else ++ crde->crd_flags &= ~CRD_F_ENCRYPT; ++ crde->crd_len = cop->len; ++ crde->crd_inject = 0; ++ ++ crde->crd_alg = cse->cipher; ++ crde->crd_key = cse->key; ++ crde->crd_klen = cse->keylen * 8; ++ } ++ ++ crp->crp_ilen = cse->uio.uio_iov[0].iov_len; ++ crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM ++ | (cop->flags & COP_F_BATCH); ++ crp->crp_buf = (caddr_t)&cse->uio; ++ crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; ++ crp->crp_sid = cse->sid; ++ crp->crp_opaque = (void *)cse; ++ ++ if (cop->iv) { ++ if (crde == NULL) { ++ error = EINVAL; ++ dprintk("%s no crde\n", __FUNCTION__); ++ goto bail; ++ } ++ if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ ++ error = EINVAL; ++ dprintk("%s arc4 with IV\n", __FUNCTION__); ++ goto bail; ++ } ++ if ((error = copy_from_user(cse->tmp_iv, cop->iv, ++ cse->info.blocksize))) { ++ dprintk("%s bad iv copy\n", __FUNCTION__); ++ goto bail; ++ } ++ memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize); ++ crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; ++ crde->crd_skip = 0; ++ } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ ++ crde->crd_skip = 0; ++ } else if (crde) { ++ crde->crd_flags |= CRD_F_IV_PRESENT; ++ crde->crd_skip = cse->info.blocksize; ++ crde->crd_len -= cse->info.blocksize; ++ } ++ ++ if (cop->mac && crda == NULL) { ++ error = EINVAL; ++ dprintk("%s no crda\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ /* ++ * Let the dispatch run unlocked, then, interlock against the ++ * callback before checking if the operation completed and going ++ * to sleep. This insures drivers don't inherit our lock which ++ * results in a lock order reversal between crypto_dispatch forced ++ * entry and the crypto_done callback into us. ++ */ ++ error = crypto_dispatch(crp); ++ if (error == 0) { ++ dprintk("%s about to WAIT\n", __FUNCTION__); ++ /* ++ * we really need to wait for driver to complete to maintain ++ * state, luckily interrupts will be remembered ++ */ ++ do { ++ error = wait_event_interruptible(crp->crp_waitq, ++ ((crp->crp_flags & CRYPTO_F_DONE) != 0)); ++ /* ++ * we can't break out of this loop or we will leave behind ++ * a huge mess, however, staying here means if your driver ++ * is broken user applications can hang and not be killed. ++ * The solution, fix your driver :-) ++ */ ++ if (error) { ++ schedule(); ++ error = 0; ++ } ++ } while ((crp->crp_flags & CRYPTO_F_DONE) == 0); ++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); ++ } ++ ++ if (crp->crp_etype != 0) { ++ error = crp->crp_etype; ++ dprintk("%s error in crp processing\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cse->error) { ++ error = cse->error; ++ dprintk("%s error in cse processing\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cop->dst && (error = copy_to_user(cop->dst, ++ cse->uio.uio_iov[0].iov_base, cop->len))) { ++ dprintk("%s bad dst copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cop->mac && ++ (error=copy_to_user(cop->mac, ++ (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, ++ cse->info.authsize))) { ++ dprintk("%s bad mac copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++bail: ++ if (crp) ++ crypto_freereq(crp); ++ if (cse->uio.uio_iov[0].iov_base) ++ kfree(cse->uio.uio_iov[0].iov_base); ++ ++ return (error); ++} ++ ++static int ++cryptodev_cb(void *op) ++{ ++ struct cryptop *crp = (struct cryptop *) op; ++ struct csession *cse = (struct csession *)crp->crp_opaque; ++ int error; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ error = crp->crp_etype; ++ if (error == EAGAIN) { ++ crp->crp_flags &= ~CRYPTO_F_DONE; ++#ifdef NOTYET ++ /* ++ * DAVIDM I am fairly sure that we should turn this into a batch ++ * request to stop bad karma/lockup, revisit ++ */ ++ crp->crp_flags |= CRYPTO_F_BATCH; ++#endif ++ return crypto_dispatch(crp); ++ } ++ if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) { ++ cse->error = error; ++ wake_up_interruptible(&crp->crp_waitq); ++ } ++ return (0); ++} ++ ++static int ++cryptodevkey_cb(void *op) ++{ ++ struct cryptkop *krp = (struct cryptkop *) op; ++ dprintk("%s()\n", __FUNCTION__); ++ wake_up_interruptible(&krp->krp_waitq); ++ return (0); ++} ++ ++static int ++cryptodev_key(struct crypt_kop *kop) ++{ ++ struct cryptkop *krp = NULL; ++ int error = EINVAL; ++ int in, out, size, i; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { ++ dprintk("%s params too big\n", __FUNCTION__); ++ return (EFBIG); ++ } ++ ++ in = kop->crk_iparams; ++ out = kop->crk_oparams; ++ switch (kop->crk_op) { ++ case CRK_MOD_EXP: ++ if (in == 3 && out == 1) ++ break; ++ return (EINVAL); ++ case CRK_MOD_EXP_CRT: ++ if (in == 6 && out == 1) ++ break; ++ return (EINVAL); ++ case CRK_DSA_SIGN: ++ if (in == 5 && out == 2) ++ break; ++ return (EINVAL); ++ case CRK_DSA_VERIFY: ++ if (in == 7 && out == 0) ++ break; ++ return (EINVAL); ++ case CRK_DH_COMPUTE_KEY: ++ if (in == 3 && out == 1) ++ break; ++ return (EINVAL); ++ default: ++ return (EINVAL); ++ } ++ ++ krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL); ++ if (!krp) ++ return (ENOMEM); ++ bzero(krp, sizeof *krp); ++ krp->krp_op = kop->crk_op; ++ krp->krp_status = kop->crk_status; ++ krp->krp_iparams = kop->crk_iparams; ++ krp->krp_oparams = kop->crk_oparams; ++ krp->krp_crid = kop->crk_crid; ++ krp->krp_status = 0; ++ krp->krp_flags = CRYPTO_KF_CBIMM; ++ krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; ++ init_waitqueue_head(&krp->krp_waitq); ++ ++ for (i = 0; i < CRK_MAXPARAM; i++) ++ krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; ++ for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { ++ size = (krp->krp_param[i].crp_nbits + 7) / 8; ++ if (size == 0) ++ continue; ++ krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL); ++ if (i >= krp->krp_iparams) ++ continue; ++ error = copy_from_user(krp->krp_param[i].crp_p, ++ kop->crk_param[i].crp_p, size); ++ if (error) ++ goto fail; ++ } ++ ++ error = crypto_kdispatch(krp); ++ if (error) ++ goto fail; ++ ++ do { ++ error = wait_event_interruptible(krp->krp_waitq, ++ ((krp->krp_flags & CRYPTO_KF_DONE) != 0)); ++ /* ++ * we can't break out of this loop or we will leave behind ++ * a huge mess, however, staying here means if your driver ++ * is broken user applications can hang and not be killed. ++ * The solution, fix your driver :-) ++ */ ++ if (error) { ++ schedule(); ++ error = 0; ++ } ++ } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0); ++ ++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); ++ ++ kop->crk_crid = krp->krp_crid; /* device that did the work */ ++ if (krp->krp_status != 0) { ++ error = krp->krp_status; ++ goto fail; ++ } ++ ++ for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { ++ size = (krp->krp_param[i].crp_nbits + 7) / 8; ++ if (size == 0) ++ continue; ++ error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, ++ size); ++ if (error) ++ goto fail; ++ } ++ ++fail: ++ if (krp) { ++ kop->crk_status = krp->krp_status; ++ for (i = 0; i < CRK_MAXPARAM; i++) { ++ if (krp->krp_param[i].crp_p) ++ kfree(krp->krp_param[i].crp_p); ++ } ++ kfree(krp); ++ } ++ return (error); ++} ++ ++static int ++cryptodev_find(struct crypt_find_op *find) ++{ ++ device_t dev; ++ ++ if (find->crid != -1) { ++ dev = crypto_find_device_byhid(find->crid); ++ if (dev == NULL) ++ return (ENOENT); ++ strlcpy(find->name, device_get_nameunit(dev), ++ sizeof(find->name)); ++ } else { ++ find->crid = crypto_find_driver(find->name); ++ if (find->crid == -1) ++ return (ENOENT); ++ } ++ return (0); ++} ++ ++static struct csession * ++csefind(struct fcrypt *fcr, u_int ses) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ list_for_each_entry(cse, &fcr->csessions, list) ++ if (cse->ses == ses) ++ return (cse); ++ return (NULL); ++} ++ ++static int ++csedelete(struct fcrypt *fcr, struct csession *cse_del) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ list_for_each_entry(cse, &fcr->csessions, list) { ++ if (cse == cse_del) { ++ list_del(&cse->list); ++ return (1); ++ } ++ } ++ return (0); ++} ++ ++static struct csession * ++cseadd(struct fcrypt *fcr, struct csession *cse) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ list_add_tail(&cse->list, &fcr->csessions); ++ cse->ses = fcr->sesn++; ++ return (cse); ++} ++ ++static struct csession * ++csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie, ++ struct cryptoini *cria, struct csession_info *info) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL); ++ if (cse == NULL) ++ return NULL; ++ memset(cse, 0, sizeof(struct csession)); ++ ++ INIT_LIST_HEAD(&cse->list); ++ init_waitqueue_head(&cse->waitq); ++ ++ cse->key = crie->cri_key; ++ cse->keylen = crie->cri_klen/8; ++ cse->mackey = cria->cri_key; ++ cse->mackeylen = cria->cri_klen/8; ++ cse->sid = sid; ++ cse->cipher = crie->cri_alg; ++ cse->mac = cria->cri_alg; ++ cse->info = *info; ++ cseadd(fcr, cse); ++ return (cse); ++} ++ ++static int ++csefree(struct csession *cse) ++{ ++ int error; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ error = crypto_freesession(cse->sid); ++ if (cse->key) ++ kfree(cse->key); ++ if (cse->mackey) ++ kfree(cse->mackey); ++ kfree(cse); ++ return(error); ++} ++ ++static int ++cryptodev_ioctl( ++ struct inode *inode, ++ struct file *filp, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ struct cryptoini cria, crie; ++ struct fcrypt *fcr = filp->private_data; ++ struct csession *cse; ++ struct csession_info info; ++ struct session2_op sop; ++ struct crypt_op cop; ++ struct crypt_kop kop; ++ struct crypt_find_op fop; ++ u_int64_t sid; ++ u_int32_t ses; ++ int feat, fd, error = 0, crid; ++ mm_segment_t fs; ++ ++ dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg); ++ ++ switch (cmd) { ++ ++ case CRIOGET: { ++ dprintk("%s(CRIOGET)\n", __FUNCTION__); ++ fs = get_fs(); ++ set_fs(get_ds()); ++ for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++) ++ if (files_fdtable(current->files)->fd[fd] == filp) ++ break; ++ fd = sys_dup(fd); ++ set_fs(fs); ++ put_user(fd, (int *) arg); ++ return IS_ERR_VALUE(fd) ? fd : 0; ++ } ++ ++#define CIOCGSESSSTR (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2") ++ case CIOCGSESSION: ++ case CIOCGSESSION2: ++ dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR); ++ memset(&crie, 0, sizeof(crie)); ++ memset(&cria, 0, sizeof(cria)); ++ memset(&info, 0, sizeof(info)); ++ memset(&sop, 0, sizeof(sop)); ++ ++ if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ? ++ sizeof(struct session_op) : sizeof(sop))) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ ++ switch (sop.cipher) { ++ case 0: ++ dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR); ++ break; ++ case CRYPTO_NULL_CBC: ++ info.blocksize = NULL_BLOCK_LEN; ++ info.minkey = NULL_MIN_KEY_LEN; ++ info.maxkey = NULL_MAX_KEY_LEN; ++ break; ++ case CRYPTO_DES_CBC: ++ info.blocksize = DES_BLOCK_LEN; ++ info.minkey = DES_MIN_KEY_LEN; ++ info.maxkey = DES_MAX_KEY_LEN; ++ break; ++ case CRYPTO_3DES_CBC: ++ info.blocksize = DES3_BLOCK_LEN; ++ info.minkey = DES3_MIN_KEY_LEN; ++ info.maxkey = DES3_MAX_KEY_LEN; ++ break; ++ case CRYPTO_BLF_CBC: ++ info.blocksize = BLOWFISH_BLOCK_LEN; ++ info.minkey = BLOWFISH_MIN_KEY_LEN; ++ info.maxkey = BLOWFISH_MAX_KEY_LEN; ++ break; ++ case CRYPTO_CAST_CBC: ++ info.blocksize = CAST128_BLOCK_LEN; ++ info.minkey = CAST128_MIN_KEY_LEN; ++ info.maxkey = CAST128_MAX_KEY_LEN; ++ break; ++ case CRYPTO_SKIPJACK_CBC: ++ info.blocksize = SKIPJACK_BLOCK_LEN; ++ info.minkey = SKIPJACK_MIN_KEY_LEN; ++ info.maxkey = SKIPJACK_MAX_KEY_LEN; ++ break; ++ case CRYPTO_AES_CBC: ++ info.blocksize = AES_BLOCK_LEN; ++ info.minkey = AES_MIN_KEY_LEN; ++ info.maxkey = AES_MAX_KEY_LEN; ++ break; ++ case CRYPTO_ARC4: ++ info.blocksize = ARC4_BLOCK_LEN; ++ info.minkey = ARC4_MIN_KEY_LEN; ++ info.maxkey = ARC4_MAX_KEY_LEN; ++ break; ++ case CRYPTO_CAMELLIA_CBC: ++ info.blocksize = CAMELLIA_BLOCK_LEN; ++ info.minkey = CAMELLIA_MIN_KEY_LEN; ++ info.maxkey = CAMELLIA_MAX_KEY_LEN; ++ break; ++ default: ++ dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ switch (sop.mac) { ++ case 0: ++ dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR); ++ break; ++ case CRYPTO_NULL_HMAC: ++ info.authsize = NULL_HASH_LEN; ++ break; ++ case CRYPTO_MD5: ++ info.authsize = MD5_HASH_LEN; ++ break; ++ case CRYPTO_SHA1: ++ info.authsize = SHA1_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_256: ++ info.authsize = SHA2_256_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_384: ++ info.authsize = SHA2_384_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_512: ++ info.authsize = SHA2_512_HASH_LEN; ++ break; ++ case CRYPTO_RIPEMD160: ++ info.authsize = RIPEMD160_HASH_LEN; ++ break; ++ case CRYPTO_MD5_HMAC: ++ info.authsize = MD5_HASH_LEN; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ info.authsize = SHA1_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_256_HMAC: ++ info.authsize = SHA2_256_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_384_HMAC: ++ info.authsize = SHA2_384_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_512_HMAC: ++ info.authsize = SHA2_512_HASH_LEN; ++ break; ++ case CRYPTO_RIPEMD160_HMAC: ++ info.authsize = RIPEMD160_HASH_LEN; ++ break; ++ default: ++ dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ if (info.blocksize) { ++ crie.cri_alg = sop.cipher; ++ crie.cri_klen = sop.keylen * 8; ++ if ((info.maxkey && sop.keylen > info.maxkey) || ++ sop.keylen < info.minkey) { ++ dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL); ++ if (copy_from_user(crie.cri_key, sop.key, ++ crie.cri_klen/8)) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ if (info.authsize) ++ crie.cri_next = &cria; ++ } ++ ++ if (info.authsize) { ++ cria.cri_alg = sop.mac; ++ cria.cri_klen = sop.mackeylen * 8; ++ if ((info.maxkey && sop.mackeylen > info.maxkey) || ++ sop.keylen < info.minkey) { ++ dprintk("%s(%s) - mackeylen %d\n", __FUNCTION__, CIOCGSESSSTR, ++ sop.mackeylen); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ if (cria.cri_klen) { ++ cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL); ++ if (copy_from_user(cria.cri_key, sop.mackey, ++ cria.cri_klen / 8)) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ } ++ } ++ ++ /* NB: CIOGSESSION2 has the crid */ ++ if (cmd == CIOCGSESSION2) { ++ crid = sop.crid; ++ error = checkcrid(crid); ++ if (error) { ++ dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__, ++ CIOCGSESSSTR, error); ++ goto bail; ++ } ++ } else { ++ /* allow either HW or SW to be used */ ++ crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; ++ } ++ error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid); ++ if (error) { ++ dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error); ++ goto bail; ++ } ++ ++ cse = csecreate(fcr, sid, &crie, &cria, &info); ++ if (cse == NULL) { ++ crypto_freesession(sid); ++ error = EINVAL; ++ dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR); ++ goto bail; ++ } ++ sop.ses = cse->ses; ++ ++ if (cmd == CIOCGSESSION2) { ++ /* return hardware/driver id */ ++ sop.crid = CRYPTO_SESID2HID(cse->sid); ++ } ++ ++ if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ? ++ sizeof(struct session_op) : sizeof(sop))) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ } ++bail: ++ if (error) { ++ dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error); ++ if (crie.cri_key) ++ kfree(crie.cri_key); ++ if (cria.cri_key) ++ kfree(cria.cri_key); ++ } ++ break; ++ case CIOCFSESSION: ++ dprintk("%s(CIOCFSESSION)\n", __FUNCTION__); ++ get_user(ses, (uint32_t*)arg); ++ cse = csefind(fcr, ses); ++ if (cse == NULL) { ++ error = EINVAL; ++ dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error); ++ break; ++ } ++ csedelete(fcr, cse); ++ error = csefree(cse); ++ break; ++ case CIOCCRYPT: ++ dprintk("%s(CIOCCRYPT)\n", __FUNCTION__); ++ if(copy_from_user(&cop, (void*)arg, sizeof(cop))) { ++ dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ cse = csefind(fcr, cop.ses); ++ if (cse == NULL) { ++ error = EINVAL; ++ dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error); ++ break; ++ } ++ error = cryptodev_op(cse, &cop); ++ if(copy_to_user((void*)arg, &cop, sizeof(cop))) { ++ dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ case CIOCKEY: ++ case CIOCKEY2: ++ dprintk("%s(CIOCKEY)\n", __FUNCTION__); ++ if (!crypto_userasymcrypto) ++ return (EPERM); /* XXX compat? */ ++ if(copy_from_user(&kop, (void*)arg, sizeof(kop))) { ++ dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ if (cmd == CIOCKEY) { ++ /* NB: crypto core enforces s/w driver use */ ++ kop.crk_crid = ++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; ++ } ++ error = cryptodev_key(&kop); ++ if(copy_to_user((void*)arg, &kop, sizeof(kop))) { ++ dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ case CIOCASYMFEAT: ++ dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__); ++ if (!crypto_userasymcrypto) { ++ /* ++ * NB: if user asym crypto operations are ++ * not permitted return "no algorithms" ++ * so well-behaved applications will just ++ * fallback to doing them in software. ++ */ ++ feat = 0; ++ } else ++ error = crypto_getfeat(&feat); ++ if (!error) { ++ error = copy_to_user((void*)arg, &feat, sizeof(feat)); ++ } ++ break; ++ case CIOCFINDDEV: ++ if (copy_from_user(&fop, (void*)arg, sizeof(fop))) { ++ dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ error = cryptodev_find(&fop); ++ if (copy_to_user((void*)arg, &fop, sizeof(fop))) { ++ dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ default: ++ dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd); ++ error = EINVAL; ++ break; ++ } ++ return(-error); ++} ++ ++#ifdef HAVE_UNLOCKED_IOCTL ++static long ++cryptodev_unlocked_ioctl( ++ struct file *filp, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ return cryptodev_ioctl(NULL, filp, cmd, arg); ++} ++#endif ++ ++static int ++cryptodev_open(struct inode *inode, struct file *filp) ++{ ++ struct fcrypt *fcr; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (filp->private_data) { ++ printk("cryptodev: Private data already exists !\n"); ++ return(0); ++ } ++ ++ fcr = kmalloc(sizeof(*fcr), GFP_KERNEL); ++ if (!fcr) { ++ dprintk("%s() - malloc failed\n", __FUNCTION__); ++ return(-ENOMEM); ++ } ++ memset(fcr, 0, sizeof(*fcr)); ++ ++ INIT_LIST_HEAD(&fcr->csessions); ++ filp->private_data = fcr; ++ return(0); ++} ++ ++static int ++cryptodev_release(struct inode *inode, struct file *filp) ++{ ++ struct fcrypt *fcr = filp->private_data; ++ struct csession *cse, *tmp; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (!filp) { ++ printk("cryptodev: No private data on release\n"); ++ return(0); ++ } ++ ++ list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) { ++ list_del(&cse->list); ++ (void)csefree(cse); ++ } ++ filp->private_data = NULL; ++ kfree(fcr); ++ return(0); ++} ++ ++static struct file_operations cryptodev_fops = { ++ .owner = THIS_MODULE, ++ .open = cryptodev_open, ++ .release = cryptodev_release, ++ .ioctl = cryptodev_ioctl, ++#ifdef HAVE_UNLOCKED_IOCTL ++ .unlocked_ioctl = cryptodev_unlocked_ioctl, ++#endif ++}; ++ ++static struct miscdevice cryptodev = { ++ .minor = CRYPTODEV_MINOR, ++ .name = "crypto", ++ .fops = &cryptodev_fops, ++}; ++ ++static int __init ++cryptodev_init(void) ++{ ++ int rc; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init); ++ rc = misc_register(&cryptodev); ++ if (rc) { ++ printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n"); ++ return(rc); ++ } ++ ++ return(0); ++} ++ ++static void __exit ++cryptodev_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ misc_deregister(&cryptodev); ++} ++ ++module_init(cryptodev_init); ++module_exit(cryptodev_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Cryptodev (user interface to OCF)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptodev.h linux-2.6.30/crypto/ocf/cryptodev.h +--- linux-2.6.30.orig/crypto/ocf/cryptodev.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptodev.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,478 @@ ++/* $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $ */ ++/* $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $ */ ++ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting ++ * ++ * This code was written by Angelos D. Keromytis in Athens, Greece, in ++ * February 2000. Network Security Technologies Inc. (NSTI) kindly ++ * supported the development of this code. ++ * ++ * Copyright (c) 2000 Angelos D. Keromytis ++ * ++ * Permission to use, copy, and modify this software with or without fee ++ * is hereby granted, provided that this entire notice is included in ++ * all source code copies of any software which is or includes a copy or ++ * modification of this software. ++ * ++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY ++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE ++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR ++ * PURPOSE. ++ * ++ * Copyright (c) 2001 Theo de Raadt ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++ ++#ifndef _CRYPTO_CRYPTO_H_ ++#define _CRYPTO_CRYPTO_H_ ++ ++/* Some initial values */ ++#define CRYPTO_DRIVERS_INITIAL 4 ++#define CRYPTO_SW_SESSIONS 32 ++ ++/* Hash values */ ++#define NULL_HASH_LEN 0 ++#define MD5_HASH_LEN 16 ++#define SHA1_HASH_LEN 20 ++#define RIPEMD160_HASH_LEN 20 ++#define SHA2_256_HASH_LEN 32 ++#define SHA2_384_HASH_LEN 48 ++#define SHA2_512_HASH_LEN 64 ++#define MD5_KPDK_HASH_LEN 16 ++#define SHA1_KPDK_HASH_LEN 20 ++/* Maximum hash algorithm result length */ ++#define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */ ++ ++/* HMAC values */ ++#define NULL_HMAC_BLOCK_LEN 1 ++#define MD5_HMAC_BLOCK_LEN 64 ++#define SHA1_HMAC_BLOCK_LEN 64 ++#define RIPEMD160_HMAC_BLOCK_LEN 64 ++#define SHA2_256_HMAC_BLOCK_LEN 64 ++#define SHA2_384_HMAC_BLOCK_LEN 128 ++#define SHA2_512_HMAC_BLOCK_LEN 128 ++/* Maximum HMAC block length */ ++#define HMAC_MAX_BLOCK_LEN SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */ ++#define HMAC_IPAD_VAL 0x36 ++#define HMAC_OPAD_VAL 0x5C ++ ++/* Encryption algorithm block sizes */ ++#define NULL_BLOCK_LEN 1 ++#define DES_BLOCK_LEN 8 ++#define DES3_BLOCK_LEN 8 ++#define BLOWFISH_BLOCK_LEN 8 ++#define SKIPJACK_BLOCK_LEN 8 ++#define CAST128_BLOCK_LEN 8 ++#define RIJNDAEL128_BLOCK_LEN 16 ++#define AES_BLOCK_LEN RIJNDAEL128_BLOCK_LEN ++#define CAMELLIA_BLOCK_LEN 16 ++#define ARC4_BLOCK_LEN 1 ++#define EALG_MAX_BLOCK_LEN AES_BLOCK_LEN /* Keep this updated */ ++ ++/* Encryption algorithm min and max key sizes */ ++#define NULL_MIN_KEY_LEN 0 ++#define NULL_MAX_KEY_LEN 0 ++#define DES_MIN_KEY_LEN 8 ++#define DES_MAX_KEY_LEN 8 ++#define DES3_MIN_KEY_LEN 24 ++#define DES3_MAX_KEY_LEN 24 ++#define BLOWFISH_MIN_KEY_LEN 4 ++#define BLOWFISH_MAX_KEY_LEN 56 ++#define SKIPJACK_MIN_KEY_LEN 10 ++#define SKIPJACK_MAX_KEY_LEN 10 ++#define CAST128_MIN_KEY_LEN 5 ++#define CAST128_MAX_KEY_LEN 16 ++#define RIJNDAEL128_MIN_KEY_LEN 16 ++#define RIJNDAEL128_MAX_KEY_LEN 32 ++#define AES_MIN_KEY_LEN RIJNDAEL128_MIN_KEY_LEN ++#define AES_MAX_KEY_LEN RIJNDAEL128_MAX_KEY_LEN ++#define CAMELLIA_MIN_KEY_LEN 16 ++#define CAMELLIA_MAX_KEY_LEN 32 ++#define ARC4_MIN_KEY_LEN 1 ++#define ARC4_MAX_KEY_LEN 256 ++ ++/* Max size of data that can be processed */ ++#define CRYPTO_MAX_DATA_LEN 64*1024 - 1 ++ ++#define CRYPTO_ALGORITHM_MIN 1 ++#define CRYPTO_DES_CBC 1 ++#define CRYPTO_3DES_CBC 2 ++#define CRYPTO_BLF_CBC 3 ++#define CRYPTO_CAST_CBC 4 ++#define CRYPTO_SKIPJACK_CBC 5 ++#define CRYPTO_MD5_HMAC 6 ++#define CRYPTO_SHA1_HMAC 7 ++#define CRYPTO_RIPEMD160_HMAC 8 ++#define CRYPTO_MD5_KPDK 9 ++#define CRYPTO_SHA1_KPDK 10 ++#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */ ++#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */ ++#define CRYPTO_ARC4 12 ++#define CRYPTO_MD5 13 ++#define CRYPTO_SHA1 14 ++#define CRYPTO_NULL_HMAC 15 ++#define CRYPTO_NULL_CBC 16 ++#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression algorithm */ ++#define CRYPTO_SHA2_256_HMAC 18 ++#define CRYPTO_SHA2_384_HMAC 19 ++#define CRYPTO_SHA2_512_HMAC 20 ++#define CRYPTO_CAMELLIA_CBC 21 ++#define CRYPTO_SHA2_256 22 ++#define CRYPTO_SHA2_384 23 ++#define CRYPTO_SHA2_512 24 ++#define CRYPTO_RIPEMD160 25 ++#define CRYPTO_ALGORITHM_MAX 25 /* Keep updated - see below */ ++ ++/* Algorithm flags */ ++#define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ ++#define CRYPTO_ALG_FLAG_RNG_ENABLE 0x02 /* Has HW RNG for DH/DSA */ ++#define CRYPTO_ALG_FLAG_DSA_SHA 0x04 /* Can do SHA on msg */ ++ ++/* ++ * Crypto driver/device flags. They can set in the crid ++ * parameter when creating a session or submitting a key ++ * op to affect the device/driver assigned. If neither ++ * of these are specified then the crid is assumed to hold ++ * the driver id of an existing (and suitable) device that ++ * must be used to satisfy the request. ++ */ ++#define CRYPTO_FLAG_HARDWARE 0x01000000 /* hardware accelerated */ ++#define CRYPTO_FLAG_SOFTWARE 0x02000000 /* software implementation */ ++ ++/* NB: deprecated */ ++struct session_op { ++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ ++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ ++ ++ u_int32_t keylen; /* cipher key */ ++ caddr_t key; ++ int mackeylen; /* mac key */ ++ caddr_t mackey; ++ ++ u_int32_t ses; /* returns: session # */ ++}; ++ ++struct session2_op { ++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ ++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ ++ ++ u_int32_t keylen; /* cipher key */ ++ caddr_t key; ++ int mackeylen; /* mac key */ ++ caddr_t mackey; ++ ++ u_int32_t ses; /* returns: session # */ ++ int crid; /* driver id + flags (rw) */ ++ int pad[4]; /* for future expansion */ ++}; ++ ++struct crypt_op { ++ u_int32_t ses; ++ u_int16_t op; /* i.e. COP_ENCRYPT */ ++#define COP_NONE 0 ++#define COP_ENCRYPT 1 ++#define COP_DECRYPT 2 ++ u_int16_t flags; ++#define COP_F_BATCH 0x0008 /* Batch op if possible */ ++ u_int len; ++ caddr_t src, dst; /* become iov[] inside kernel */ ++ caddr_t mac; /* must be big enough for chosen MAC */ ++ caddr_t iv; ++}; ++ ++/* ++ * Parameters for looking up a crypto driver/device by ++ * device name or by id. The latter are returned for ++ * created sessions (crid) and completed key operations. ++ */ ++struct crypt_find_op { ++ int crid; /* driver id + flags */ ++ char name[32]; /* device/driver name */ ++}; ++ ++/* bignum parameter, in packed bytes, ... */ ++struct crparam { ++ caddr_t crp_p; ++ u_int crp_nbits; ++}; ++ ++#define CRK_MAXPARAM 8 ++ ++struct crypt_kop { ++ u_int crk_op; /* ie. CRK_MOD_EXP or other */ ++ u_int crk_status; /* return status */ ++ u_short crk_iparams; /* # of input parameters */ ++ u_short crk_oparams; /* # of output parameters */ ++ u_int crk_crid; /* NB: only used by CIOCKEY2 (rw) */ ++ struct crparam crk_param[CRK_MAXPARAM]; ++}; ++#define CRK_ALGORITM_MIN 0 ++#define CRK_MOD_EXP 0 ++#define CRK_MOD_EXP_CRT 1 ++#define CRK_DSA_SIGN 2 ++#define CRK_DSA_VERIFY 3 ++#define CRK_DH_COMPUTE_KEY 4 ++#define CRK_ALGORITHM_MAX 4 /* Keep updated - see below */ ++ ++#define CRF_MOD_EXP (1 << CRK_MOD_EXP) ++#define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT) ++#define CRF_DSA_SIGN (1 << CRK_DSA_SIGN) ++#define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY) ++#define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY) ++ ++/* ++ * done against open of /dev/crypto, to get a cloned descriptor. ++ * Please use F_SETFD against the cloned descriptor. ++ */ ++#define CRIOGET _IOWR('c', 100, u_int32_t) ++#define CRIOASYMFEAT CIOCASYMFEAT ++#define CRIOFINDDEV CIOCFINDDEV ++ ++/* the following are done against the cloned descriptor */ ++#define CIOCGSESSION _IOWR('c', 101, struct session_op) ++#define CIOCFSESSION _IOW('c', 102, u_int32_t) ++#define CIOCCRYPT _IOWR('c', 103, struct crypt_op) ++#define CIOCKEY _IOWR('c', 104, struct crypt_kop) ++#define CIOCASYMFEAT _IOR('c', 105, u_int32_t) ++#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op) ++#define CIOCKEY2 _IOWR('c', 107, struct crypt_kop) ++#define CIOCFINDDEV _IOWR('c', 108, struct crypt_find_op) ++ ++struct cryptotstat { ++ struct timespec acc; /* total accumulated time */ ++ struct timespec min; /* min time */ ++ struct timespec max; /* max time */ ++ u_int32_t count; /* number of observations */ ++}; ++ ++struct cryptostats { ++ u_int32_t cs_ops; /* symmetric crypto ops submitted */ ++ u_int32_t cs_errs; /* symmetric crypto ops that failed */ ++ u_int32_t cs_kops; /* asymetric/key ops submitted */ ++ u_int32_t cs_kerrs; /* asymetric/key ops that failed */ ++ u_int32_t cs_intrs; /* crypto swi thread activations */ ++ u_int32_t cs_rets; /* crypto return thread activations */ ++ u_int32_t cs_blocks; /* symmetric op driver block */ ++ u_int32_t cs_kblocks; /* symmetric op driver block */ ++ /* ++ * When CRYPTO_TIMING is defined at compile time and the ++ * sysctl debug.crypto is set to 1, the crypto system will ++ * accumulate statistics about how long it takes to process ++ * crypto requests at various points during processing. ++ */ ++ struct cryptotstat cs_invoke; /* crypto_dipsatch -> crypto_invoke */ ++ struct cryptotstat cs_done; /* crypto_invoke -> crypto_done */ ++ struct cryptotstat cs_cb; /* crypto_done -> callback */ ++ struct cryptotstat cs_finis; /* callback -> callback return */ ++ ++ u_int32_t cs_drops; /* crypto ops dropped due to congestion */ ++}; ++ ++#ifdef __KERNEL__ ++ ++/* Standard initialization structure beginning */ ++struct cryptoini { ++ int cri_alg; /* Algorithm to use */ ++ int cri_klen; /* Key length, in bits */ ++ int cri_mlen; /* Number of bytes we want from the ++ entire hash. 0 means all. */ ++ caddr_t cri_key; /* key to use */ ++ u_int8_t cri_iv[EALG_MAX_BLOCK_LEN]; /* IV to use */ ++ struct cryptoini *cri_next; ++}; ++ ++/* Describe boundaries of a single crypto operation */ ++struct cryptodesc { ++ int crd_skip; /* How many bytes to ignore from start */ ++ int crd_len; /* How many bytes to process */ ++ int crd_inject; /* Where to inject results, if applicable */ ++ int crd_flags; ++ ++#define CRD_F_ENCRYPT 0x01 /* Set when doing encryption */ ++#define CRD_F_IV_PRESENT 0x02 /* When encrypting, IV is already in ++ place, so don't copy. */ ++#define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */ ++#define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */ ++#define CRD_F_KEY_EXPLICIT 0x10 /* Key explicitly provided */ ++#define CRD_F_COMP 0x0f /* Set when doing compression */ ++ ++ struct cryptoini CRD_INI; /* Initialization/context data */ ++#define crd_iv CRD_INI.cri_iv ++#define crd_key CRD_INI.cri_key ++#define crd_alg CRD_INI.cri_alg ++#define crd_klen CRD_INI.cri_klen ++ ++ struct cryptodesc *crd_next; ++}; ++ ++/* Structure describing complete operation */ ++struct cryptop { ++ struct list_head crp_next; ++ wait_queue_head_t crp_waitq; ++ ++ u_int64_t crp_sid; /* Session ID */ ++ int crp_ilen; /* Input data total length */ ++ int crp_olen; /* Result total length */ ++ ++ int crp_etype; /* ++ * Error type (zero means no error). ++ * All error codes except EAGAIN ++ * indicate possible data corruption (as in, ++ * the data have been touched). On all ++ * errors, the crp_sid may have changed ++ * (reset to a new one), so the caller ++ * should always check and use the new ++ * value on future requests. ++ */ ++ int crp_flags; ++ ++#define CRYPTO_F_SKBUF 0x0001 /* Input/output are skbuf chains */ ++#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ ++#define CRYPTO_F_REL 0x0004 /* Must return data in same place */ ++#define CRYPTO_F_BATCH 0x0008 /* Batch op if possible */ ++#define CRYPTO_F_CBIMM 0x0010 /* Do callback immediately */ ++#define CRYPTO_F_DONE 0x0020 /* Operation completed */ ++#define CRYPTO_F_CBIFSYNC 0x0040 /* Do CBIMM if op is synchronous */ ++ ++ caddr_t crp_buf; /* Data to be processed */ ++ caddr_t crp_opaque; /* Opaque pointer, passed along */ ++ struct cryptodesc *crp_desc; /* Linked list of processing descriptors */ ++ ++ int (*crp_callback)(struct cryptop *); /* Callback function */ ++}; ++ ++#define CRYPTO_BUF_CONTIG 0x0 ++#define CRYPTO_BUF_IOV 0x1 ++#define CRYPTO_BUF_SKBUF 0x2 ++ ++#define CRYPTO_OP_DECRYPT 0x0 ++#define CRYPTO_OP_ENCRYPT 0x1 ++ ++/* ++ * Hints passed to process methods. ++ */ ++#define CRYPTO_HINT_MORE 0x1 /* more ops coming shortly */ ++ ++struct cryptkop { ++ struct list_head krp_next; ++ wait_queue_head_t krp_waitq; ++ ++ int krp_flags; ++#define CRYPTO_KF_DONE 0x0001 /* Operation completed */ ++#define CRYPTO_KF_CBIMM 0x0002 /* Do callback immediately */ ++ ++ u_int krp_op; /* ie. CRK_MOD_EXP or other */ ++ u_int krp_status; /* return status */ ++ u_short krp_iparams; /* # of input parameters */ ++ u_short krp_oparams; /* # of output parameters */ ++ u_int krp_crid; /* desired device, etc. */ ++ u_int32_t krp_hid; ++ struct crparam krp_param[CRK_MAXPARAM]; /* kvm */ ++ int (*krp_callback)(struct cryptkop *); ++}; ++ ++#include ++ ++/* ++ * Session ids are 64 bits. The lower 32 bits contain a "local id" which ++ * is a driver-private session identifier. The upper 32 bits contain a ++ * "hardware id" used by the core crypto code to identify the driver and ++ * a copy of the driver's capabilities that can be used by client code to ++ * optimize operation. ++ */ ++#define CRYPTO_SESID2HID(_sid) (((_sid) >> 32) & 0x00ffffff) ++#define CRYPTO_SESID2CAPS(_sid) (((_sid) >> 32) & 0xff000000) ++#define CRYPTO_SESID2LID(_sid) (((u_int32_t) (_sid)) & 0xffffffff) ++ ++extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard); ++extern int crypto_freesession(u_int64_t sid); ++#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE ++#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE ++#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */ ++extern int32_t crypto_get_driverid(device_t dev, int flags); ++extern int crypto_find_driver(const char *); ++extern device_t crypto_find_device_byhid(int hid); ++extern int crypto_getcaps(int hid); ++extern int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, ++ u_int32_t flags); ++extern int crypto_kregister(u_int32_t, int, u_int32_t); ++extern int crypto_unregister(u_int32_t driverid, int alg); ++extern int crypto_unregister_all(u_int32_t driverid); ++extern int crypto_dispatch(struct cryptop *crp); ++extern int crypto_kdispatch(struct cryptkop *); ++#define CRYPTO_SYMQ 0x1 ++#define CRYPTO_ASYMQ 0x2 ++extern int crypto_unblock(u_int32_t, int); ++extern void crypto_done(struct cryptop *crp); ++extern void crypto_kdone(struct cryptkop *); ++extern int crypto_getfeat(int *); ++ ++extern void crypto_freereq(struct cryptop *crp); ++extern struct cryptop *crypto_getreq(int num); ++ ++extern int crypto_usercrypto; /* userland may do crypto requests */ ++extern int crypto_userasymcrypto; /* userland may do asym crypto reqs */ ++extern int crypto_devallowsoft; /* only use hardware crypto */ ++ ++/* ++ * random number support, crypto_unregister_all will unregister ++ */ ++extern int crypto_rregister(u_int32_t driverid, ++ int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg); ++extern int crypto_runregister_all(u_int32_t driverid); ++ ++/* ++ * Crypto-related utility routines used mainly by drivers. ++ * ++ * XXX these don't really belong here; but for now they're ++ * kept apart from the rest of the system. ++ */ ++struct uio; ++extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp); ++extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp); ++extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off); ++ ++extern void crypto_copyback(int flags, caddr_t buf, int off, int size, ++ caddr_t in); ++extern void crypto_copydata(int flags, caddr_t buf, int off, int size, ++ caddr_t out); ++extern int crypto_apply(int flags, caddr_t buf, int off, int len, ++ int (*f)(void *, void *, u_int), void *arg); ++ ++#endif /* __KERNEL__ */ ++#endif /* _CRYPTO_CRYPTO_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptosoft.c linux-2.6.30/crypto/ocf/cryptosoft.c +--- linux-2.6.30.orig/crypto/ocf/cryptosoft.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptosoft.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,898 @@ ++/* ++ * An OCF module that uses the linux kernel cryptoapi, based on the ++ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * but is mostly unrecognisable, ++ * ++ * Written by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ * --------------------------------------------------------------------------- ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct { ++ softc_device_decl sc_dev; ++} swcr_softc; ++ ++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) ++ ++/* Software session entry */ ++ ++#define SW_TYPE_CIPHER 0 ++#define SW_TYPE_HMAC 1 ++#define SW_TYPE_AUTH2 2 ++#define SW_TYPE_HASH 3 ++#define SW_TYPE_COMP 4 ++#define SW_TYPE_BLKCIPHER 5 ++ ++struct swcr_data { ++ int sw_type; ++ int sw_alg; ++ struct crypto_tfm *sw_tfm; ++ union { ++ struct { ++ char *sw_key; ++ int sw_klen; ++ int sw_mlen; ++ } hmac; ++ void *sw_comp_buf; ++ } u; ++ struct swcr_data *sw_next; ++}; ++ ++#ifndef CRYPTO_TFM_MODE_CBC ++/* ++ * As of linux-2.6.21 this is no longer defined, and presumably no longer ++ * needed to be passed into the crypto core code. ++ */ ++#define CRYPTO_TFM_MODE_CBC 0 ++#define CRYPTO_TFM_MODE_ECB 0 ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ /* ++ * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new ++ * API into old API. ++ */ ++ ++ /* Symmetric/Block Cipher */ ++ struct blkcipher_desc ++ { ++ struct crypto_tfm *tfm; ++ void *info; ++ }; ++ #define ecb(X) #X ++ #define cbc(X) #X ++ #define crypto_has_blkcipher(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_blkcipher_cast(X) X ++ #define crypto_blkcipher_tfm(X) X ++ #define crypto_alloc_blkcipher(X, Y, Z) crypto_alloc_tfm(X, mode) ++ #define crypto_blkcipher_ivsize(X) crypto_tfm_alg_ivsize(X) ++ #define crypto_blkcipher_blocksize(X) crypto_tfm_alg_blocksize(X) ++ #define crypto_blkcipher_setkey(X, Y, Z) crypto_cipher_setkey(X, Y, Z) ++ #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \ ++ crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) ++ #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \ ++ crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) ++ ++ /* Hash/HMAC/Digest */ ++ struct hash_desc ++ { ++ struct crypto_tfm *tfm; ++ }; ++ #define hmac(X) #X ++ #define crypto_has_hash(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_hash_cast(X) X ++ #define crypto_hash_tfm(X) X ++ #define crypto_alloc_hash(X, Y, Z) crypto_alloc_tfm(X, mode) ++ #define crypto_hash_digestsize(X) crypto_tfm_alg_digestsize(X) ++ #define crypto_hash_digest(W, X, Y, Z) \ ++ crypto_digest_digest((W)->tfm, X, sg_num, Z) ++ ++ /* Asymmetric Cipher */ ++ #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0) ++ ++ /* Compression */ ++ #define crypto_has_comp(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_comp_tfm(X) X ++ #define crypto_comp_cast(X) X ++ #define crypto_alloc_comp(X, Y, Z) crypto_alloc_tfm(X, mode) ++#else ++ #define ecb(X) "ecb(" #X ")" ++ #define cbc(X) "cbc(" #X ")" ++ #define hmac(X) "hmac(" #X ")" ++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ ++ ++struct crypto_details ++{ ++ char *alg_name; ++ int mode; ++ int sw_type; ++}; ++ ++/* ++ * This needs to be kept updated with CRYPTO_xxx list (cryptodev.h). ++ * If the Algorithm is not supported, then insert a {NULL, 0, 0} entry. ++ * ++ * IMPORTANT: The index to the array IS CRYPTO_xxx. ++ */ ++static struct crypto_details crypto_details[CRYPTO_ALGORITHM_MAX + 1] = { ++ { NULL, 0, 0 }, ++ /* CRYPTO_xxx index starts at 1 */ ++ { cbc(des), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(des3_ede), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(blowfish), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(cast5), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(skipjack), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { hmac(md5), 0, SW_TYPE_HMAC }, ++ { hmac(sha1), 0, SW_TYPE_HMAC }, ++ { hmac(ripemd160), 0, SW_TYPE_HMAC }, ++ { "md5-kpdk??", 0, SW_TYPE_HASH }, ++ { "sha1-kpdk??", 0, SW_TYPE_HASH }, ++ { cbc(aes), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { ecb(arc4), CRYPTO_TFM_MODE_ECB, SW_TYPE_BLKCIPHER }, ++ { "md5", 0, SW_TYPE_HASH }, ++ { "sha1", 0, SW_TYPE_HASH }, ++ { hmac(digest_null), 0, SW_TYPE_HMAC }, ++ { cbc(cipher_null), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { "deflate", 0, SW_TYPE_COMP }, ++ { hmac(sha256), 0, SW_TYPE_HMAC }, ++ { hmac(sha384), 0, SW_TYPE_HMAC }, ++ { hmac(sha512), 0, SW_TYPE_HMAC }, ++ { cbc(camellia), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { "sha256", 0, SW_TYPE_HASH }, ++ { "sha384", 0, SW_TYPE_HASH }, ++ { "sha512", 0, SW_TYPE_HASH }, ++ { "ripemd160", 0, SW_TYPE_HASH }, ++}; ++ ++int32_t swcr_id = -1; ++module_param(swcr_id, int, 0444); ++MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver"); ++ ++int swcr_fail_if_compression_grows = 1; ++module_param(swcr_fail_if_compression_grows, int, 0644); ++MODULE_PARM_DESC(swcr_fail_if_compression_grows, ++ "Treat compression that results in more data as a failure"); ++ ++static struct swcr_data **swcr_sessions = NULL; ++static u_int32_t swcr_sesnum = 0; ++ ++static int swcr_process(device_t, struct cryptop *, int); ++static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int swcr_freesession(device_t, u_int64_t); ++ ++static device_method_t swcr_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, swcr_newsession), ++ DEVMETHOD(cryptodev_freesession,swcr_freesession), ++ DEVMETHOD(cryptodev_process, swcr_process), ++}; ++ ++#define debug swcr_debug ++int swcr_debug = 0; ++module_param(swcr_debug, int, 0644); ++MODULE_PARM_DESC(swcr_debug, "Enable debug"); ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) ++{ ++ struct swcr_data **swd; ++ u_int32_t i; ++ int error; ++ char *algo; ++ int mode, sw_type; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (swcr_sessions) { ++ for (i = 1; i < swcr_sesnum; i++) ++ if (swcr_sessions[i] == NULL) ++ break; ++ } else ++ i = 1; /* NB: to silence compiler warning */ ++ ++ if (swcr_sessions == NULL || i == swcr_sesnum) { ++ if (swcr_sessions == NULL) { ++ i = 1; /* We leave swcr_sessions[0] empty */ ++ swcr_sesnum = CRYPTO_SW_SESSIONS; ++ } else ++ swcr_sesnum *= 2; ++ ++ swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC); ++ if (swd == NULL) { ++ /* Reset session number */ ++ if (swcr_sesnum == CRYPTO_SW_SESSIONS) ++ swcr_sesnum = 0; ++ else ++ swcr_sesnum /= 2; ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *)); ++ ++ /* Copy existing sessions */ ++ if (swcr_sessions) { ++ memcpy(swd, swcr_sessions, ++ (swcr_sesnum / 2) * sizeof(struct swcr_data *)); ++ kfree(swcr_sessions); ++ } ++ ++ swcr_sessions = swd; ++ } ++ ++ swd = &swcr_sessions[i]; ++ *sid = i; ++ ++ while (cri) { ++ *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data), ++ SLAB_ATOMIC); ++ if (*swd == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(*swd, 0, sizeof(struct swcr_data)); ++ ++ if (cri->cri_alg > CRYPTO_ALGORITHM_MAX) { ++ printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ algo = crypto_details[cri->cri_alg].alg_name; ++ if (!algo || !*algo) { ++ printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ mode = crypto_details[cri->cri_alg].mode; ++ sw_type = crypto_details[cri->cri_alg].sw_type; ++ ++ /* Algorithm specific configuration */ ++ switch (cri->cri_alg) { ++ case CRYPTO_NULL_CBC: ++ cri->cri_klen = 0; /* make it work with crypto API */ ++ break; ++ default: ++ break; ++ } ++ ++ if (sw_type == SW_TYPE_BLKCIPHER) { ++ dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__, ++ algo, mode); ++ ++ (*swd)->sw_tfm = crypto_blkcipher_tfm( ++ crypto_alloc_blkcipher(algo, 0, ++ CRYPTO_ALG_ASYNC)); ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n", ++ algo,mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ if (debug) { ++ dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d", ++ __FUNCTION__,cri->cri_klen,(cri->cri_klen + 7)/8); ++ for (i = 0; i < (cri->cri_klen + 7) / 8; i++) ++ { ++ dprintk("%s0x%x", (i % 8) ? " " : "\n ",cri->cri_key[i]); ++ } ++ dprintk("\n"); ++ } ++ error = crypto_blkcipher_setkey( ++ crypto_blkcipher_cast((*swd)->sw_tfm), cri->cri_key, ++ (cri->cri_klen + 7) / 8); ++ if (error) { ++ printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error, ++ (*swd)->sw_tfm->crt_flags); ++ swcr_freesession(NULL, i); ++ return error; ++ } ++ } else if (sw_type == SW_TYPE_HMAC || sw_type == SW_TYPE_HASH) { ++ dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__, ++ algo, mode); ++ ++ (*swd)->sw_tfm = crypto_hash_tfm( ++ crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC)); ++ ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n", ++ algo, mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8; ++ (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen, ++ SLAB_ATOMIC); ++ if ((*swd)->u.hmac.sw_key == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen); ++ if (cri->cri_mlen) { ++ (*swd)->u.hmac.sw_mlen = cri->cri_mlen; ++ } else { ++ (*swd)->u.hmac.sw_mlen = ++ crypto_hash_digestsize( ++ crypto_hash_cast((*swd)->sw_tfm)); ++ } ++ } else if (sw_type == SW_TYPE_COMP) { ++ (*swd)->sw_tfm = crypto_comp_tfm( ++ crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC)); ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n", ++ algo, mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC); ++ if ((*swd)->u.sw_comp_buf == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ } else { ++ printk("cryptosoft: Unhandled sw_type %d\n", sw_type); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ (*swd)->sw_alg = cri->cri_alg; ++ (*swd)->sw_type = sw_type; ++ ++ cri = cri->cri_next; ++ swd = &((*swd)->sw_next); ++ } ++ return 0; ++} ++ ++/* ++ * Free a session. ++ */ ++static int ++swcr_freesession(device_t dev, u_int64_t tid) ++{ ++ struct swcr_data *swd; ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > swcr_sesnum || swcr_sessions == NULL || ++ swcr_sessions[sid] == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return(EINVAL); ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return(0); ++ ++ while ((swd = swcr_sessions[sid]) != NULL) { ++ swcr_sessions[sid] = swd->sw_next; ++ if (swd->sw_tfm) ++ crypto_free_tfm(swd->sw_tfm); ++ if (swd->sw_type == SW_TYPE_COMP) { ++ if (swd->u.sw_comp_buf) ++ kfree(swd->u.sw_comp_buf); ++ } else { ++ if (swd->u.hmac.sw_key) ++ kfree(swd->u.hmac.sw_key); ++ } ++ kfree(swd); ++ } ++ return 0; ++} ++ ++/* ++ * Process a software request. ++ */ ++static int ++swcr_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct cryptodesc *crd; ++ struct swcr_data *sw; ++ u_int32_t lid; ++#define SCATTERLIST_MAX 16 ++ struct scatterlist sg[SCATTERLIST_MAX]; ++ int sg_num, sg_len, skip; ++ struct sk_buff *skb = NULL; ++ struct uio *uiop = NULL; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL || ++ swcr_sessions[lid] == NULL) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ /* ++ * do some error checking outside of the loop for SKB and IOV processing ++ * this leaves us with valid skb or uiop pointers for later ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ skb = (struct sk_buff *) crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) { ++ printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__, ++ skb_shinfo(skb)->nr_frags); ++ goto done; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ uiop = (struct uio *) crp->crp_buf; ++ if (uiop->uio_iovcnt > SCATTERLIST_MAX) { ++ printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__, ++ uiop->uio_iovcnt); ++ goto done; ++ } ++ } ++ ++ /* Go through crypto descriptors, processing as we go */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ /* ++ * Find the crypto context. ++ * ++ * XXX Note that the logic here prevents us from having ++ * XXX the same algorithm multiple times in a session ++ * XXX (or rather, we can but it won't give us the right ++ * XXX results). To do that, we'd need some way of differentiating ++ * XXX between the various instances of an algorithm (so we can ++ * XXX locate the correct crypto context). ++ */ ++ for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg; ++ sw = sw->sw_next) ++ ; ++ ++ /* No such context ? */ ++ if (sw == NULL) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ skip = crd->crd_skip; ++ ++ /* ++ * setup the SG list skip from the start of the buffer ++ */ ++ memset(sg, 0, sizeof(sg)); ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ int i, len; ++ ++ sg_num = 0; ++ sg_len = 0; ++ ++ if (skip < skb_headlen(skb)) { ++ len = skb_headlen(skb) - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ virt_to_page(skb->data + skip), len, ++ offset_in_page(skb->data + skip)); ++ sg_len += len; ++ sg_num++; ++ skip = 0; ++ } else ++ skip -= skb_headlen(skb); ++ ++ for (i = 0; sg_len < crd->crd_len && ++ i < skb_shinfo(skb)->nr_frags && ++ sg_num < SCATTERLIST_MAX; i++) { ++ if (skip < skb_shinfo(skb)->frags[i].size) { ++ len = skb_shinfo(skb)->frags[i].size - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ skb_shinfo(skb)->frags[i].page, ++ len, ++ skb_shinfo(skb)->frags[i].page_offset + skip); ++ sg_len += len; ++ sg_num++; ++ skip = 0; ++ } else ++ skip -= skb_shinfo(skb)->frags[i].size; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ int len; ++ ++ sg_len = 0; ++ for (sg_num = 0; sg_len <= crd->crd_len && ++ sg_num < uiop->uio_iovcnt && ++ sg_num < SCATTERLIST_MAX; sg_num++) { ++ if (skip <= uiop->uio_iov[sg_num].iov_len) { ++ len = uiop->uio_iov[sg_num].iov_len - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ virt_to_page(uiop->uio_iov[sg_num].iov_base+skip), ++ len, ++ offset_in_page(uiop->uio_iov[sg_num].iov_base+skip)); ++ sg_len += len; ++ skip = 0; ++ } else ++ skip -= uiop->uio_iov[sg_num].iov_len; ++ } ++ } else { ++ sg_len = (crp->crp_ilen - skip); ++ if (sg_len > crd->crd_len) ++ sg_len = crd->crd_len; ++ sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip), ++ sg_len, offset_in_page(crp->crp_buf + skip)); ++ sg_num = 1; ++ } ++ ++ ++ switch (sw->sw_type) { ++ case SW_TYPE_BLKCIPHER: { ++ unsigned char iv[EALG_MAX_BLOCK_LEN]; ++ unsigned char *ivp = iv; ++ int ivsize = ++ crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm)); ++ struct blkcipher_desc desc; ++ ++ if (sg_len < crypto_blkcipher_blocksize( ++ crypto_blkcipher_cast(sw->sw_tfm))) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__, ++ sg_len, crypto_blkcipher_blocksize( ++ crypto_blkcipher_cast(sw->sw_tfm))); ++ goto done; ++ } ++ ++ if (ivsize > sizeof(iv)) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ int i, error; ++ ++ if (debug) { ++ dprintk("%s key:", __FUNCTION__); ++ for (i = 0; i < (crd->crd_klen + 7) / 8; i++) ++ dprintk("%s0x%x", (i % 8) ? " " : "\n ", ++ crd->crd_key[i]); ++ dprintk("\n"); ++ } ++ error = crypto_blkcipher_setkey( ++ crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key, ++ (crd->crd_klen + 7) / 8); ++ if (error) { ++ dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", ++ error, sw->sw_tfm->crt_flags); ++ crp->crp_etype = -error; ++ } ++ } ++ ++ memset(&desc, 0, sizeof(desc)); ++ desc.tfm = crypto_blkcipher_cast(sw->sw_tfm); ++ ++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ ++ ++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { ++ ivp = crd->crd_iv; ++ } else { ++ get_random_bytes(ivp, ivsize); ++ } ++ /* ++ * do we have to copy the IV back to the buffer ? ++ */ ++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ivsize, (caddr_t)ivp); ++ } ++ desc.info = ivp; ++ crypto_blkcipher_encrypt_iv(&desc, sg, sg, sg_len); ++ ++ } else { /*decrypt */ ++ ++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { ++ ivp = crd->crd_iv; ++ } else { ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ivsize, (caddr_t)ivp); ++ } ++ desc.info = ivp; ++ crypto_blkcipher_decrypt_iv(&desc, sg, sg, sg_len); ++ } ++ } break; ++ case SW_TYPE_HMAC: ++ case SW_TYPE_HASH: ++ { ++ char result[HASH_MAX_LEN]; ++ struct hash_desc desc; ++ ++ /* check we have room for the result */ ++ if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) { ++ dprintk( ++ "cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d digestsize=%d\n", ++ crp->crp_ilen, crd->crd_skip + sg_len, crd->crd_inject, ++ sw->u.hmac.sw_mlen); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ memset(&desc, 0, sizeof(desc)); ++ desc.tfm = crypto_hash_cast(sw->sw_tfm); ++ ++ memset(result, 0, sizeof(result)); ++ ++ if (sw->sw_type == SW_TYPE_HMAC) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen, ++ sg, sg_num, result); ++#else ++ crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key, ++ sw->u.hmac.sw_klen); ++ crypto_hash_digest(&desc, sg, sg_len, result); ++#endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ ++ ++ } else { /* SW_TYPE_HASH */ ++ crypto_hash_digest(&desc, sg, sg_len, result); ++ } ++ ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, sw->u.hmac.sw_mlen, result); ++ } ++ break; ++ ++ case SW_TYPE_COMP: { ++ void *ibuf = NULL; ++ void *obuf = sw->u.sw_comp_buf; ++ int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN; ++ int ret = 0; ++ ++ /* ++ * we need to use an additional copy if there is more than one ++ * input chunk since the kernel comp routines do not handle ++ * SG yet. Otherwise we just use the input buffer as is. ++ * Rather than allocate another buffer we just split the tmp ++ * buffer we already have. ++ * Perhaps we should just use zlib directly ? ++ */ ++ if (sg_num > 1) { ++ int blk; ++ ++ ibuf = obuf; ++ for (blk = 0; blk < sg_num; blk++) { ++ memcpy(obuf, sg_virt(&sg[blk]), ++ sg[blk].length); ++ obuf += sg[blk].length; ++ } ++ olen -= sg_len; ++ } else ++ ibuf = sg_virt(&sg[0]); ++ ++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */ ++ ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm), ++ ibuf, ilen, obuf, &olen); ++ if (!ret && olen > crd->crd_len) { ++ dprintk("cryptosoft: ERANGE compress %d into %d\n", ++ crd->crd_len, olen); ++ if (swcr_fail_if_compression_grows) ++ ret = ERANGE; ++ } ++ } else { /* decompress */ ++ ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm), ++ ibuf, ilen, obuf, &olen); ++ if (!ret && (olen + crd->crd_inject) > crp->crp_olen) { ++ dprintk("cryptosoft: ETOOSMALL decompress %d into %d, " ++ "space for %d,at offset %d\n", ++ crd->crd_len, olen, crp->crp_olen, crd->crd_inject); ++ ret = ETOOSMALL; ++ } ++ } ++ if (ret) ++ dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret); ++ ++ /* ++ * on success copy result back, ++ * linux crpyto API returns -errno, we need to fix that ++ */ ++ crp->crp_etype = ret < 0 ? -ret : ret; ++ if (ret == 0) { ++ /* copy back the result and return it's size */ ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, olen, obuf); ++ crp->crp_olen = olen; ++ } ++ ++ ++ } break; ++ ++ default: ++ /* Unknown/unsupported algorithm */ ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ } ++ ++done: ++ crypto_done(crp); ++ return 0; ++} ++ ++static int ++cryptosoft_init(void) ++{ ++ int i, sw_type, mode; ++ char *algo; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init); ++ ++ softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods); ++ ++ swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc), ++ CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC); ++ if (swcr_id < 0) { ++ printk("Software crypto device cannot initialize!"); ++ return -ENODEV; ++ } ++ ++#define REGISTER(alg) \ ++ crypto_register(swcr_id, alg, 0,0); ++ ++ for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; ++i) ++ { ++ ++ algo = crypto_details[i].alg_name; ++ if (!algo || !*algo) ++ { ++ dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i); ++ continue; ++ } ++ ++ mode = crypto_details[i].mode; ++ sw_type = crypto_details[i].sw_type; ++ ++ switch (sw_type) ++ { ++ case SW_TYPE_CIPHER: ++ if (crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:CIPHER algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_HMAC: ++ if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:HMAC algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_HASH: ++ if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:HASH algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_COMP: ++ if (crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:COMP algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_BLKCIPHER: ++ if (crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ default: ++ dprintk( ++ "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n", ++ __FUNCTION__, sw_type, i, algo); ++ break; ++ } ++ } ++ ++ return(0); ++} ++ ++static void ++cryptosoft_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(swcr_id); ++ swcr_id = -1; ++} ++ ++module_init(cryptosoft_init); ++module_exit(cryptosoft_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_asym.c linux-2.6.30/crypto/ocf/ep80579/icp_asym.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_asym.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_asym.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1375 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++#include "icp_ocf.h" ++ ++/*The following define values (containing the word 'INDEX') are used to find ++the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h). ++These values were found through analysis of the OCF OpenSSL patch. If the ++calling program uses different input buffer positions, these defines will have ++to be changed.*/ ++ ++/*DIFFIE HELLMAN buffer index values*/ ++#define ICP_DH_KRP_PARAM_PRIME_INDEX (0) ++#define ICP_DH_KRP_PARAM_BASE_INDEX (1) ++#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX (2) ++#define ICP_DH_KRP_PARAM_RESULT_INDEX (3) ++ ++/*MOD EXP buffer index values*/ ++#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX (0) ++#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX (1) ++#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX (2) ++#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX (3) ++ ++#define SINGLE_BYTE_VALUE (4) ++ ++/*MOD EXP CRT buffer index values*/ ++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX (0) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX (1) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX (2) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX (3) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX (4) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX (5) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX (6) ++ ++/*DSA sign buffer index values*/ ++#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX (0) ++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX (1) ++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX (2) ++#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX (3) ++#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX (4) ++#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX (5) ++#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX (6) ++ ++/*DSA verify buffer index values*/ ++#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX (0) ++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX (1) ++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX (2) ++#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX (3) ++#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX (4) ++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX (5) ++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX (6) ++ ++/*DSA sign prime Q vs random number K size check values*/ ++#define DONT_RUN_LESS_THAN_CHECK (0) ++#define FAIL_A_IS_GREATER_THAN_B (1) ++#define FAIL_A_IS_EQUAL_TO_B (1) ++#define SUCCESS_A_IS_LESS_THAN_B (0) ++#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS (500) ++ ++/* We need to set a cryptokp success value just in case it is set or allocated ++ and not set to zero outside of this module */ ++#define CRYPTO_OP_SUCCESS (0) ++ ++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp); ++ ++static int icp_ocfDrvModExp(struct cryptkop *krp); ++ ++static int icp_ocfDrvModExpCRT(struct cryptkop *krp); ++ ++static int ++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck); ++ ++static int icp_ocfDrvDsaSign(struct cryptkop *krp); ++ ++static int icp_ocfDrvDsaVerify(struct cryptkop *krp); ++ ++static void ++icp_ocfDrvDhP1CallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV); ++ ++static void ++icp_ocfDrvModExpCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pResult); ++ ++static void ++icp_ocfDrvModExpCRTCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pOutputData); ++ ++static void ++icp_ocfDrvDsaVerifyCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaBoolean verifyStatus); ++ ++static void ++icp_ocfDrvDsaRSSignCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, ++ CpaBoolean protocolStatus, ++ CpaFlatBuffer * pR, CpaFlatBuffer * pS); ++ ++/* Name : icp_ocfDrvPkeProcess ++ * ++ * Description : This function will choose which PKE process to follow ++ * based on the input arguments ++ */ ++int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ ++ if (NULL == krp) { ++ DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n", ++ __FUNCTION__, krp); ++ return EINVAL; ++ } ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ switch (krp->krp_op) { ++ case CRK_DH_COMPUTE_KEY: ++ DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDHComputeKey(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDHComputeKey failed " ++ "(%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_MOD_EXP: ++ DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvModExp(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_MOD_EXP_CRT: ++ DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvModExpCRT(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvModExpCRT " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_DSA_SIGN: ++ DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDsaSign(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDsaSign " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_DSA_VERIFY: ++ DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDsaVerify(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDsaVerify " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ default: ++ EPRINTK("%s(): Asymettric function not " ++ "supported (%d).\n", __FUNCTION__, krp->krp_op); ++ krp->krp_status = EOPNOTSUPP; ++ return EOPNOTSUPP; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvSwapBytes ++ * ++ * Description : This function is used to swap the byte order of a buffer. ++ * It has been seen that in general we are passed little endian byte order ++ * buffers, but LAC only accepts big endian byte order buffers. ++ */ ++static void inline ++icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes) ++{ ++ ++ int i; ++ u_int8_t *end_ptr; ++ u_int8_t hold_val; ++ ++ end_ptr = num + (buff_len_bytes - 1); ++ buff_len_bytes = buff_len_bytes >> 1; ++ for (i = 0; i < buff_len_bytes; i++) { ++ hold_val = *num; ++ *num = *end_ptr; ++ num++; ++ *end_ptr = hold_val; ++ end_ptr--; ++ } ++} ++ ++/* Name : icp_ocfDrvDHComputeKey ++ * ++ * Description : This function will map Diffie Hellman calls from OCF ++ * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and ++ * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases ++ * break down to a modular exponentiation. ++ */ ++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ void *callbackTag = NULL; ++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; ++ CpaFlatBuffer *pLocalOctetStringPV = NULL; ++ uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0; ++ ++ /* Input checks - check prime is a multiple of 8 bits to allow for ++ allocation later */ ++ dh_prime_len_bits = ++ (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits); ++ ++ /* LAC can reject prime lengths based on prime key sizes, we just ++ need to make sure we can allocate space for the base and ++ exponent buffers correctly */ ++ if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) { ++ APRINTK("%s(): Warning Prime number buffer size is not a " ++ "multiple of 8 bits\n", __FUNCTION__); ++ } ++ ++ /* Result storage space should be the same size as the prime as this ++ value can take up the same amount of storage space */ ++ if (dh_prime_len_bits != ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) { ++ DPRINTK("%s(): Return Buffer must be the same size " ++ "as the Prime buffer\n", __FUNCTION__); ++ krp->krp_status = EINVAL; ++ return EINVAL; ++ } ++ /* Switch to size in bytes */ ++ BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits); ++ ++ callbackTag = krp; ++ ++ pPhase1OpData = kmem_cache_zalloc(drvDH_zone, GFP_KERNEL); ++ if (NULL == pPhase1OpData) { ++ APRINTK("%s():Failed to get memory for key gen data\n", ++ __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pLocalOctetStringPV = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pLocalOctetStringPV) { ++ APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n", ++ __FUNCTION__); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ pPhase1OpData->primeP.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p; ++ ++ pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes; ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes); ++ ++ pPhase1OpData->baseG.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData, ++ pPhase1OpData->baseG.dataLenInBytes); ++ ++ pPhase1OpData->privateValueX.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData, ++ pPhase1OpData->privateValueX.dataLenInBytes); ++ ++ /* Output parameters */ ++ pLocalOctetStringPV->pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits); ++ ++ lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDhP1CallBack, ++ callbackTag, pPhase1OpData, ++ pLocalOctetStringPV); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvModExp ++ * ++ * Description : This function will map ordinary Modular Exponentiation calls ++ * from OCF to the LAC API. ++ * ++ */ ++static int icp_ocfDrvModExp(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ void *callbackTag = NULL; ++ CpaCyLnModExpOpData *pModExpOpData = NULL; ++ CpaFlatBuffer *pResult = NULL; ++ ++ if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits % ++ NUM_BITS_IN_BYTE) != 0) { ++ DPRINTK("%s(): Warning - modulus buffer size (%d) is not a " ++ "multiple of 8 bits\n", __FUNCTION__, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. ++ crp_nbits); ++ } ++ ++ /* Result storage space should be the same size as the prime as this ++ value can take up the same amount of storage space */ ++ if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits > ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) { ++ APRINTK("%s(): Return Buffer size must be the same or" ++ " greater than the Modulus buffer\n", __FUNCTION__); ++ krp->krp_status = EINVAL; ++ return EINVAL; ++ } ++ ++ callbackTag = krp; ++ ++ pModExpOpData = kmem_cache_zalloc(drvLnModExp_zone, GFP_KERNEL); ++ if (NULL == pModExpOpData) { ++ APRINTK("%s():Failed to get memory for key gen data\n", ++ __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pResult = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pResult) { ++ APRINTK("%s():Failed to get memory for ModExp result\n", ++ __FUNCTION__); ++ kmem_cache_free(drvLnModExp_zone, pModExpOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ pModExpOpData->modulus.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData, ++ pModExpOpData->modulus.dataLenInBytes); ++ ++ /*OCF patch to Openswan Pluto regularly sends the base value as 2 ++ bits in size. In this case, it has been found it is better to ++ use the base size memory space as the input buffer (if the number ++ is in bits is less than a byte, the number of bits is the input ++ value) */ ++ if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits < ++ NUM_BITS_IN_BYTE) { ++ DPRINTK("%s : base is small (%d)\n", __FUNCTION__, krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); ++ pModExpOpData->base.dataLenInBytes = SINGLE_BYTE_VALUE; ++ pModExpOpData->base.pData = ++ (uint8_t *) & (krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits); ++ *((uint32_t *) pModExpOpData->base.pData) = ++ htonl(*((uint32_t *) pModExpOpData->base.pData)); ++ ++ } else { ++ ++ DPRINTK("%s : base is big (%d)\n", __FUNCTION__, krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); ++ pModExpOpData->base.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(pModExpOpData->base.pData, ++ pModExpOpData->base.dataLenInBytes); ++ } ++ ++ pModExpOpData->exponent.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData, ++ pModExpOpData->exponent.dataLenInBytes); ++ /* Output parameters */ ++ pResult->pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p, ++ BITS_TO_BYTES(pResult->dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvModExpCallBack, ++ callbackTag, pModExpOpData, pResult); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): Mod Exp Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pResult); ++ kmem_cache_free(drvLnModExp_zone, pModExpOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvModExpCRT ++ * ++ * Description : This function will map ordinary Modular Exponentiation Chinese ++ * Remainder Theorem implementaion calls from OCF to the LAC API. ++ * ++ * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2 ++ * decrypt operation. Therefore P and Q input values must always be prime ++ * numbers. Although basic primality checks are done in LAC, it is up to the ++ * user to do any correct prime number checking before passing the inputs. ++ */ ++ ++static int icp_ocfDrvModExpCRT(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL; ++ void *callbackTag = NULL; ++ CpaFlatBuffer *pOutputData = NULL; ++ ++ /*Parameter input checks are all done by LAC, no need to repeat ++ them here. */ ++ callbackTag = krp; ++ ++ rsaDecryptOpData = kmem_cache_zalloc(drvRSADecrypt_zone, GFP_KERNEL); ++ if (NULL == rsaDecryptOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for MOD EXP CRT Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey ++ = kmem_cache_zalloc(drvRSAPrivateKey_zone, GFP_KERNEL); ++ if (NULL == rsaDecryptOpData->pRecipientPrivateKey) { ++ APRINTK("%s():Failed to get memory for MOD EXP CRT" ++ " private key values struct\n", __FUNCTION__); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ version = CPA_CY_RSA_VERSION_TWO_PRIME; ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; ++ ++ pOutputData = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pOutputData) { ++ APRINTK("%s():Failed to get memory" ++ " for MOD EXP CRT output data\n", __FUNCTION__); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ rsaDecryptOpData->pRecipientPrivateKey); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ version = CPA_CY_RSA_VERSION_TWO_PRIME; ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; ++ ++ /* Link parameters */ ++ rsaDecryptOpData->inputData.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData, ++ rsaDecryptOpData->inputData.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ prime1P.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime1P.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime1P.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ prime2Q.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime2Q.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime2Q.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ exponent1Dp.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.dataLenInBytes); ++ ++ /* Output Parameter */ ++ pOutputData->pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pOutputData->dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvModExpCRTCallBack, ++ callbackTag, rsaDecryptOpData, pOutputData); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pOutputData); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ rsaDecryptOpData->pRecipientPrivateKey); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvCheckALessThanB ++ * ++ * Description : This function will check whether the first argument is less ++ * than the second. It is used to check whether the DSA RS sign Random K ++ * value is less than the Prime Q value (as defined in the specification) ++ * ++ */ ++static int ++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck) ++{ ++ ++ uint8_t *MSB_K = pK->pData; ++ uint8_t *MSB_Q = pQ->pData; ++ uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes; ++ ++ if (DONT_RUN_LESS_THAN_CHECK == *doCheck) { ++ return FAIL_A_IS_GREATER_THAN_B; ++ } ++ ++/*Check MSBs ++if A == B, check next MSB ++if A > B, return A_IS_GREATER_THAN_B ++if A < B, return A_IS_LESS_THAN_B (success) ++*/ ++ while (*MSB_K == *MSB_Q) { ++ MSB_K++; ++ MSB_Q++; ++ ++ buffer_lengths_in_bytes--; ++ if (0 == buffer_lengths_in_bytes) { ++ DPRINTK("%s() Buffers have equal value!!\n", ++ __FUNCTION__); ++ return FAIL_A_IS_EQUAL_TO_B; ++ } ++ ++ } ++ ++ if (*MSB_K < *MSB_Q) { ++ return SUCCESS_A_IS_LESS_THAN_B; ++ } else { ++ return FAIL_A_IS_GREATER_THAN_B; ++ } ++ ++} ++ ++/* Name : icp_ocfDrvDsaSign ++ * ++ * Description : This function will map DSA RS Sign from OCF to the LAC API. ++ * ++ * NOTE: From looking at OCF patch to OpenSSL and even the number of input ++ * parameters, OCF expects us to generate the random seed value. This value ++ * is generated and passed to LAC, however the number is discared in the ++ * callback and not returned to the user. ++ */ ++static int icp_ocfDrvDsaSign(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL; ++ void *callbackTag = NULL; ++ CpaCyRandGenOpData randGenOpData; ++ int primeQSizeInBytes = 0; ++ int doCheck = 0; ++ CpaFlatBuffer randData; ++ CpaBoolean protocolStatus = CPA_FALSE; ++ CpaFlatBuffer *pR = NULL; ++ CpaFlatBuffer *pS = NULL; ++ ++ callbackTag = krp; ++ ++ BITS_TO_BYTES(primeQSizeInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) { ++ APRINTK("%s(): DSA PRIME Q size not equal to the " ++ "FIPS defined 20bytes, = %d\n", ++ __FUNCTION__, primeQSizeInBytes); ++ krp->krp_status = EDOM; ++ return EDOM; ++ } ++ ++ dsaRsSignOpData = kmem_cache_zalloc(drvDSARSSign_zone, GFP_KERNEL); ++ if (NULL == dsaRsSignOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA RS Sign Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ dsaRsSignOpData->K.pData = ++ kmem_cache_alloc(drvDSARSSignKValue_zone, GFP_ATOMIC); ++ ++ if (NULL == dsaRsSignOpData->K.pData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA RS Sign Op Random value\n", __FUNCTION__); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pR = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pR) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA signature R\n", __FUNCTION__); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pS = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pS) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA signature S\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /*link prime number parameter for ease of processing */ ++ dsaRsSignOpData->P.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData, ++ dsaRsSignOpData->P.dataLenInBytes); ++ ++ dsaRsSignOpData->Q.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData, ++ dsaRsSignOpData->Q.dataLenInBytes); ++ ++ /*generate random number with equal buffer size to Prime value Q, ++ but value less than Q */ ++ dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes; ++ ++ randGenOpData.generateBits = CPA_TRUE; ++ randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes; ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData, ++ dsaRsSignOpData->K.dataLenInBytes, ++ &randData); ++ ++ doCheck = 0; ++ while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K), ++ &(dsaRsSignOpData->Q), &doCheck)) { ++ ++ if (CPA_STATUS_SUCCESS ++ != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, &randGenOpData, &randData)) { ++ APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K" ++ "value\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = EAGAIN; ++ return EAGAIN; ++ } ++ ++ doCheck++; ++ if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) { ++ APRINTK("%s(): ERROR - Failed to find DSA RS Sign K " ++ "value less than Q value\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = EAGAIN; ++ return EAGAIN; ++ } ++ ++ } ++ /*Rand Data - no need to swap bytes for pK */ ++ ++ /* Link parameters */ ++ dsaRsSignOpData->G.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData, ++ dsaRsSignOpData->G.dataLenInBytes); ++ ++ dsaRsSignOpData->X.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits); ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData, ++ dsaRsSignOpData->X.dataLenInBytes); ++ ++ dsaRsSignOpData->M.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->M.pData, ++ dsaRsSignOpData->M.dataLenInBytes); ++ ++ /* Output Parameters */ ++ pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pS->dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX]. ++ crp_nbits); ++ ++ pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pR->dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDsaRSSignCallBack, ++ callbackTag, dsaRsSignOpData, ++ &protocolStatus, pR, pS); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvDsaVerify ++ * ++ * Description : This function will map DSA RS Verify from OCF to the LAC API. ++ * ++ */ ++static int icp_ocfDrvDsaVerify(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL; ++ void *callbackTag = NULL; ++ CpaBoolean verifyStatus = CPA_FALSE; ++ ++ callbackTag = krp; ++ ++ dsaVerifyOpData = kmem_cache_zalloc(drvDSAVerify_zone, GFP_KERNEL); ++ if (NULL == dsaVerifyOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA Verify Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ dsaVerifyOpData->P.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData, ++ dsaVerifyOpData->P.dataLenInBytes); ++ ++ dsaVerifyOpData->Q.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData, ++ dsaVerifyOpData->Q.dataLenInBytes); ++ ++ dsaVerifyOpData->G.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData, ++ dsaVerifyOpData->G.dataLenInBytes); ++ ++ dsaVerifyOpData->Y.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData, ++ dsaVerifyOpData->Y.dataLenInBytes); ++ ++ dsaVerifyOpData->M.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->M.pData, ++ dsaVerifyOpData->M.dataLenInBytes); ++ ++ dsaVerifyOpData->R.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData, ++ dsaVerifyOpData->R.dataLenInBytes); ++ ++ dsaVerifyOpData->S.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData, ++ dsaVerifyOpData->S.dataLenInBytes); ++ ++ lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDsaVerifyCallBack, ++ callbackTag, dsaVerifyOpData, &verifyStatus); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DSA Verify Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ kmem_cache_free(drvDSAVerify_zone, dsaVerifyOpData); ++ krp->krp_status = ECANCELED; ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvReadRandom ++ * ++ * Description : This function will map RNG functionality calls from OCF ++ * to the LAC API. ++ */ ++int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyRandGenOpData randGenOpData; ++ CpaFlatBuffer randData; ++ ++ if (NULL == buf) { ++ APRINTK("%s(): Invalid input parameters\n", __FUNCTION__); ++ return EINVAL; ++ } ++ ++ /* maxwords here is number of integers to generate data for */ ++ randGenOpData.generateBits = CPA_TRUE; ++ ++ randGenOpData.lenInBytes = maxwords * sizeof(uint32_t); ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) buf, ++ randGenOpData.lenInBytes, &randData); ++ ++ lacStatus = cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, &randGenOpData, &randData); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_LacSymRandGen failed (%d). \n", ++ __FUNCTION__, lacStatus); ++ return RETURN_RAND_NUM_GEN_FAILED; ++ } ++ ++ return randGenOpData.lenInBytes / sizeof(uint32_t); ++} ++ ++/* Name : icp_ocfDrvDhP1Callback ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DH operation. ++ */ ++static void ++icp_ocfDrvDhP1CallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pPhase1OpData = (CpaCyDhPhase1KeyGenOpData *) pOpData; ++ ++ if (NULL == pLocalOctetStringPV) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "pLocalOctetStringPV Data is NULL\n", __FUNCTION__); ++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): Diffie Hellman Phase1 Key Gen failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pLocalOctetStringPV->pData, ++ pLocalOctetStringPV->dataLenInBytes); ++ ++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); ++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvModExpCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the Mod Exp operation. ++ */ ++static void ++icp_ocfDrvModExpCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpdata, CpaFlatBuffer * pResult) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyLnModExpOpData *pLnModExpOpData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpdata) { ++ DPRINTK("%s(): Invalid Mod Exp input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pLnModExpOpData = (CpaCyLnModExpOpData *) pOpdata; ++ ++ if (NULL == pResult) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "pResult data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); ++ kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): LAC Mod Exp Operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pResult->pData, pResult->dataLenInBytes); ++ ++ /*switch base size value back to original */ ++ if (pLnModExpOpData->base.pData == ++ (uint8_t *) & (krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits)) { ++ *((uint32_t *) pLnModExpOpData->base.pData) = ++ ntohl(*((uint32_t *) pLnModExpOpData->base.pData)); ++ } ++ icp_ocfDrvFreeFlatBuffer(pResult); ++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); ++ kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); ++ ++ crypto_kdone(krp); ++ ++ return; ++ ++} ++ ++/* Name : icp_ocfDrvModExpCRTCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the Mod Exp CRT operation. ++ */ ++static void ++icp_ocfDrvModExpCRTCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pOutputData) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyRsaDecryptOpData *pDecryptData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pDecryptData = (CpaCyRsaDecryptOpData *) pOpData; ++ ++ if (NULL == pOutputData) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pOutputData is NULL\n", __FUNCTION__); ++ memset(pDecryptData->pRecipientPrivateKey, 0, ++ sizeof(CpaCyRsaPrivateKey)); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ pDecryptData->pRecipientPrivateKey); ++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); ++ kmem_cache_free(drvRSADecrypt_zone, pDecryptData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): LAC Mod Exp CRT operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pOutputData->pData, pOutputData->dataLenInBytes); ++ ++ icp_ocfDrvFreeFlatBuffer(pOutputData); ++ memset(pDecryptData->pRecipientPrivateKey, 0, ++ sizeof(CpaCyRsaPrivateKey)); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ pDecryptData->pRecipientPrivateKey); ++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); ++ kmem_cache_free(drvRSADecrypt_zone, pDecryptData); ++ ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvDsaRSSignCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DSA RS sign operation. ++ */ ++static void ++icp_ocfDrvDsaRSSignCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, ++ CpaBoolean protocolStatus, ++ CpaFlatBuffer * pR, CpaFlatBuffer * pS) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyDsaRSSignOpData *pSignData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pSignData = (CpaCyDsaRSSignOpData *) pOpData; ++ ++ if (NULL == pR) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pR sign is NULL\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (NULL == pS) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pS sign is NULL\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS != status) { ++ APRINTK("%s(): LAC DSA RS Sign operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } else { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ ++ if (CPA_TRUE != protocolStatus) { ++ DPRINTK("%s(): LAC DSA RS Sign operation failed due " ++ "to protocol error\n", __FUNCTION__); ++ krp->krp_status = EIO; ++ } ++ } ++ ++ /* Swap bytes only when the callback status is successful and ++ protocolStatus is set to true */ ++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == protocolStatus) { ++ icp_ocfDrvSwapBytes(pR->pData, pR->dataLenInBytes); ++ icp_ocfDrvSwapBytes(pS->pData, pS->dataLenInBytes); ++ } ++ ++ icp_ocfDrvFreeFlatBuffer(pR); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ memset(pSignData->K.pData, 0, pSignData->K.dataLenInBytes); ++ kmem_cache_free(drvDSARSSignKValue_zone, pSignData->K.pData); ++ memset(pSignData, 0, sizeof(CpaCyDsaRSSignOpData)); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvDsaVerifyCallback ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DSA Verify operation. ++ */ ++static void ++icp_ocfDrvDsaVerifyCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaBoolean verifyStatus) ++{ ++ ++ struct cryptkop *krp = NULL; ++ CpaCyDsaVerifyOpData *pVerData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pVerData = (CpaCyDsaVerifyOpData *) pOpData; ++ ++ if (CPA_STATUS_SUCCESS != status) { ++ APRINTK("%s(): LAC DSA Verify operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } else { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ ++ if (CPA_TRUE != verifyStatus) { ++ DPRINTK("%s(): DSA signature invalid\n", __FUNCTION__); ++ krp->krp_status = EIO; ++ } ++ } ++ ++ /* Swap bytes only when the callback status is successful and ++ verifyStatus is set to true */ ++ /*Just swapping back the key values for now. Possibly all ++ swapped buffers need to be reverted */ ++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == verifyStatus) { ++ icp_ocfDrvSwapBytes(pVerData->R.pData, ++ pVerData->R.dataLenInBytes); ++ icp_ocfDrvSwapBytes(pVerData->S.pData, ++ pVerData->S.dataLenInBytes); ++ } ++ ++ memset(pVerData, 0, sizeof(CpaCyDsaVerifyOpData)); ++ kmem_cache_free(drvDSAVerify_zone, pVerData); ++ crypto_kdone(krp); ++ ++ return; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_common.c linux-2.6.30/crypto/ocf/ep80579/icp_common.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_common.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,891 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++/* ++ * An OCF module that uses Intel® QuickAssist Integrated Accelerator to do the ++ * crypto. ++ * ++ * This driver requires the ICP Access Library that is available from Intel in ++ * order to operate. ++ */ ++ ++#include "icp_ocf.h" ++ ++#define ICP_OCF_COMP_NAME "ICP_OCF" ++#define ICP_OCF_VER_MAIN (2) ++#define ICP_OCF_VER_MJR (0) ++#define ICP_OCF_VER_MNR (0) ++ ++#define MAX_DEREG_RETRIES (100) ++#define DEFAULT_DEREG_RETRIES (10) ++#define DEFAULT_DEREG_DELAY_IN_JIFFIES (10) ++ ++/* This defines the maximum number of sessions possible between OCF ++ and the OCF Tolapai Driver. If set to zero, there is no limit. */ ++#define DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT (0) ++#define NUM_SUPPORTED_CAPABILITIES (21) ++ ++/*Slabs zones*/ ++struct kmem_cache *drvSessionData_zone = NULL; ++struct kmem_cache *drvOpData_zone = NULL; ++struct kmem_cache *drvDH_zone = NULL; ++struct kmem_cache *drvLnModExp_zone = NULL; ++struct kmem_cache *drvRSADecrypt_zone = NULL; ++struct kmem_cache *drvRSAPrivateKey_zone = NULL; ++struct kmem_cache *drvDSARSSign_zone = NULL; ++struct kmem_cache *drvDSARSSignKValue_zone = NULL; ++struct kmem_cache *drvDSAVerify_zone = NULL; ++ ++/*Slab zones for flatbuffers and bufferlist*/ ++struct kmem_cache *drvFlatBuffer_zone = NULL; ++ ++static int icp_ocfDrvInit(void); ++static void icp_ocfDrvExit(void); ++static void icp_ocfDrvFreeCaches(void); ++static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg); ++ ++int32_t icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ ++/* Module parameter - gives the number of times LAC deregistration shall be ++ re-tried */ ++int num_dereg_retries = DEFAULT_DEREG_RETRIES; ++ ++/* Module parameter - gives the delay time in jiffies before a LAC session ++ shall be attempted to be deregistered again */ ++int dereg_retry_delay_in_jiffies = DEFAULT_DEREG_DELAY_IN_JIFFIES; ++ ++/* Module parameter - gives the maximum number of sessions possible between ++ OCF and the OCF Tolapai Driver. If set to zero, there is no limit.*/ ++int max_sessions = DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT; ++ ++/* This is set when the module is removed from the system, no further ++ processing can take place if this is set */ ++atomic_t icp_ocfDrvIsExiting = ATOMIC_INIT(0); ++ ++/* This is used to show how many lac sessions were not deregistered*/ ++atomic_t lac_session_failed_dereg_count = ATOMIC_INIT(0); ++ ++/* This is used to track the number of registered sessions between OCF and ++ * and the OCF Tolapai driver, when max_session is set to value other than ++ * zero. This ensures that the max_session set for the OCF and the driver ++ * is equal to the LAC registered sessions */ ++atomic_t num_ocf_to_drv_registered_sessions = ATOMIC_INIT(0); ++ ++/* Head of linked list used to store session data */ ++struct list_head icp_ocfDrvGlobalSymListHead; ++struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; ++ ++spinlock_t icp_ocfDrvSymSessInfoListSpinlock = SPIN_LOCK_UNLOCKED; ++rwlock_t icp_kmem_cache_destroy_alloc_lock = RW_LOCK_UNLOCKED; ++ ++struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; ++ ++struct icp_drvBuffListInfo defBuffListInfo; ++ ++static struct { ++ softc_device_decl sc_dev; ++} icpDev; ++ ++static device_method_t icp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, icp_ocfDrvNewSession), ++ DEVMETHOD(cryptodev_freesession, icp_ocfDrvFreeLACSession), ++ DEVMETHOD(cryptodev_process, icp_ocfDrvSymProcess), ++ DEVMETHOD(cryptodev_kprocess, icp_ocfDrvPkeProcess), ++}; ++ ++module_param(num_dereg_retries, int, S_IRUGO); ++module_param(dereg_retry_delay_in_jiffies, int, S_IRUGO); ++module_param(max_sessions, int, S_IRUGO); ++ ++MODULE_PARM_DESC(num_dereg_retries, ++ "Number of times to retry LAC Sym Session Deregistration. " ++ "Default 10, Max 100"); ++MODULE_PARM_DESC(dereg_retry_delay_in_jiffies, "Delay in jiffies " ++ "(added to a schedule() function call) before a LAC Sym " ++ "Session Dereg is retried. Default 10"); ++MODULE_PARM_DESC(max_sessions, "This sets the maximum number of sessions " ++ "between OCF and this driver. If this value is set to zero, " ++ "max session count checking is disabled. Default is zero(0)"); ++ ++/* Name : icp_ocfDrvInit ++ * ++ * Description : This function will register all the symmetric and asymmetric ++ * functionality that will be accelerated by the hardware. It will also ++ * get a unique driver ID from the OCF and initialise all slab caches ++ */ ++static int __init icp_ocfDrvInit(void) ++{ ++ int ocfStatus = 0; ++ ++ IPRINTK("=== %s ver %d.%d.%d ===\n", ICP_OCF_COMP_NAME, ++ ICP_OCF_VER_MAIN, ICP_OCF_VER_MJR, ICP_OCF_VER_MNR); ++ ++ if (MAX_DEREG_RETRIES < num_dereg_retries) { ++ EPRINTK("Session deregistration retry count set to greater " ++ "than %d", MAX_DEREG_RETRIES); ++ return -1; ++ } ++ ++ /* Initialize and Start the Cryptographic component */ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE)) { ++ EPRINTK("Failed to initialize and start the instance " ++ "of the Cryptographic component.\n"); ++ return -1; ++ } ++ ++ /* Set the default size of BufferList to allocate */ ++ memset(&defBuffListInfo, 0, sizeof(struct icp_drvBuffListInfo)); ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvBufferListMemInfo(ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS, ++ &defBuffListInfo)) { ++ EPRINTK("Failed to get bufferlist memory info.\n"); ++ return -1; ++ } ++ ++ /*Register OCF Tolapai Driver with OCF */ ++ memset(&icpDev, 0, sizeof(icpDev)); ++ softc_device_init(&icpDev, "icp", 0, icp_methods); ++ ++ icp_ocfDrvDriverId = crypto_get_driverid(softc_get_device(&icpDev), ++ CRYPTOCAP_F_HARDWARE); ++ ++ if (icp_ocfDrvDriverId < 0) { ++ EPRINTK("%s : ICP driver failed to register with OCF!\n", ++ __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ /*Create all the slab caches used by the OCF Tolapai Driver */ ++ drvSessionData_zone = ++ ICP_CACHE_CREATE("ICP Session Data", struct icp_drvSessionData); ++ ICP_CACHE_NULL_CHECK(drvSessionData_zone); ++ ++ /* ++ * Allocation of the OpData includes the allocation space for meta data. ++ * The memory after the opData structure is reserved for this meta data. ++ */ ++ drvOpData_zone = ++ kmem_cache_create("ICP Op Data", sizeof(struct icp_drvOpData) + ++ defBuffListInfo.metaSize ,0, SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ++ ++ ICP_CACHE_NULL_CHECK(drvOpData_zone); ++ ++ drvDH_zone = ICP_CACHE_CREATE("ICP DH data", CpaCyDhPhase1KeyGenOpData); ++ ICP_CACHE_NULL_CHECK(drvDH_zone); ++ ++ drvLnModExp_zone = ++ ICP_CACHE_CREATE("ICP ModExp data", CpaCyLnModExpOpData); ++ ICP_CACHE_NULL_CHECK(drvLnModExp_zone); ++ ++ drvRSADecrypt_zone = ++ ICP_CACHE_CREATE("ICP RSA decrypt data", CpaCyRsaDecryptOpData); ++ ICP_CACHE_NULL_CHECK(drvRSADecrypt_zone); ++ ++ drvRSAPrivateKey_zone = ++ ICP_CACHE_CREATE("ICP RSA private key data", CpaCyRsaPrivateKey); ++ ICP_CACHE_NULL_CHECK(drvRSAPrivateKey_zone); ++ ++ drvDSARSSign_zone = ++ ICP_CACHE_CREATE("ICP DSA Sign", CpaCyDsaRSSignOpData); ++ ICP_CACHE_NULL_CHECK(drvDSARSSign_zone); ++ ++ /*too awkward to use a macro here */ ++ drvDSARSSignKValue_zone = ++ kmem_cache_create("ICP DSA Sign Rand Val", ++ DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES, 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ICP_CACHE_NULL_CHECK(drvDSARSSignKValue_zone); ++ ++ drvDSAVerify_zone = ++ ICP_CACHE_CREATE("ICP DSA Verify", CpaCyDsaVerifyOpData); ++ ICP_CACHE_NULL_CHECK(drvDSAVerify_zone); ++ ++ drvFlatBuffer_zone = ++ ICP_CACHE_CREATE("ICP Flat Buffers", CpaFlatBuffer); ++ ICP_CACHE_NULL_CHECK(drvFlatBuffer_zone); ++ ++ /* Register the ICP symmetric crypto support. */ ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_NULL_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_DES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_3DES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_AES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_ARC4); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512_HMAC); ++ ++ /* Register the ICP asymmetric algorithm support */ ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DH_COMPUTE_KEY); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP_CRT); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_SIGN); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_VERIFY); ++ ++ /* Register the ICP random number generator support */ ++ if (OCF_REGISTRATION_STATUS_SUCCESS == ++ crypto_rregister(icp_ocfDrvDriverId, icp_ocfDrvReadRandom, NULL)) { ++ ocfStatus++; ++ } ++ ++ if (OCF_ZERO_FUNCTIONALITY_REGISTERED == ocfStatus) { ++ DPRINTK("%s: Failed to register any device capabilities\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeCaches(); ++ icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ return -ECANCELED; ++ } ++ ++ DPRINTK("%s: Registered %d of %d device capabilities\n", ++ __FUNCTION__, ocfStatus, NUM_SUPPORTED_CAPABILITIES); ++ ++/*Session data linked list used during module exit*/ ++ INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead); ++ INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead_FreeMemList); ++ ++ icp_ocfDrvFreeLacSessionWorkQ = ++ create_singlethread_workqueue("ocfLacDeregWorkQueue"); ++ ++ return 0; ++} ++ ++/* Name : icp_ocfDrvExit ++ * ++ * Description : This function will deregister all the symmetric sessions ++ * registered with the LAC component. It will also deregister all symmetric ++ * and asymmetric functionality that can be accelerated by the hardware via OCF ++ * and random number generation if it is enabled. ++ */ ++static void icp_ocfDrvExit(void) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ struct icp_drvSessionData *sessionData = NULL; ++ struct icp_drvSessionData *tempSessionData = NULL; ++ int i, remaining_delay_time_in_jiffies = 0; ++ /* There is a possibility of a process or new session command being */ ++ /* sent before this variable is incremented. The aim of this variable */ ++ /* is to stop a loop of calls creating a deadlock situation which */ ++ /* would prevent the driver from exiting. */ ++ ++ atomic_inc(&icp_ocfDrvIsExiting); ++ ++ /*Existing sessions will be routed to another driver after these calls */ ++ crypto_unregister_all(icp_ocfDrvDriverId); ++ crypto_runregister_all(icp_ocfDrvDriverId); ++ ++ /*If any sessions are waiting to be deregistered, do that. This also ++ flushes the work queue */ ++ destroy_workqueue(icp_ocfDrvFreeLacSessionWorkQ); ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ list_for_each_entry_safe(tempSessionData, sessionData, ++ &icp_ocfDrvGlobalSymListHead, listNode) { ++ for (i = 0; i < num_dereg_retries; i++) { ++ /*No harm if bad input - LAC will handle error cases */ ++ if (ICP_SESSION_RUNNING == tempSessionData->inUse) { ++ lacStatus = ++ cpaCySymRemoveSession ++ (CPA_INSTANCE_HANDLE_SINGLE, ++ tempSessionData->sessHandle); ++ if (CPA_STATUS_SUCCESS == lacStatus) { ++ /* Succesfully deregistered */ ++ break; ++ } else if (CPA_STATUS_RETRY != lacStatus) { ++ atomic_inc ++ (&lac_session_failed_dereg_count); ++ break; ++ } ++ ++ /*schedule_timout returns the time left for completion if ++ * this task is set to TASK_INTERRUPTIBLE */ ++ remaining_delay_time_in_jiffies = ++ dereg_retry_delay_in_jiffies; ++ while (0 > remaining_delay_time_in_jiffies) { ++ remaining_delay_time_in_jiffies = ++ schedule_timeout ++ (remaining_delay_time_in_jiffies); ++ } ++ ++ DPRINTK ++ ("%s(): Retry %d to deregistrate the session\n", ++ __FUNCTION__, i); ++ } ++ } ++ ++ /*remove from current list */ ++ list_del(&(tempSessionData->listNode)); ++ /*add to free mem linked list */ ++ list_add(&(tempSessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead_FreeMemList); ++ ++ } ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ /*set back to initial values */ ++ sessionData = NULL; ++ /*still have a reference in our list! */ ++ tempSessionData = NULL; ++ /*free memory */ ++ list_for_each_entry_safe(tempSessionData, sessionData, ++ &icp_ocfDrvGlobalSymListHead_FreeMemList, ++ listNode) { ++ ++ list_del(&(tempSessionData->listNode)); ++ /* Free allocated CpaCySymSessionCtx */ ++ if (NULL != tempSessionData->sessHandle) { ++ kfree(tempSessionData->sessHandle); ++ } ++ memset(tempSessionData, 0, sizeof(struct icp_drvSessionData)); ++ kmem_cache_free(drvSessionData_zone, tempSessionData); ++ } ++ ++ if (0 != atomic_read(&lac_session_failed_dereg_count)) { ++ DPRINTK("%s(): %d LAC sessions were not deregistered " ++ "correctly. This is not a clean exit! \n", ++ __FUNCTION__, ++ atomic_read(&lac_session_failed_dereg_count)); ++ } ++ ++ icp_ocfDrvFreeCaches(); ++ icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ ++ /* Shutdown the Cryptographic component */ ++ lacStatus = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ DPRINTK("%s(): Failed to stop instance of the " ++ "Cryptographic component.(status == %d)\n", ++ __FUNCTION__, lacStatus); ++ } ++ ++} ++ ++/* Name : icp_ocfDrvFreeCaches ++ * ++ * Description : This function deregisters all slab caches ++ */ ++static void icp_ocfDrvFreeCaches(void) ++{ ++ if (atomic_read(&icp_ocfDrvIsExiting) != CPA_TRUE) { ++ atomic_set(&icp_ocfDrvIsExiting, 1); ++ } ++ ++ /*Sym Zones */ ++ ICP_CACHE_DESTROY(drvSessionData_zone); ++ ICP_CACHE_DESTROY(drvOpData_zone); ++ ++ /*Asym zones */ ++ ICP_CACHE_DESTROY(drvDH_zone); ++ ICP_CACHE_DESTROY(drvLnModExp_zone); ++ ICP_CACHE_DESTROY(drvRSADecrypt_zone); ++ ICP_CACHE_DESTROY(drvRSAPrivateKey_zone); ++ ICP_CACHE_DESTROY(drvDSARSSignKValue_zone); ++ ICP_CACHE_DESTROY(drvDSARSSign_zone); ++ ICP_CACHE_DESTROY(drvDSAVerify_zone); ++ ++ /*FlatBuffer and BufferList Zones */ ++ ICP_CACHE_DESTROY(drvFlatBuffer_zone); ++ ++} ++ ++/* Name : icp_ocfDrvDeregRetry ++ * ++ * Description : This function will try to farm the session deregistration ++ * off to a work queue. If it fails, nothing more can be done and it ++ * returns an error ++ */ ++ ++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister) ++{ ++ struct icp_ocfDrvFreeLacSession *workstore = NULL; ++ ++ DPRINTK("%s(): Retry - Deregistering session (%p)\n", ++ __FUNCTION__, sessionToDeregister); ++ ++ /*make sure the session is not available to be allocated during this ++ process */ ++ atomic_inc(&lac_session_failed_dereg_count); ++ ++ /*Farm off to work queue */ ++ workstore = ++ kmalloc(sizeof(struct icp_ocfDrvFreeLacSession), GFP_ATOMIC); ++ if (NULL == workstore) { ++ DPRINTK("%s(): unable to free session - no memory available " ++ "for work queue\n", __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ workstore->sessionToDeregister = sessionToDeregister; ++ ++ INIT_WORK(&(workstore->work), icp_ocfDrvDeferedFreeLacSessionProcess, ++ workstore); ++ queue_work(icp_ocfDrvFreeLacSessionWorkQ, &(workstore->work)); ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ ++} ++ ++/* Name : icp_ocfDrvDeferedFreeLacSessionProcess ++ * ++ * Description : This function will retry (module input parameter) ++ * 'num_dereg_retries' times to deregister any symmetric session that recieves a ++ * CPA_STATUS_RETRY message from the LAC component. This function is run in ++ * Thread context because it is called from a worker thread ++ */ ++static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg) ++{ ++ struct icp_ocfDrvFreeLacSession *workstore = NULL; ++ CpaCySymSessionCtx sessionToDeregister = NULL; ++ int i = 0; ++ int remaining_delay_time_in_jiffies = 0; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ ++ workstore = (struct icp_ocfDrvFreeLacSession *)arg; ++ if (NULL == workstore) { ++ DPRINTK("%s() function called with null parameter \n", ++ __FUNCTION__); ++ return; ++ } ++ ++ sessionToDeregister = workstore->sessionToDeregister; ++ kfree(workstore); ++ ++ /*if exiting, give deregistration one more blast only */ ++ if (atomic_read(&icp_ocfDrvIsExiting) == CPA_TRUE) { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ ++ if (lacStatus != CPA_STATUS_SUCCESS) { ++ DPRINTK("%s() Failed to Dereg LAC session %p " ++ "during module exit\n", __FUNCTION__, ++ sessionToDeregister); ++ return; ++ } ++ ++ atomic_dec(&lac_session_failed_dereg_count); ++ return; ++ } ++ ++ for (i = 0; i <= num_dereg_retries; i++) { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ ++ if (lacStatus == CPA_STATUS_SUCCESS) { ++ atomic_dec(&lac_session_failed_dereg_count); ++ return; ++ } ++ if (lacStatus != CPA_STATUS_RETRY) { ++ DPRINTK("%s() Failed to deregister session - lacStatus " ++ " = %d", __FUNCTION__, lacStatus); ++ break; ++ } ++ ++ /*schedule_timout returns the time left for completion if this ++ task is set to TASK_INTERRUPTIBLE */ ++ remaining_delay_time_in_jiffies = dereg_retry_delay_in_jiffies; ++ while (0 > remaining_delay_time_in_jiffies) { ++ remaining_delay_time_in_jiffies = ++ schedule_timeout(remaining_delay_time_in_jiffies); ++ } ++ ++ } ++ ++ DPRINTK("%s(): Unable to deregister session\n", __FUNCTION__); ++ DPRINTK("%s(): Number of unavailable LAC sessions = %d\n", __FUNCTION__, ++ atomic_read(&lac_session_failed_dereg_count)); ++} ++ ++/* Name : icp_ocfDrvPtrAndLenToFlatBuffer ++ * ++ * Description : This function converts a "pointer and length" buffer ++ * structure to Fredericksburg Flat Buffer (CpaFlatBuffer) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, ++ CpaFlatBuffer * pFlatBuffer) ++{ ++ pFlatBuffer->pData = pData; ++ pFlatBuffer->dataLenInBytes = len; ++} ++ ++/* Name : icp_ocfDrvSingleSkBuffToFlatBuffer ++ * ++ * Description : This function converts a single socket buffer (sk_buff) ++ * structure to a Fredericksburg Flat Buffer (CpaFlatBuffer) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++static inline void ++icp_ocfDrvSingleSkBuffToFlatBuffer(struct sk_buff *pSkb, ++ CpaFlatBuffer * pFlatBuffer) ++{ ++ pFlatBuffer->pData = pSkb->data; ++ pFlatBuffer->dataLenInBytes = skb_headlen(pSkb); ++} ++ ++/* Name : icp_ocfDrvSkBuffToBufferList ++ * ++ * Description : This function converts a socket buffer (sk_buff) structure to ++ * Fredericksburg Scatter/Gather (CpaBufferList) buffer format. ++ * ++ * This function assumes that the bufferlist has been allocated with the correct ++ * number of buffer arrays. ++ * ++ */ ++inline int ++icp_ocfDrvSkBuffToBufferList(struct sk_buff *pSkb, CpaBufferList * bufferList) ++{ ++ CpaFlatBuffer *curFlatBuffer = NULL; ++ char *skbuffPageAddr = NULL; ++ struct sk_buff *pCurFrag = NULL; ++ struct skb_shared_info *pShInfo = NULL; ++ uint32_t page_offset = 0, i = 0; ++ ++ DPRINTK("%s(): Entry Point\n", __FUNCTION__); ++ ++ /* ++ * In all cases, the first skb needs to be translated to FlatBuffer. ++ * Perform a buffer translation for the first skbuff ++ */ ++ curFlatBuffer = bufferList->pBuffers; ++ icp_ocfDrvSingleSkBuffToFlatBuffer(pSkb, curFlatBuffer); ++ ++ /* Set the userData to point to the original sk_buff */ ++ bufferList->pUserData = (void *)pSkb; ++ ++ /* We now know we'll have at least one element in the SGL */ ++ bufferList->numBuffers = 1; ++ ++ if (0 == skb_is_nonlinear(pSkb)) { ++ /* Is a linear buffer - therefore it's a single skbuff */ ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ ++ curFlatBuffer++; ++ pShInfo = skb_shinfo(pSkb); ++ if (pShInfo->frag_list != NULL && pShInfo->nr_frags != 0) { ++ EPRINTK("%s():" ++ "Translation for a combination of frag_list " ++ "and frags[] array not supported!\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } else if (pShInfo->frag_list != NULL) { ++ /* ++ * Non linear skbuff supported through frag_list ++ * Perform translation for each fragment (sk_buff) ++ * in the frag_list of the first sk_buff. ++ */ ++ for (pCurFrag = pShInfo->frag_list; ++ pCurFrag != NULL; pCurFrag = pCurFrag->next) { ++ icp_ocfDrvSingleSkBuffToFlatBuffer(pCurFrag, ++ curFlatBuffer); ++ curFlatBuffer++; ++ bufferList->numBuffers++; ++ } ++ } else if (pShInfo->nr_frags != 0) { ++ /* ++ * Perform translation for each fragment in frags array ++ * and add to the BufferList ++ */ ++ for (i = 0; i < pShInfo->nr_frags; i++) { ++ /* Get the page address and offset of this frag */ ++ skbuffPageAddr = (char *)pShInfo->frags[i].page; ++ page_offset = pShInfo->frags[i].page_offset; ++ ++ /* Convert a pointer and length to a flat buffer */ ++ icp_ocfDrvPtrAndLenToFlatBuffer(skbuffPageAddr + ++ page_offset, ++ pShInfo->frags[i].size, ++ curFlatBuffer); ++ curFlatBuffer++; ++ bufferList->numBuffers++; ++ } ++ } else { ++ EPRINTK("%s():" "Could not recognize skbuff fragments!\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvBufferListToSkBuff ++ * ++ * Description : This function converts a Fredericksburg Scatter/Gather ++ * (CpaBufferList) buffer format to socket buffer structure. ++ */ ++inline int ++icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, struct sk_buff **skb) ++{ ++ DPRINTK("%s(): Entry Point\n", __FUNCTION__); ++ ++ /* Retrieve the orignal skbuff */ ++ *skb = (struct sk_buff *)bufferList->pUserData; ++ if (NULL == *skb) { ++ EPRINTK("%s():" ++ "Error on converting from a BufferList. " ++ "The BufferList does not contain an sk_buff.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvPtrAndLenToBufferList ++ * ++ * Description : This function converts a "pointer and length" buffer ++ * structure to Fredericksburg Scatter/Gather Buffer (CpaBufferList) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, ++ CpaBufferList * pBufferList) ++{ ++ pBufferList->numBuffers = 1; ++ pBufferList->pBuffers->pData = pDataIn; ++ pBufferList->pBuffers->dataLenInBytes = length; ++} ++ ++/* Name : icp_ocfDrvBufferListToPtrAndLen ++ * ++ * Description : This function converts Fredericksburg Scatter/Gather Buffer ++ * (CpaBufferList) format to a "pointer and length" buffer structure. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, ++ void **ppDataOut, uint32_t * pLength) ++{ ++ *ppDataOut = pBufferList->pBuffers->pData; ++ *pLength = pBufferList->pBuffers->dataLenInBytes; ++} ++ ++/* Name : icp_ocfDrvBufferListMemInfo ++ * ++ * Description : This function will set the number of flat buffers in ++ * bufferlist, the size of memory to allocate for the pPrivateMetaData ++ * member of the CpaBufferList. ++ */ ++int ++icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, ++ struct icp_drvBuffListInfo *buffListInfo) ++{ ++ buffListInfo->numBuffers = numBuffers; ++ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, ++ buffListInfo->numBuffers, ++ &(buffListInfo->metaSize))) { ++ EPRINTK("%s() Failed to get buffer list meta size.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvGetSkBuffFrags ++ * ++ * Description : This function will determine the number of ++ * fragments in a socket buffer(sk_buff). ++ */ ++inline uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff * pSkb) ++{ ++ uint16_t numFrags = 0; ++ struct sk_buff *pCurFrag = NULL; ++ struct skb_shared_info *pShInfo = NULL; ++ ++ if (NULL == pSkb) ++ return 0; ++ ++ numFrags = 1; ++ if (0 == skb_is_nonlinear(pSkb)) { ++ /* Linear buffer - it's a single skbuff */ ++ return numFrags; ++ } ++ ++ pShInfo = skb_shinfo(pSkb); ++ if (NULL != pShInfo->frag_list && 0 != pShInfo->nr_frags) { ++ EPRINTK("%s(): Combination of frag_list " ++ "and frags[] array not supported!\n", __FUNCTION__); ++ return 0; ++ } else if (0 != pShInfo->nr_frags) { ++ numFrags += pShInfo->nr_frags; ++ return numFrags; ++ } else if (NULL != pShInfo->frag_list) { ++ for (pCurFrag = pShInfo->frag_list; ++ pCurFrag != NULL; pCurFrag = pCurFrag->next) { ++ numFrags++; ++ } ++ return numFrags; ++ } else { ++ return 0; ++ } ++} ++ ++/* Name : icp_ocfDrvFreeFlatBuffer ++ * ++ * Description : This function will deallocate flat buffer. ++ */ ++inline void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer) ++{ ++ if (pFlatBuffer != NULL) { ++ memset(pFlatBuffer, 0, sizeof(CpaFlatBuffer)); ++ kmem_cache_free(drvFlatBuffer_zone, pFlatBuffer); ++ } ++} ++ ++/* Name : icp_ocfDrvAllocMetaData ++ * ++ * Description : This function will allocate memory for the ++ * pPrivateMetaData member of CpaBufferList. ++ */ ++inline int ++icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, ++ const struct icp_drvOpData *pOpData) ++{ ++ Cpa32U metaSize = 0; ++ ++ if (pBufferList->numBuffers <= ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS){ ++ void *pOpDataStartAddr = (void *)pOpData; ++ ++ if (0 == defBuffListInfo.metaSize) { ++ pBufferList->pPrivateMetaData = NULL; ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ /* ++ * The meta data allocation has been included as part of the ++ * op data. It has been pre-allocated in memory just after the ++ * icp_drvOpData structure. ++ */ ++ pBufferList->pPrivateMetaData = pOpDataStartAddr + ++ sizeof(struct icp_drvOpData); ++ } else { ++ if (CPA_STATUS_SUCCESS != ++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, ++ pBufferList->numBuffers, ++ &metaSize)) { ++ EPRINTK("%s() Failed to get buffer list meta size.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ if (0 == metaSize) { ++ pBufferList->pPrivateMetaData = NULL; ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ ++ pBufferList->pPrivateMetaData = kmalloc(metaSize, GFP_ATOMIC); ++ } ++ if (NULL == pBufferList->pPrivateMetaData) { ++ EPRINTK("%s() Failed to allocate pPrivateMetaData.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvFreeMetaData ++ * ++ * Description : This function will deallocate pPrivateMetaData memory. ++ */ ++inline void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList) ++{ ++ if (NULL == pBufferList->pPrivateMetaData) { ++ return; ++ } ++ ++ /* ++ * Only free the meta data if the BufferList has more than ++ * ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS number of buffers. ++ * Otherwise, the meta data shall be freed when the icp_drvOpData is ++ * freed. ++ */ ++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < pBufferList->numBuffers){ ++ kfree(pBufferList->pPrivateMetaData); ++ } ++} ++ ++module_init(icp_ocfDrvInit); ++module_exit(icp_ocfDrvExit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Intel"); ++MODULE_DESCRIPTION("OCF Driver for Intel Quick Assist crypto acceleration"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_ocf.h linux-2.6.30/crypto/ocf/ep80579/icp_ocf.h +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_ocf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_ocf.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,363 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++/* ++ * OCF drv driver header file for the Intel ICP processor. ++ */ ++ ++#ifndef ICP_OCF_H ++#define ICP_OCF_H ++ ++#include ++#include ++#include ++ ++#include "cryptodev.h" ++#include "uio.h" ++ ++#include "cpa.h" ++#include "cpa_cy_im.h" ++#include "cpa_cy_sym.h" ++#include "cpa_cy_rand.h" ++#include "cpa_cy_dh.h" ++#include "cpa_cy_rsa.h" ++#include "cpa_cy_ln.h" ++#include "cpa_cy_common.h" ++#include "cpa_cy_dsa.h" ++ ++#define NUM_BITS_IN_BYTE (8) ++#define NUM_BITS_IN_BYTE_MINUS_ONE (NUM_BITS_IN_BYTE -1) ++#define INVALID_DRIVER_ID (-1) ++#define RETURN_RAND_NUM_GEN_FAILED (-1) ++ ++/*This is define means only one operation can be chained to another ++(resulting in one chain of two operations)*/ ++#define MAX_NUM_OF_CHAINED_OPS (1) ++/*This is the max block cipher initialisation vector*/ ++#define MAX_IV_LEN_IN_BYTES (20) ++/*This is used to check whether the OCF to this driver session limit has ++ been disabled*/ ++#define NO_OCF_TO_DRV_MAX_SESSIONS (0) ++ ++/*OCF values mapped here*/ ++#define ICP_SHA1_DIGEST_SIZE_IN_BYTES (SHA1_HASH_LEN) ++#define ICP_SHA256_DIGEST_SIZE_IN_BYTES (SHA2_256_HASH_LEN) ++#define ICP_SHA384_DIGEST_SIZE_IN_BYTES (SHA2_384_HASH_LEN) ++#define ICP_SHA512_DIGEST_SIZE_IN_BYTES (SHA2_512_HASH_LEN) ++#define ICP_MD5_DIGEST_SIZE_IN_BYTES (MD5_HASH_LEN) ++#define ARC4_COUNTER_LEN (ARC4_BLOCK_LEN) ++ ++#define OCF_REGISTRATION_STATUS_SUCCESS (0) ++#define OCF_ZERO_FUNCTIONALITY_REGISTERED (0) ++#define ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR (0) ++#define ICP_OCF_DRV_STATUS_SUCCESS (0) ++#define ICP_OCF_DRV_STATUS_FAIL (1) ++ ++/*Turn on/off debug options*/ ++#define ICP_OCF_PRINT_DEBUG_MESSAGES (0) ++#define ICP_OCF_PRINT_KERN_ALERT (1) ++#define ICP_OCF_PRINT_KERN_ERRS (1) ++ ++/*DSA Prime Q size in bytes (as defined in the standard) */ ++#define DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES (20) ++ ++/*MACRO DEFINITIONS*/ ++ ++#define BITS_TO_BYTES(bytes, bits) \ ++ bytes = (bits + NUM_BITS_IN_BYTE_MINUS_ONE) / NUM_BITS_IN_BYTE ++ ++#define ICP_CACHE_CREATE(cache_ID, cache_name) \ ++ kmem_cache_create(cache_ID, sizeof(cache_name),0, \ ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ++#define ICP_CACHE_NULL_CHECK(slab_zone) \ ++{ \ ++ if(NULL == slab_zone){ \ ++ icp_ocfDrvFreeCaches(); \ ++ EPRINTK("%s() line %d: Not enough memory!\n", \ ++ __FUNCTION__, __LINE__); \ ++ return ENOMEM; \ ++ } \ ++} ++ ++#define ICP_CACHE_DESTROY(slab_zone) \ ++{ \ ++ if(NULL != slab_zone){ \ ++ kmem_cache_destroy(slab_zone); \ ++ slab_zone = NULL; \ ++ } \ ++} ++ ++#define ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(alg) \ ++{ \ ++ if(OCF_REGISTRATION_STATUS_SUCCESS == \ ++ crypto_register(icp_ocfDrvDriverId, \ ++ alg, \ ++ 0, \ ++ 0)) { \ ++ ocfStatus++; \ ++ } \ ++} ++ ++#define ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(alg) \ ++{ \ ++ if(OCF_REGISTRATION_STATUS_SUCCESS == \ ++ crypto_kregister(icp_ocfDrvDriverId, \ ++ alg, \ ++ 0)){ \ ++ ocfStatus++; \ ++ } \ ++} ++ ++#if ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++#define DPRINTK(args...) \ ++{ \ ++ printk(args); \ ++} ++ ++#else //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++ ++#define DPRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++ ++#if ICP_OCF_PRINT_KERN_ALERT == 1 ++#define APRINTK(args...) \ ++{ \ ++ printk(KERN_ALERT args); \ ++} ++ ++#else //ICP_OCF_PRINT_KERN_ALERT == 1 ++ ++#define APRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_KERN_ALERT == 1 ++ ++#if ICP_OCF_PRINT_KERN_ERRS == 1 ++#define EPRINTK(args...) \ ++{ \ ++ printk(KERN_ERR args); \ ++} ++ ++#else //ICP_OCF_PRINT_KERN_ERRS == 1 ++ ++#define EPRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_KERN_ERRS == 1 ++ ++#define IPRINTK(args...) \ ++{ \ ++ printk(KERN_INFO args); \ ++} ++ ++/*END OF MACRO DEFINITIONS*/ ++ ++typedef enum { ++ ICP_OCF_DRV_ALG_CIPHER = 0, ++ ICP_OCF_DRV_ALG_HASH ++} icp_ocf_drv_alg_type_t; ++ ++/* These are all defined in icp_common.c */ ++extern atomic_t lac_session_failed_dereg_count; ++extern atomic_t icp_ocfDrvIsExiting; ++extern atomic_t num_ocf_to_drv_registered_sessions; ++ ++/*These are use inputs used in icp_sym.c and icp_common.c ++ They are instantiated in icp_common.c*/ ++extern int max_sessions; ++ ++extern int32_t icp_ocfDrvDriverId; ++extern struct list_head icp_ocfDrvGlobalSymListHead; ++extern struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; ++extern struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; ++extern spinlock_t icp_ocfDrvSymSessInfoListSpinlock; ++extern rwlock_t icp_kmem_cache_destroy_alloc_lock; ++ ++/*Slab zones for symettric functionality, instantiated in icp_common.c*/ ++extern struct kmem_cache *drvSessionData_zone; ++extern struct kmem_cache *drvOpData_zone; ++ ++/*Slabs zones for asymettric functionality, instantiated in icp_common.c*/ ++extern struct kmem_cache *drvDH_zone; ++extern struct kmem_cache *drvLnModExp_zone; ++extern struct kmem_cache *drvRSADecrypt_zone; ++extern struct kmem_cache *drvRSAPrivateKey_zone; ++extern struct kmem_cache *drvDSARSSign_zone; ++extern struct kmem_cache *drvDSARSSignKValue_zone; ++extern struct kmem_cache *drvDSAVerify_zone; ++ ++/*Slab zones for flatbuffers and bufferlist*/ ++extern struct kmem_cache *drvFlatBuffer_zone; ++ ++#define ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS (16) ++ ++struct icp_drvBuffListInfo { ++ Cpa16U numBuffers; ++ Cpa32U metaSize; ++ Cpa32U metaOffset; ++ Cpa32U buffListSize; ++}; ++extern struct icp_drvBuffListInfo defBuffListInfo; ++ ++/* ++* This struct is used to keep a reference to the relevant node in the list ++* of sessionData structs, to the buffer type required by OCF and to the OCF ++* provided crp struct that needs to be returned. All this info is needed in ++* the callback function. ++* ++* IV can sometimes be stored in non-contiguous memory (e.g. skbuff ++* linked/frag list, therefore a contiguous memory space for the IV data must be ++* created and passed to LAC ++* ++*/ ++struct icp_drvOpData { ++ CpaCySymOpData lacOpData; ++ uint32_t digestSizeInBytes; ++ struct cryptop *crp; ++ uint8_t bufferType; ++ uint8_t ivData[MAX_IV_LEN_IN_BYTES]; ++ uint16_t numBufferListArray; ++ CpaBufferList srcBuffer; ++ CpaFlatBuffer bufferListArray[ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS]; ++ CpaBoolean verifyResult; ++}; ++/*Values used to derisk chances of performs being called against ++deregistered sessions (for which the slab page has been reclaimed) ++This is not a fix - since page frames are reclaimed from a slab, one cannot ++rely on that memory not being re-used by another app.*/ ++typedef enum { ++ ICP_SESSION_INITIALISED = 0x5C5C5C, ++ ICP_SESSION_RUNNING = 0x005C00, ++ ICP_SESSION_DEREGISTERED = 0xC5C5C5 ++} usage_derisk; ++ ++/* ++This is the OCF<->OCF_DRV session object: ++ ++1.The first member is a listNode. These session objects are added to a linked ++ list in order to make it easier to remove them all at session exit time. ++2.The second member is used to give the session object state and derisk the ++ possibility of OCF batch calls executing against a deregistered session (as ++ described above). ++3.The third member is a LAC<->OCF_DRV session handle (initialised with the first ++ perform request for that session). ++4.The fourth is the LAC session context. All the parameters for this structure ++ are only known when the first perform request for this session occurs. That is ++ why the OCF Tolapai Driver only registers a new LAC session at perform time ++*/ ++struct icp_drvSessionData { ++ struct list_head listNode; ++ usage_derisk inUse; ++ CpaCySymSessionCtx sessHandle; ++ CpaCySymSessionSetupData lacSessCtx; ++}; ++ ++/* This struct is required for deferred session ++ deregistration as a work queue function can ++ only have one argument*/ ++struct icp_ocfDrvFreeLacSession { ++ CpaCySymSessionCtx sessionToDeregister; ++ struct work_struct work; ++}; ++ ++int icp_ocfDrvNewSession(device_t dev, uint32_t * sild, struct cryptoini *cri); ++ ++int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid); ++ ++int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint); ++ ++int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint); ++ ++int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords); ++ ++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister); ++ ++int icp_ocfDrvSkBuffToBufferList(struct sk_buff *skb, ++ CpaBufferList * bufferList); ++ ++int icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, ++ struct sk_buff **skb); ++ ++void icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, ++ CpaFlatBuffer * pFlatBuffer); ++ ++void icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, ++ CpaBufferList * pBufferList); ++ ++void icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, ++ void **ppDataOut, uint32_t * pLength); ++ ++int icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, ++ struct icp_drvBuffListInfo *buffListInfo); ++ ++uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff *pSkb); ++ ++void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer); ++ ++int icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, ++ const struct icp_drvOpData *pOpData); ++ ++void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList); ++ ++#endif ++/* ICP_OCF_H */ +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_sym.c linux-2.6.30/crypto/ocf/ep80579/icp_sym.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_sym.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_sym.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1382 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++/* ++ * An OCF module that uses the API for Intel® QuickAssist Technology to do the ++ * cryptography. ++ * ++ * This driver requires the ICP Access Library that is available from Intel in ++ * order to operate. ++ */ ++ ++#include "icp_ocf.h" ++ ++/*This is the call back function for all symmetric cryptographic processes. ++ Its main functionality is to free driver crypto operation structure and to ++ call back to OCF*/ ++static void ++icp_ocfDrvSymCallBack(void *callbackTag, ++ CpaStatus status, ++ const CpaCySymOp operationType, ++ void *pOpData, ++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult); ++ ++/*This function is used to extract crypto processing information from the OCF ++ inputs, so as that it may be passed onto LAC*/ ++static int ++icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc); ++ ++/*This function checks whether the crp_desc argument pertains to a digest or a ++ cipher operation*/ ++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc); ++ ++/*This function copies all the passed in session context information and stores ++ it in a LAC context structure*/ ++static int ++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, ++ CpaCySymSessionSetupData * lacSessCtx); ++ ++/*This top level function is used to find a pointer to where a digest is ++ stored/needs to be inserted. */ ++static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc); ++ ++/*This function is called when a digest pointer has to be found within a ++ SKBUFF.*/ ++static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData ++ *drvOpData, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*The following two functions are called if the SKBUFF digest pointer is not ++ positioned in the linear portion of the buffer (i.e. it is in a linked SKBUFF ++ or page fragment).*/ ++/*This function takes care of the page fragment case.*/ ++static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*This function takes care of the linked list case.*/ ++static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*This function is used to free an OCF->OCF_DRV session object*/ ++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData); ++ ++/*max IOV buffs supported in a UIO structure*/ ++#define NUM_IOV_SUPPORTED (1) ++ ++/* Name : icp_ocfDrvSymCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the relevant symmetric operation. ++ * ++ * Notes : The callbackTag is a pointer to an icp_drvOpData. This memory ++ * object was passed to LAC for the cryptographic processing and contains all ++ * the relevant information for cleaning up buffer handles etc. so that the ++ * OCF Tolapai Driver portion of this crypto operation can be fully completed. ++ */ ++static void ++icp_ocfDrvSymCallBack(void *callbackTag, ++ CpaStatus status, ++ const CpaCySymOp operationType, ++ void *pOpData, ++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult) ++{ ++ struct cryptop *crp = NULL; ++ struct icp_drvOpData *temp_drvOpData = ++ (struct icp_drvOpData *)callbackTag; ++ uint64_t *tempBasePtr = NULL; ++ uint32_t tempLen = 0; ++ ++ if (NULL == temp_drvOpData) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null userOpaque data" ++ "(status == %d).\n", __FUNCTION__, status); ++ DPRINTK("%s(): Unable to call OCF back! \n", __FUNCTION__); ++ return; ++ } ++ ++ crp = temp_drvOpData->crp; ++ crp->crp_etype = ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null Symmetric Op data" ++ "(status == %d).\n", __FUNCTION__, status); ++ crp->crp_etype = ECANCELED; ++ crypto_done(crp); ++ return; ++ } ++ ++ if (NULL == pDstBuffer) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null Dst Bufferlist data" ++ "(status == %d).\n", __FUNCTION__, status); ++ crp->crp_etype = ECANCELED; ++ crypto_done(crp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ ++ if (temp_drvOpData->bufferType == CRYPTO_F_SKBUF) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvBufferListToSkBuff(pDstBuffer, ++ (struct sk_buff **) ++ &(crp->crp_buf))) { ++ EPRINTK("%s(): BufferList to SkBuff " ++ "conversion error.\n", __FUNCTION__); ++ crp->crp_etype = EPERM; ++ } ++ } else { ++ icp_ocfDrvBufferListToPtrAndLen(pDstBuffer, ++ (void **)&tempBasePtr, ++ &tempLen); ++ crp->crp_olen = (int)tempLen; ++ } ++ ++ } else { ++ DPRINTK("%s(): The callback from the LAC component has failed" ++ "(status == %d).\n", __FUNCTION__, status); ++ ++ crp->crp_etype = ECANCELED; ++ } ++ ++ if (temp_drvOpData->numBufferListArray > ++ ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { ++ kfree(pDstBuffer->pBuffers); ++ } ++ icp_ocfDrvFreeMetaData(pDstBuffer); ++ kmem_cache_free(drvOpData_zone, temp_drvOpData); ++ ++ /* Invoke the OCF callback function */ ++ crypto_done(crp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvNewSession ++ * ++ * Description : This function will create a new Driver<->OCF session ++ * ++ * Notes : LAC session registration happens during the first perform call. ++ * That is the first time we know all information about a given session. ++ */ ++int icp_ocfDrvNewSession(device_t dev, uint32_t * sid, struct cryptoini *cri) ++{ ++ struct icp_drvSessionData *sessionData = NULL; ++ uint32_t delete_session = 0; ++ ++ /* The SID passed in should be our driver ID. We can return the */ ++ /* local ID (LID) which is a unique identifier which we can use */ ++ /* to differentiate between the encrypt/decrypt LAC session handles */ ++ if (NULL == sid) { ++ EPRINTK("%s(): Invalid input parameters - NULL sid.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (NULL == cri) { ++ EPRINTK("%s(): Invalid input parameters - NULL cryptoini.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (icp_ocfDrvDriverId != *sid) { ++ EPRINTK("%s(): Invalid input parameters - bad driver ID\n", ++ __FUNCTION__); ++ EPRINTK("\t sid = 0x08%p \n \t cri = 0x08%p \n", sid, cri); ++ return EINVAL; ++ } ++ ++ sessionData = kmem_cache_zalloc(drvSessionData_zone, GFP_ATOMIC); ++ if (NULL == sessionData) { ++ DPRINTK("%s():No memory for Session Data\n", __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ /*put this check in the spinlock so no new sessions can be added to the ++ linked list when we are exiting */ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ delete_session++; ++ ++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS != max_sessions) { ++ if (atomic_read(&num_ocf_to_drv_registered_sessions) >= ++ (max_sessions - ++ atomic_read(&lac_session_failed_dereg_count))) { ++ delete_session++; ++ } else { ++ atomic_inc(&num_ocf_to_drv_registered_sessions); ++ /* Add to session data linked list */ ++ list_add(&(sessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead); ++ } ++ ++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS == max_sessions) { ++ list_add(&(sessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead); ++ } ++ ++ sessionData->inUse = ICP_SESSION_INITIALISED; ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (delete_session) { ++ DPRINTK("%s():No Session handles available\n", __FUNCTION__); ++ kmem_cache_free(drvSessionData_zone, sessionData); ++ return EPERM; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAlgorithmSetup(cri, &(sessionData->lacSessCtx))) { ++ DPRINTK("%s():algorithm not supported\n", __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EINVAL; ++ } ++ ++ if (cri->cri_next) { ++ if (cri->cri_next->cri_next != NULL) { ++ DPRINTK("%s():only two chained algorithms supported\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EPERM; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAlgorithmSetup(cri->cri_next, ++ &(sessionData->lacSessCtx))) { ++ DPRINTK("%s():second algorithm not supported\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EINVAL; ++ } ++ ++ sessionData->lacSessCtx.symOperation = ++ CPA_CY_SYM_OP_ALGORITHM_CHAINING; ++ } ++ ++ *sid = (uint32_t) sessionData; ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvAlgorithmSetup ++ * ++ * Description : This function builds the session context data from the ++ * information supplied through OCF. Algorithm chain order and whether the ++ * session is Encrypt/Decrypt can only be found out at perform time however, so ++ * the session is registered with LAC at that time. ++ */ ++static int ++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, ++ CpaCySymSessionSetupData * lacSessCtx) ++{ ++ ++ lacSessCtx->sessionPriority = CPA_CY_PRIORITY_NORMAL; ++ ++ switch (cri->cri_alg) { ++ ++ case CRYPTO_NULL_CBC: ++ DPRINTK("%s(): NULL CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_NULL; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_DES_CBC: ++ DPRINTK("%s(): DES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_DES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_3DES_CBC: ++ DPRINTK("%s(): 3DES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_3DES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_AES_CBC: ++ DPRINTK("%s(): AES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_AES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_ARC4: ++ DPRINTK("%s(): ARC4\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_ARC4; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_SHA1: ++ DPRINTK("%s(): SHA1\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA1_HMAC: ++ DPRINTK("%s(): SHA1_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_256: ++ DPRINTK("%s(): SHA256\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA256; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_256_HMAC: ++ DPRINTK("%s(): SHA256_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA256; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_384: ++ DPRINTK("%s(): SHA384\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA384; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_384_HMAC: ++ DPRINTK("%s(): SHA384_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA384; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_512: ++ DPRINTK("%s(): SHA512\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA512; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_512_HMAC: ++ DPRINTK("%s(): SHA512_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA512; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_MD5: ++ DPRINTK("%s(): MD5\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_MD5_HMAC: ++ DPRINTK("%s(): MD5_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ default: ++ DPRINTK("%s(): ALG Setup FAIL\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvFreeOCFSession ++ * ++ * Description : This function deletes all existing Session data representing ++ * the Cryptographic session established between OCF and this driver. This ++ * also includes freeing the memory allocated for the session context. The ++ * session object is also removed from the session linked list. ++ */ ++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData) ++{ ++ ++ sessionData->inUse = ICP_SESSION_DEREGISTERED; ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ /*If the Driver is exiting, allow that process to ++ handle any deletions */ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ return; ++ } ++ ++ atomic_dec(&num_ocf_to_drv_registered_sessions); ++ ++ list_del(&(sessionData->listNode)); ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (NULL != sessionData->sessHandle) { ++ kfree(sessionData->sessHandle); ++ } ++ kmem_cache_free(drvSessionData_zone, sessionData); ++} ++ ++/* Name : icp_ocfDrvFreeLACSession ++ * ++ * Description : This attempts to deregister a LAC session. If it fails, the ++ * deregistation retry function is called. ++ */ ++int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid) ++{ ++ CpaCySymSessionCtx sessionToDeregister = NULL; ++ struct icp_drvSessionData *sessionData = NULL; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ int retval = 0; ++ ++ sessionData = (struct icp_drvSessionData *)CRYPTO_SESID2LID(sid); ++ if (NULL == sessionData) { ++ EPRINTK("%s(): OCF Free session called with Null Session ID.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ sessionToDeregister = sessionData->sessHandle; ++ ++ if (ICP_SESSION_INITIALISED == sessionData->inUse) { ++ DPRINTK("%s() Session not registered with LAC\n", __FUNCTION__); ++ } else if (NULL == sessionData->sessHandle) { ++ EPRINTK ++ ("%s(): OCF Free session called with Null Session Handle.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } else { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ if (CPA_STATUS_RETRY == lacStatus) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvDeregRetry(&sessionToDeregister)) { ++ /* the retry function increments the ++ dereg failed count */ ++ DPRINTK("%s(): LAC failed to deregister the " ++ "session. (localSessionId= %p)\n", ++ __FUNCTION__, sessionToDeregister); ++ retval = EPERM; ++ } ++ ++ } else if (CPA_STATUS_SUCCESS != lacStatus) { ++ DPRINTK("%s(): LAC failed to deregister the session. " ++ "localSessionId= %p, lacStatus = %d\n", ++ __FUNCTION__, sessionToDeregister, lacStatus); ++ atomic_inc(&lac_session_failed_dereg_count); ++ retval = EPERM; ++ } ++ } ++ ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return retval; ++ ++} ++ ++/* Name : icp_ocfDrvAlgCheck ++ * ++ * Description : This function checks whether the cryptodesc argument pertains ++ * to a sym or hash function ++ */ ++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc) ++{ ++ ++ if (crp_desc->crd_alg == CRYPTO_3DES_CBC || ++ crp_desc->crd_alg == CRYPTO_AES_CBC || ++ crp_desc->crd_alg == CRYPTO_DES_CBC || ++ crp_desc->crd_alg == CRYPTO_NULL_CBC || ++ crp_desc->crd_alg == CRYPTO_ARC4) { ++ return ICP_OCF_DRV_ALG_CIPHER; ++ } ++ ++ return ICP_OCF_DRV_ALG_HASH; ++} ++ ++/* Name : icp_ocfDrvSymProcess ++ * ++ * Description : This function will map symmetric functionality calls from OCF ++ * to the LAC API. It will also allocate memory to store the session context. ++ * ++ * Notes: If it is the first perform call for a given session, then a LAC ++ * session is registered. After the session is registered, no checks as ++ * to whether session paramaters have changed (e.g. alg chain order) are ++ * done. ++ */ ++int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct icp_drvSessionData *sessionData = NULL; ++ struct icp_drvOpData *drvOpData = NULL; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ Cpa32U sessionCtxSizeInBytes = 0; ++ uint16_t numBufferListArray = 0; ++ ++ if (NULL == crp) { ++ DPRINTK("%s(): Invalid input parameters, cryptop is NULL\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (NULL == crp->crp_desc) { ++ DPRINTK("%s(): Invalid input parameters, no crp_desc attached " ++ "to crp\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ if (NULL == crp->crp_buf) { ++ DPRINTK("%s(): Invalid input parameters, no buffer attached " ++ "to crp\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ crp->crp_etype = EFAULT; ++ return EFAULT; ++ } ++ ++ sessionData = (struct icp_drvSessionData *) ++ (CRYPTO_SESID2LID(crp->crp_sid)); ++ if (NULL == sessionData) { ++ DPRINTK("%s(): Invalid input parameters, Null Session ID \n", ++ __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++/*If we get a request against a deregisted session, cancel operation*/ ++ if (ICP_SESSION_DEREGISTERED == sessionData->inUse) { ++ DPRINTK("%s(): Session ID %d was deregistered \n", ++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); ++ crp->crp_etype = EFAULT; ++ return EFAULT; ++ } ++ ++/*If none of the session states are set, then the session structure was either ++ not initialised properly or we are reading from a freed memory area (possible ++ due to OCF batch mode not removing queued requests against deregistered ++ sessions*/ ++ if (ICP_SESSION_INITIALISED != sessionData->inUse && ++ ICP_SESSION_RUNNING != sessionData->inUse) { ++ DPRINTK("%s(): Session - ID %d - not properly initialised or " ++ "memory freed back to the kernel \n", ++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ /*For the below checks, remember error checking is already done in LAC. ++ We're not validating inputs subsequent to registration */ ++ if (sessionData->inUse == ICP_SESSION_INITIALISED) { ++ DPRINTK("%s(): Initialising session\n", __FUNCTION__); ++ ++ if (NULL != crp->crp_desc->crd_next) { ++ if (ICP_OCF_DRV_ALG_CIPHER == ++ icp_ocfDrvAlgCheck(crp->crp_desc)) { ++ ++ sessionData->lacSessCtx.algChainOrder = ++ CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; ++ ++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ } else { ++ sessionData->lacSessCtx.algChainOrder = ++ CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; ++ ++ if (crp->crp_desc->crd_next->crd_flags & ++ CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ ++ } ++ ++ } else if (ICP_OCF_DRV_ALG_CIPHER == ++ icp_ocfDrvAlgCheck(crp->crp_desc)) { ++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ ++ } ++ ++ /*No action required for standalone Auth here */ ++ ++ /* Allocate memory for SymSessionCtx before the Session Registration */ ++ lacStatus = ++ cpaCySymSessionCtxGetSize(CPA_INSTANCE_HANDLE_SINGLE, ++ &(sessionData->lacSessCtx), ++ &sessionCtxSizeInBytes); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymSessionCtxGetSize failed - %d\n", ++ __FUNCTION__, lacStatus); ++ return EINVAL; ++ } ++ sessionData->sessHandle = ++ kmalloc(sessionCtxSizeInBytes, GFP_ATOMIC); ++ if (NULL == sessionData->sessHandle) { ++ EPRINTK ++ ("%s(): Failed to get memory for SymSessionCtx\n", ++ __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ lacStatus = cpaCySymInitSession(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvSymCallBack, ++ &(sessionData->lacSessCtx), ++ sessionData->sessHandle); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymInitSession failed -%d \n", ++ __FUNCTION__, lacStatus); ++ return EFAULT; ++ } ++ ++ sessionData->inUse = ICP_SESSION_RUNNING; ++ } ++ ++ drvOpData = kmem_cache_zalloc(drvOpData_zone, GFP_ATOMIC); ++ if (NULL == drvOpData) { ++ EPRINTK("%s():Failed to get memory for drvOpData\n", ++ __FUNCTION__); ++ crp->crp_etype = ENOMEM; ++ return ENOMEM; ++ } ++ ++ drvOpData->lacOpData.pSessionCtx = sessionData->sessHandle; ++ drvOpData->digestSizeInBytes = sessionData->lacSessCtx.hashSetupData. ++ digestResultLenInBytes; ++ drvOpData->crp = crp; ++ ++ /* Set the default buffer list array memory allocation */ ++ drvOpData->srcBuffer.pBuffers = drvOpData->bufferListArray; ++ drvOpData->numBufferListArray = ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS; ++ ++ /* ++ * Allocate buffer list array memory allocation if the ++ * data fragment is more than the default allocation ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ numBufferListArray = icp_ocfDrvGetSkBuffFrags((struct sk_buff *) ++ crp->crp_buf); ++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < numBufferListArray) { ++ DPRINTK("%s() numBufferListArray more than default\n", ++ __FUNCTION__); ++ drvOpData->srcBuffer.pBuffers = NULL; ++ drvOpData->srcBuffer.pBuffers = ++ kmalloc(numBufferListArray * ++ sizeof(CpaFlatBuffer), GFP_ATOMIC); ++ if (NULL == drvOpData->srcBuffer.pBuffers) { ++ EPRINTK("%s() Failed to get memory for " ++ "pBuffers\n", __FUNCTION__); ++ kmem_cache_free(drvOpData_zone, drvOpData); ++ crp->crp_etype = ENOMEM; ++ return ENOMEM; ++ } ++ drvOpData->numBufferListArray = numBufferListArray; ++ } ++ } ++ ++ /* ++ * Check the type of buffer structure we got and convert it into ++ * CpaBufferList format. ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvSkBuffToBufferList((struct sk_buff *)crp->crp_buf, ++ &(drvOpData->srcBuffer))) { ++ EPRINTK("%s():Failed to translate from SK_BUF " ++ "to bufferlist\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ drvOpData->bufferType = CRYPTO_F_SKBUF; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* OCF only supports IOV of one entry. */ ++ if (NUM_IOV_SUPPORTED == ++ ((struct uio *)(crp->crp_buf))->uio_iovcnt) { ++ ++ icp_ocfDrvPtrAndLenToBufferList(((struct uio *)(crp-> ++ crp_buf))-> ++ uio_iov[0].iov_base, ++ ((struct uio *)(crp-> ++ crp_buf))-> ++ uio_iov[0].iov_len, ++ &(drvOpData-> ++ srcBuffer)); ++ ++ drvOpData->bufferType = CRYPTO_F_IOV; ++ ++ } else { ++ DPRINTK("%s():Unable to handle IOVs with lengths of " ++ "greater than one!\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ } else { ++ icp_ocfDrvPtrAndLenToBufferList(crp->crp_buf, ++ crp->crp_ilen, ++ &(drvOpData->srcBuffer)); ++ ++ drvOpData->bufferType = CRYPTO_BUF_CONTIG; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->crp_desc)) { ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ if (drvOpData->crp->crp_desc->crd_next != NULL) { ++ if (icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp-> ++ crp_desc->crd_next)) { ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ } ++ ++ /* Allocate srcBuffer's private meta data */ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAllocMetaData(&(drvOpData->srcBuffer), drvOpData)) { ++ EPRINTK("%s() icp_ocfDrvAllocMetaData failed\n", __FUNCTION__); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ /* Perform "in-place" crypto operation */ ++ lacStatus = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE, ++ (void *)drvOpData, ++ &(drvOpData->lacOpData), ++ &(drvOpData->srcBuffer), ++ &(drvOpData->srcBuffer), ++ &(drvOpData->verifyResult)); ++ if (CPA_STATUS_RETRY == lacStatus) { ++ DPRINTK("%s(): cpaCySymPerformOp retry, lacStatus = %d\n", ++ __FUNCTION__, lacStatus); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymPerformOp failed, lacStatus = %d\n", ++ __FUNCTION__, lacStatus); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ return 0; //OCF success status value ++ ++ err: ++ if (drvOpData->numBufferListArray > ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { ++ kfree(drvOpData->srcBuffer.pBuffers); ++ } ++ icp_ocfDrvFreeMetaData(&(drvOpData->srcBuffer)); ++ kmem_cache_free(drvOpData_zone, drvOpData); ++ ++ return crp->crp_etype; ++} ++ ++/* Name : icp_ocfDrvProcessDataSetup ++ * ++ * Description : This function will setup all the cryptographic operation data ++ * that is required by LAC to execute the operation. ++ */ ++static int icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc) ++{ ++ CpaCyRandGenOpData randGenOpData; ++ CpaFlatBuffer randData; ++ ++ drvOpData->lacOpData.packetType = CPA_CY_SYM_PACKET_TYPE_FULL; ++ ++ /* Convert from the cryptop to the ICP LAC crypto parameters */ ++ switch (crp_desc->crd_alg) { ++ case CRYPTO_NULL_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = NULL_BLOCK_LEN; ++ break; ++ case CRYPTO_DES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = DES_BLOCK_LEN; ++ break; ++ case CRYPTO_3DES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = DES3_BLOCK_LEN; ++ break; ++ case CRYPTO_ARC4: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = ARC4_COUNTER_LEN; ++ break; ++ case CRYPTO_AES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = RIJNDAEL128_BLOCK_LEN; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ case CRYPTO_SHA2_256: ++ case CRYPTO_SHA2_256_HMAC: ++ case CRYPTO_SHA2_384: ++ case CRYPTO_SHA2_384_HMAC: ++ case CRYPTO_SHA2_512: ++ case CRYPTO_SHA2_512_HMAC: ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ drvOpData->lacOpData. ++ hashStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToHashInBytes = crp_desc->crd_len; ++ drvOpData->lacOpData. ++ pDigestResult = ++ icp_ocfDrvDigestPointerFind(drvOpData, crp_desc); ++ ++ if (NULL == drvOpData->lacOpData.pDigestResult) { ++ DPRINTK("%s(): ERROR - could not calculate " ++ "Digest Result memory address\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ drvOpData->lacOpData.digestVerify = CPA_FALSE; ++ break; ++ default: ++ DPRINTK("%s(): Crypto process error - algorithm not " ++ "found \n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ /* Figure out what the IV is supposed to be */ ++ if ((crp_desc->crd_alg == CRYPTO_DES_CBC) || ++ (crp_desc->crd_alg == CRYPTO_3DES_CBC) || ++ (crp_desc->crd_alg == CRYPTO_AES_CBC)) { ++ /*ARC4 doesn't use an IV */ ++ if (crp_desc->crd_flags & CRD_F_IV_EXPLICIT) { ++ /* Explicit IV provided to OCF */ ++ drvOpData->lacOpData.pIv = crp_desc->crd_iv; ++ } else { ++ /* IV is not explicitly provided to OCF */ ++ ++ /* Point the LAC OP Data IV pointer to our allocated ++ storage location for this session. */ ++ drvOpData->lacOpData.pIv = drvOpData->ivData; ++ ++ if ((crp_desc->crd_flags & CRD_F_ENCRYPT) && ++ ((crp_desc->crd_flags & CRD_F_IV_PRESENT) == 0)) { ++ ++ /* Encrypting - need to create IV */ ++ randGenOpData.generateBits = CPA_TRUE; ++ randGenOpData.lenInBytes = MAX_IV_LEN_IN_BYTES; ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) ++ drvOpData-> ++ ivData, ++ MAX_IV_LEN_IN_BYTES, ++ &randData); ++ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, ++ &randGenOpData, &randData)) { ++ DPRINTK("%s(): ERROR - Failed to" ++ " generate" ++ " Initialisation Vector\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ crypto_copyback(drvOpData->crp-> ++ crp_flags, ++ drvOpData->crp->crp_buf, ++ crp_desc->crd_inject, ++ drvOpData->lacOpData. ++ ivLenInBytes, ++ (caddr_t) (drvOpData->lacOpData. ++ pIv)); ++ } else { ++ /* Reading IV from buffer */ ++ crypto_copydata(drvOpData->crp-> ++ crp_flags, ++ drvOpData->crp->crp_buf, ++ crp_desc->crd_inject, ++ drvOpData->lacOpData. ++ ivLenInBytes, ++ (caddr_t) (drvOpData->lacOpData. ++ pIv)); ++ } ++ ++ } ++ ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvDigestPointerFind ++ * ++ * Description : This function is used to find the memory address of where the ++ * digest information shall be stored in. Input buffer types are an skbuff, iov ++ * or flat buffer. The address is found using the buffer data start address and ++ * an offset. ++ * ++ * Note: In the case of a linux skbuff, the digest address may exist within ++ * a memory space linked to from the start buffer. These linked memory spaces ++ * must be traversed by the data length offset in order to find the digest start ++ * address. Whether there is enough space for the digest must also be checked. ++ */ ++ ++static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc) ++{ ++ ++ int offsetInBytes = crp_desc->crd_inject; ++ uint32_t digestSizeInBytes = drvOpData->digestSizeInBytes; ++ uint8_t *flat_buffer_base = NULL; ++ int flat_buffer_length = 0; ++ struct sk_buff *skb; ++ ++ if (drvOpData->crp->crp_flags & CRYPTO_F_SKBUF) { ++ /*check if enough overall space to store hash */ ++ skb = (struct sk_buff *)(drvOpData->crp->crp_buf); ++ ++ if (skb->len < (offsetInBytes + digestSizeInBytes)) { ++ DPRINTK("%s() Not enough space for Digest" ++ " payload after the offset (%d), " ++ "digest size (%d) \n", __FUNCTION__, ++ offsetInBytes, digestSizeInBytes); ++ return NULL; ++ } ++ ++ return icp_ocfDrvSkbuffDigestPointerFind(drvOpData, ++ offsetInBytes, ++ digestSizeInBytes); ++ ++ } else { ++ /* IOV or flat buffer */ ++ if (drvOpData->crp->crp_flags & CRYPTO_F_IOV) { ++ /*single IOV check has already been done */ ++ flat_buffer_base = ((struct uio *) ++ (drvOpData->crp->crp_buf))-> ++ uio_iov[0].iov_base; ++ flat_buffer_length = ((struct uio *) ++ (drvOpData->crp->crp_buf))-> ++ uio_iov[0].iov_len; ++ } else { ++ flat_buffer_base = (uint8_t *) drvOpData->crp->crp_buf; ++ flat_buffer_length = drvOpData->crp->crp_ilen; ++ } ++ ++ if (flat_buffer_length < (offsetInBytes + digestSizeInBytes)) { ++ DPRINTK("%s() Not enough space for Digest " ++ "(IOV/Flat Buffer) \n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) (flat_buffer_base + offsetInBytes); ++ } ++ } ++ DPRINTK("%s() Should not reach this point\n", __FUNCTION__); ++ return NULL; ++} ++ ++/* Name : icp_ocfDrvSkbuffDigestPointerFind ++ * ++ * Description : This function is used by icp_ocfDrvDigestPointerFind to process ++ * the non-linear portion of the skbuff if the fragmentation type is a linked ++ * list (frag_list is not NULL in the skb_shared_info structure) ++ */ ++static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData ++ *drvOpData, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ ++ struct sk_buff *skb = NULL; ++ struct skb_shared_info *skb_shared = NULL; ++ ++ uint32_t skbuffisnonlinear = 0; ++ ++ uint32_t skbheadlen = 0; ++ ++ skb = (struct sk_buff *)(drvOpData->crp->crp_buf); ++ skbuffisnonlinear = skb_is_nonlinear(skb); ++ ++ skbheadlen = skb_headlen(skb); ++ ++ /*Linear skb checks */ ++ if (skbheadlen > offsetInBytes) { ++ ++ if (skbheadlen >= (offsetInBytes + digestSizeInBytes)) { ++ return (uint8_t *) (skb->data + offsetInBytes); ++ } else { ++ DPRINTK("%s() Auth payload stretches " ++ "accross contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } ++ } else { ++ if (skbuffisnonlinear) { ++ offsetInBytes -= skbheadlen; ++ } else { ++ DPRINTK("%s() Offset outside of buffer boundaries\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ } ++ ++ /*Non Linear checks */ ++ skb_shared = (struct skb_shared_info *)(skb->end); ++ if (unlikely(NULL == skb_shared)) { ++ DPRINTK("%s() skbuff shared info stucture is NULL! \n", ++ __FUNCTION__); ++ return NULL; ++ } else if ((0 != skb_shared->nr_frags) && ++ (skb_shared->frag_list != NULL)) { ++ DPRINTK("%s() skbuff nr_frags AND " ++ "frag_list not supported \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ /*TCP segmentation more likely than IP fragmentation */ ++ if (likely(0 != skb_shared->nr_frags)) { ++ return icp_ocfDrvDigestSkbNRFragsCheck(skb, skb_shared, ++ offsetInBytes, ++ digestSizeInBytes); ++ } else if (skb_shared->frag_list != NULL) { ++ return icp_ocfDrvDigestSkbFragListCheck(skb, skb_shared, ++ offsetInBytes, ++ digestSizeInBytes); ++ } else { ++ DPRINTK("%s() skbuff is non-linear but does not show any " ++ "linked data\n", __FUNCTION__); ++ return NULL; ++ } ++ ++} ++ ++/* Name : icp_ocfDrvDigestSkbNRFragsCheck ++ * ++ * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to ++ * process the non-linear portion of the skbuff, if the fragmentation type is ++ * page fragments ++ */ ++static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ int i = 0; ++ /*nr_frags starts from 1 */ ++ if (MAX_SKB_FRAGS < skb_shared->nr_frags) { ++ DPRINTK("%s error processing skbuff " ++ "page frame -- MAX FRAGS exceeded \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for (i = 0; i < skb_shared->nr_frags; i++) { ++ ++ if (offsetInBytes >= skb_shared->frags[i].size) { ++ /*offset still greater than data position */ ++ offsetInBytes -= skb_shared->frags[i].size; ++ } else { ++ /* found the page containing start of hash */ ++ ++ if (NULL == skb_shared->frags[i].page) { ++ DPRINTK("%s() Linked page is NULL!\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ ++ if (offsetInBytes + digestSizeInBytes > ++ skb_shared->frags[i].size) { ++ DPRINTK("%s() Auth payload stretches accross " ++ "contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) (skb_shared->frags[i].page + ++ skb_shared->frags[i]. ++ page_offset + ++ offsetInBytes); ++ } ++ } ++ /*only possible if internal page sizes are set wrong */ ++ if (offsetInBytes < 0) { ++ DPRINTK("%s error processing skbuff page frame " ++ "-- offset calculation \n", __FUNCTION__); ++ return NULL; ++ } ++ } ++ /*only possible if internal page sizes are set wrong */ ++ DPRINTK("%s error processing skbuff page frame " ++ "-- ran out of page fragments, remaining offset = %d \n", ++ __FUNCTION__, offsetInBytes); ++ return NULL; ++ ++} ++ ++/* Name : icp_ocfDrvDigestSkbFragListCheck ++ * ++ * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to ++ * process the non-linear portion of the skbuff, if the fragmentation type is ++ * a linked list ++ * ++ */ ++static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ ++ struct sk_buff *skb_list = skb_shared->frag_list; ++ /*check added for readability */ ++ if (NULL == skb_list) { ++ DPRINTK("%s error processing skbuff " ++ "-- no more list! \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for (; skb_list; skb_list = skb_list->next) { ++ if (NULL == skb_list) { ++ DPRINTK("%s error processing skbuff " ++ "-- no more list! \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ if (offsetInBytes >= skb_list->len) { ++ offsetInBytes -= skb_list->len; ++ ++ } else { ++ if (offsetInBytes + digestSizeInBytes > skb_list->len) { ++ DPRINTK("%s() Auth payload stretches accross " ++ "contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) ++ (skb_list->data + offsetInBytes); ++ } ++ ++ } ++ ++ /*This check is only needed if internal skb_list length values ++ are set wrong. */ ++ if (0 > offsetInBytes) { ++ DPRINTK("%s() error processing skbuff object -- offset " ++ "calculation \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ } ++ ++ /*catch all for unusual for-loop exit. ++ This code should never be reached */ ++ DPRINTK("%s() Catch-All hit! Process error.\n", __FUNCTION__); ++ return NULL; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/Makefile linux-2.6.30/crypto/ocf/ep80579/Makefile +--- linux-2.6.30.orig/crypto/ocf/ep80579/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,107 @@ ++######################################################################### ++# ++# Targets supported ++# all - builds everything and installs ++# install - identical to all ++# depend - build dependencies ++# clean - clears derived objects except the .depend files ++# distclean- clears all derived objects and the .depend file ++# ++# @par ++# This file is provided under a dual BSD/GPLv2 license. When using or ++# redistributing this file, you may do so under either license. ++# ++# GPL LICENSE SUMMARY ++# ++# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# The full GNU General Public License is included in this distribution ++# in the file called LICENSE.GPL. ++# ++# Contact Information: ++# Intel Corporation ++# ++# BSD LICENSE ++# ++# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++# All rights reserved. ++# ++# Redistribution and use in source and binary forms, with or without ++# modification, are permitted provided that the following conditions ++# are met: ++# ++# * Redistributions of source code must retain the above copyright ++# notice, this list of conditions and the following disclaimer. ++# * Redistributions in binary form must reproduce the above copyright ++# notice, this list of conditions and the following disclaimer in ++# the documentation and/or other materials provided with the ++# distribution. ++# * Neither the name of Intel Corporation nor the names of its ++# contributors may be used to endorse or promote products derived ++# from this software without specific prior written permission. ++# ++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++# ++# ++# version: Security.L.1.0.130 ++############################################################################ ++ ++ ++####################Common variables and definitions######################## ++ ++# Ensure The ENV_DIR environmental var is defined. ++ifndef ICP_ENV_DIR ++$(error ICP_ENV_DIR is undefined. Please set the path to your environment makefile \ ++ "-> setenv ICP_ENV_DIR ") ++endif ++ ++#Add your project environment Makefile ++include $(ICP_ENV_DIR)/environment.mk ++ ++#include the makefile with all the default and common Make variable definitions ++include $(ICP_BUILDSYSTEM_PATH)/build_files/common.mk ++ ++#Add the name for the executable, Library or Module output definitions ++OUTPUT_NAME= icp_ocf ++ ++# List of Source Files to be compiled ++SOURCES= icp_common.c icp_sym.c icp_asym.c ++ ++#common includes between all supported OSes ++INCLUDES= -I $(ICP_API_DIR) -I$(ICP_LAC_API) \ ++-I$(ICP_OCF_SRC_DIR) ++ ++# The location of the os level makefile needs to be changed. ++include $(ICP_ENV_DIR)/$(ICP_OS)_$(ICP_OS_LEVEL).mk ++ ++# On the line directly below list the outputs you wish to build for, ++# e.g "lib_static lib_shared exe module" as show below ++install: module ++ ++###################Include rules makefiles######################## ++include $(ICP_BUILDSYSTEM_PATH)/build_files/rules.mk ++###################End of Rules inclusion######################### ++ ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751.c linux-2.6.30/crypto/ocf/hifn/hifn7751.c +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,2970 @@ ++/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * Copyright (c) 2003 Hifn Inc. ++ * ++ * This driver is based on a previous driver by Invertex, for which they ++ * requested: Please send any comments, feedback, bug-fixes, or feature ++ * requests to software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ * ++__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.40 2007/03/21 03:42:49 sam Exp $"); ++ */ ++ ++/* ++ * Driver for various Hifn encryption processors. ++ */ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DPRINTF(a...) if (hifn_debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "hifn"); \ ++ printk(a); \ ++ } else ++#else ++#define DPRINTF(a...) ++#endif ++ ++static inline int ++pci_get_revid(struct pci_dev *dev) ++{ ++ u8 rid = 0; ++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid); ++ return rid; ++} ++ ++static struct hifn_stats hifnstats; ++ ++#define debug hifn_debug ++int hifn_debug = 0; ++module_param(hifn_debug, int, 0644); ++MODULE_PARM_DESC(hifn_debug, "Enable debug"); ++ ++int hifn_maxbatch = 1; ++module_param(hifn_maxbatch, int, 0644); ++MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt"); ++ ++#ifdef MODULE_PARM ++char *hifn_pllconfig = NULL; ++MODULE_PARM(hifn_pllconfig, "s"); ++#else ++char hifn_pllconfig[32]; /* This setting is RO after loading */ ++module_param_string(hifn_pllconfig, hifn_pllconfig, 32, 0444); ++#endif ++MODULE_PARM_DESC(hifn_pllconfig, "PLL config, ie., pci66, ext33, ..."); ++ ++#ifdef HIFN_VULCANDEV ++#include ++#include ++ ++static struct cdevsw vulcanpk_cdevsw; /* forward declaration */ ++#endif ++ ++/* ++ * Prototypes and count for the pci_device structure ++ */ ++static int hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent); ++static void hifn_remove(struct pci_dev *dev); ++ ++static int hifn_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int hifn_freesession(device_t, u_int64_t); ++static int hifn_process(device_t, struct cryptop *, int); ++ ++static device_method_t hifn_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, hifn_newsession), ++ DEVMETHOD(cryptodev_freesession,hifn_freesession), ++ DEVMETHOD(cryptodev_process, hifn_process), ++}; ++ ++static void hifn_reset_board(struct hifn_softc *, int); ++static void hifn_reset_puc(struct hifn_softc *); ++static void hifn_puc_wait(struct hifn_softc *); ++static int hifn_enable_crypto(struct hifn_softc *); ++static void hifn_set_retry(struct hifn_softc *sc); ++static void hifn_init_dma(struct hifn_softc *); ++static void hifn_init_pci_registers(struct hifn_softc *); ++static int hifn_sramsize(struct hifn_softc *); ++static int hifn_dramsize(struct hifn_softc *); ++static int hifn_ramtype(struct hifn_softc *); ++static void hifn_sessions(struct hifn_softc *); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hifn_intr(int irq, void *arg); ++#else ++static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs); ++#endif ++static u_int hifn_write_command(struct hifn_command *, u_int8_t *); ++static u_int32_t hifn_next_signature(u_int32_t a, u_int cnt); ++static void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *); ++static int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int); ++static int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *); ++static int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *); ++static int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *); ++static int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *); ++static int hifn_init_pubrng(struct hifn_softc *); ++static void hifn_tick(unsigned long arg); ++static void hifn_abort(struct hifn_softc *); ++static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *); ++ ++static void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t); ++static void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t); ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int hifn_read_random(void *arg, u_int32_t *buf, int len); ++#endif ++ ++#define HIFN_MAX_CHIPS 8 ++static struct hifn_softc *hifn_chip_idx[HIFN_MAX_CHIPS]; ++ ++static __inline u_int32_t ++READ_REG_0(struct hifn_softc *sc, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar0 + reg); ++ sc->sc_bar0_lastreg = (bus_size_t) -1; ++ return (v); ++} ++#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val) ++ ++static __inline u_int32_t ++READ_REG_1(struct hifn_softc *sc, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar1 + reg); ++ sc->sc_bar1_lastreg = (bus_size_t) -1; ++ return (v); ++} ++#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val) ++ ++/* ++ * map in a given buffer (great on some arches :-) ++ */ ++ ++static int ++pci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio) ++{ ++ struct iovec *iov = uio->uio_iov; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) { ++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, ++ iov->iov_base, iov->iov_len, ++ PCI_DMA_BIDIRECTIONAL); ++ buf->segs[buf->nsegs].ds_len = iov->iov_len; ++ buf->mapsize += iov->iov_len; ++ iov++; ++ buf->nsegs++; ++ } ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given sk_buff ++ */ ++ ++static int ++pci_map_skb(struct hifn_softc *sc,struct hifn_operand *buf,struct sk_buff *skb) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ ++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, ++ skb->data, skb_headlen(skb), PCI_DMA_BIDIRECTIONAL); ++ buf->segs[0].ds_len = skb_headlen(skb); ++ buf->mapsize += buf->segs[0].ds_len; ++ ++ buf->nsegs = 1; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; ) { ++ buf->segs[buf->nsegs].ds_len = skb_shinfo(skb)->frags[i].size; ++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, ++ page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ buf->segs[buf->nsegs].ds_len, PCI_DMA_BIDIRECTIONAL); ++ buf->mapsize += buf->segs[buf->nsegs].ds_len; ++ buf->nsegs++; ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given contiguous buffer ++ */ ++ ++static int ++pci_map_buf(struct hifn_softc *sc,struct hifn_operand *buf, void *b, int len) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, ++ b, len, PCI_DMA_BIDIRECTIONAL); ++ buf->segs[0].ds_len = len; ++ buf->mapsize += buf->segs[0].ds_len; ++ buf->nsegs = 1; ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++#if 0 /* not needed at this time */ ++static void ++pci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ for (i = 0; i < buf->nsegs; i++) ++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++} ++#endif ++ ++static void ++pci_unmap_buf(struct hifn_softc *sc, struct hifn_operand *buf) ++{ ++ int i; ++ DPRINTF("%s()\n", __FUNCTION__); ++ for (i = 0; i < buf->nsegs; i++) { ++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++ buf->segs[i].ds_addr = 0; ++ buf->segs[i].ds_len = 0; ++ } ++ buf->nsegs = 0; ++ buf->mapsize = 0; ++ buf->map = 0; ++} ++ ++static const char* ++hifn_partname(struct hifn_softc *sc) ++{ ++ /* XXX sprintf numbers when not decoded */ ++ switch (pci_get_vendor(sc->sc_pcidev)) { ++ case PCI_VENDOR_HIFN: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; ++ case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; ++ case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; ++ case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; ++ case PCI_PRODUCT_HIFN_7955: return "Hifn 7955"; ++ case PCI_PRODUCT_HIFN_7956: return "Hifn 7956"; ++ } ++ return "Hifn unknown-part"; ++ case PCI_VENDOR_INVERTEX: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; ++ } ++ return "Invertex unknown-part"; ++ case PCI_VENDOR_NETSEC: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; ++ } ++ return "NetSec unknown-part"; ++ } ++ return "Unknown-vendor unknown-part"; ++} ++ ++static u_int ++checkmaxmin(struct pci_dev *dev, const char *what, u_int v, u_int min, u_int max) ++{ ++ struct hifn_softc *sc = pci_get_drvdata(dev); ++ if (v > max) { ++ device_printf(sc->sc_dev, "Warning, %s %u out of range, " ++ "using max %u\n", what, v, max); ++ v = max; ++ } else if (v < min) { ++ device_printf(sc->sc_dev, "Warning, %s %u out of range, " ++ "using min %u\n", what, v, min); ++ v = min; ++ } ++ return v; ++} ++ ++/* ++ * Select PLL configuration for 795x parts. This is complicated in ++ * that we cannot determine the optimal parameters without user input. ++ * The reference clock is derived from an external clock through a ++ * multiplier. The external clock is either the host bus (i.e. PCI) ++ * or an external clock generator. When using the PCI bus we assume ++ * the clock is either 33 or 66 MHz; for an external source we cannot ++ * tell the speed. ++ * ++ * PLL configuration is done with a string: "pci" for PCI bus, or "ext" ++ * for an external source, followed by the frequency. We calculate ++ * the appropriate multiplier and PLL register contents accordingly. ++ * When no configuration is given we default to "pci66" since that ++ * always will allow the card to work. If a card is using the PCI ++ * bus clock and in a 33MHz slot then it will be operating at half ++ * speed until the correct information is provided. ++ * ++ * We use a default setting of "ext66" because according to Mike Ham ++ * of HiFn, almost every board in existence has an external crystal ++ * populated at 66Mhz. Using PCI can be a problem on modern motherboards, ++ * because PCI33 can have clocks from 0 to 33Mhz, and some have ++ * non-PCI-compliant spread-spectrum clocks, which can confuse the pll. ++ */ ++static void ++hifn_getpllconfig(struct pci_dev *dev, u_int *pll) ++{ ++ const char *pllspec = hifn_pllconfig; ++ u_int freq, mul, fl, fh; ++ u_int32_t pllconfig; ++ char *nxt; ++ ++ if (pllspec == NULL) ++ pllspec = "ext66"; ++ fl = 33, fh = 66; ++ pllconfig = 0; ++ if (strncmp(pllspec, "ext", 3) == 0) { ++ pllspec += 3; ++ pllconfig |= HIFN_PLL_REF_SEL; ++ switch (pci_get_device(dev)) { ++ case PCI_PRODUCT_HIFN_7955: ++ case PCI_PRODUCT_HIFN_7956: ++ fl = 20, fh = 100; ++ break; ++#ifdef notyet ++ case PCI_PRODUCT_HIFN_7954: ++ fl = 20, fh = 66; ++ break; ++#endif ++ } ++ } else if (strncmp(pllspec, "pci", 3) == 0) ++ pllspec += 3; ++ freq = strtoul(pllspec, &nxt, 10); ++ if (nxt == pllspec) ++ freq = 66; ++ else ++ freq = checkmaxmin(dev, "frequency", freq, fl, fh); ++ /* ++ * Calculate multiplier. We target a Fck of 266 MHz, ++ * allowing only even values, possibly rounded down. ++ * Multipliers > 8 must set the charge pump current. ++ */ ++ mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12); ++ pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT; ++ if (mul > 8) ++ pllconfig |= HIFN_PLL_IS; ++ *pll = pllconfig; ++} ++ ++/* ++ * Attach an interface that successfully probed. ++ */ ++static int ++hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct hifn_softc *sc = NULL; ++ char rbase; ++ u_int16_t ena, rev; ++ int rseg, rc; ++ unsigned long mem_start, mem_len; ++ static int num_chips = 0; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (pci_set_mwi(dev)) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("hifn: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "hifn", num_chips, hifn_methods); ++ ++ sc->sc_pcidev = dev; ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_num = num_chips++; ++ if (sc->sc_num < HIFN_MAX_CHIPS) ++ hifn_chip_idx[sc->sc_num] = sc; ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ spin_lock_init(&sc->sc_mtx); ++ ++ /* XXX handle power management */ ++ ++ /* ++ * The 7951 and 795x have a random number generator and ++ * public key support; note this. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) ++ sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; ++ /* ++ * The 7811 has a random number generator and ++ * we also note it's identity 'cuz of some quirks. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) ++ sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; ++ ++ /* ++ * The 795x parts support AES. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) { ++ sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES; ++ /* ++ * Select PLL configuration. This depends on the ++ * bus and board design and must be manually configured ++ * if the default setting is unacceptable. ++ */ ++ hifn_getpllconfig(dev, &sc->sc_pllconfig); ++ } ++ ++ /* ++ * Setup PCI resources. Note that we record the bus ++ * tag and handle for each register mapping, this is ++ * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, ++ * and WRITE_REG_1 macros throughout the driver. ++ */ ++ mem_start = pci_resource_start(sc->sc_pcidev, 0); ++ mem_len = pci_resource_len(sc->sc_pcidev, 0); ++ sc->sc_bar0 = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar0) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 0); ++ goto fail; ++ } ++ sc->sc_bar0_lastreg = (bus_size_t) -1; ++ ++ mem_start = pci_resource_start(sc->sc_pcidev, 1); ++ mem_len = pci_resource_len(sc->sc_pcidev, 1); ++ sc->sc_bar1 = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar1) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 1); ++ goto fail; ++ } ++ sc->sc_bar1_lastreg = (bus_size_t) -1; ++ ++ /* fix up the bus size */ ++ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); ++ goto fail; ++ } ++ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, ++ "No usable consistent DMA configuration, aborting.\n"); ++ goto fail; ++ } ++ ++ hifn_set_retry(sc); ++ ++ /* ++ * Setup the area where the Hifn DMA's descriptors ++ * and associated data structures. ++ */ ++ sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev, ++ sizeof(*sc->sc_dma), ++ &sc->sc_dma_physaddr); ++ if (!sc->sc_dma) { ++ device_printf(sc->sc_dev, "cannot alloc sc_dma\n"); ++ goto fail; ++ } ++ bzero(sc->sc_dma, sizeof(*sc->sc_dma)); ++ ++ /* ++ * Reset the board and do the ``secret handshake'' ++ * to enable the crypto support. Then complete the ++ * initialization procedure by setting up the interrupt ++ * and hooking in to the system crypto support so we'll ++ * get used for system services like the crypto device, ++ * IPsec, RNG device, etc. ++ */ ++ hifn_reset_board(sc, 0); ++ ++ if (hifn_enable_crypto(sc) != 0) { ++ device_printf(sc->sc_dev, "crypto enabling failed\n"); ++ goto fail; ++ } ++ hifn_reset_puc(sc); ++ ++ hifn_init_dma(sc); ++ hifn_init_pci_registers(sc); ++ ++ pci_set_master(sc->sc_pcidev); ++ ++ /* XXX can't dynamically determine ram type for 795x; force dram */ ++ if (sc->sc_flags & HIFN_IS_7956) ++ sc->sc_drammodel = 1; ++ else if (hifn_ramtype(sc)) ++ goto fail; ++ ++ if (sc->sc_drammodel == 0) ++ hifn_sramsize(sc); ++ else ++ hifn_dramsize(sc); ++ ++ /* ++ * Workaround for NetSec 7751 rev A: half ram size because two ++ * of the address lines were left floating ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && ++ pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && ++ pci_get_revid(dev) == 0x61) /*XXX???*/ ++ sc->sc_ramsize >>= 1; ++ ++ /* ++ * Arrange the interrupt line. ++ */ ++ rc = request_irq(dev->irq, hifn_intr, IRQF_SHARED, "hifn", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); ++ goto fail; ++ } ++ sc->sc_irq = dev->irq; ++ ++ hifn_sessions(sc); ++ ++ /* ++ * NB: Keep only the low 16 bits; this masks the chip id ++ * from the 7951. ++ */ ++ rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; ++ ++ rseg = sc->sc_ramsize / 1024; ++ rbase = 'K'; ++ if (sc->sc_ramsize >= (1024 * 1024)) { ++ rbase = 'M'; ++ rseg /= 1024; ++ } ++ device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram", ++ hifn_partname(sc), rev, ++ rseg, rbase, sc->sc_drammodel ? 'd' : 's'); ++ if (sc->sc_flags & HIFN_IS_7956) ++ printf(", pll=0x%x<%s clk, %ux mult>", ++ sc->sc_pllconfig, ++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", ++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); ++ printf("\n"); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto fail; ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ++ READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); ++ ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++ switch (ena) { ++ case HIFN_PUSTAT_ENA_2: ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); ++ if (sc->sc_flags & HIFN_HAS_AES) ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ /*FALLTHROUGH*/ ++ case HIFN_PUSTAT_ENA_1: ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ break; ++ } ++ ++ if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) ++ hifn_init_pubrng(sc); ++ ++ init_timer(&sc->sc_tickto); ++ sc->sc_tickto.function = hifn_tick; ++ sc->sc_tickto.data = (unsigned long) sc->sc_num; ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++ ++ return (0); ++ ++fail: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_dma) { ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ pci_free_consistent(sc->sc_pcidev, ++ sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++ } ++ kfree(sc); ++ return (-ENXIO); ++} ++ ++/* ++ * Detach an interface that successfully probed. ++ */ ++static void ++hifn_remove(struct pci_dev *dev) ++{ ++ struct hifn_softc *sc = pci_get_drvdata(dev); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_detach: null software carrier!")); ++ ++ /* disable interrupts */ ++ HIFN_LOCK(sc); ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); ++ HIFN_UNLOCK(sc); ++ ++ /*XXX other resources */ ++ del_timer_sync(&sc->sc_tickto); ++ ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ free_irq(sc->sc_irq, sc); ++ ++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++} ++ ++ ++static int ++hifn_init_pubrng(struct hifn_softc *sc) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if ((sc->sc_flags & HIFN_IS_7811) == 0) { ++ /* Reset 7951 public key/rng engine */ ++ WRITE_REG_1(sc, HIFN_1_PUB_RESET, ++ READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET); ++ ++ for (i = 0; i < 100; i++) { ++ DELAY(1000); ++ if ((READ_REG_1(sc, HIFN_1_PUB_RESET) & ++ HIFN_PUBRST_RESET) == 0) ++ break; ++ } ++ ++ if (i == 100) { ++ device_printf(sc->sc_dev, "public key init failed\n"); ++ return (1); ++ } ++ } ++ ++ /* Enable the rng, if available */ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ if (sc->sc_flags & HIFN_HAS_RNG) { ++ if (sc->sc_flags & HIFN_IS_7811) { ++ u_int32_t r; ++ r = READ_REG_1(sc, HIFN_1_7811_RNGENA); ++ if (r & HIFN_7811_RNGENA_ENA) { ++ r &= ~HIFN_7811_RNGENA_ENA; ++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); ++ } ++ WRITE_REG_1(sc, HIFN_1_7811_RNGCFG, ++ HIFN_7811_RNGCFG_DEFL); ++ r |= HIFN_7811_RNGENA_ENA; ++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); ++ } else ++ WRITE_REG_1(sc, HIFN_1_RNG_CONFIG, ++ READ_REG_1(sc, HIFN_1_RNG_CONFIG) | ++ HIFN_RNGCFG_ENA); ++ ++ sc->sc_rngfirst = 1; ++ crypto_rregister(sc->sc_cid, hifn_read_random, sc); ++ } ++#endif ++ ++ /* Enable public key engine, if available */ ++ if (sc->sc_flags & HIFN_HAS_PUBLIC) { ++ WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); ++ sc->sc_dmaier |= HIFN_DMAIER_PUBDONE; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++#ifdef HIFN_VULCANDEV ++ sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0, ++ UID_ROOT, GID_WHEEL, 0666, ++ "vulcanpk"); ++ sc->sc_pkdev->si_drv1 = sc; ++#endif ++ } ++ ++ return (0); ++} ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int ++hifn_read_random(void *arg, u_int32_t *buf, int len) ++{ ++ struct hifn_softc *sc = (struct hifn_softc *) arg; ++ u_int32_t sts; ++ int i, rc = 0; ++ ++ if (len <= 0) ++ return rc; ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ /* ONLY VALID ON 7811!!!! */ ++ for (i = 0; i < 5; i++) { ++ sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS); ++ if (sts & HIFN_7811_RNGSTS_UFL) { ++ device_printf(sc->sc_dev, ++ "RNG underflow: disabling\n"); ++ /* DAVIDM perhaps return -1 */ ++ break; ++ } ++ if ((sts & HIFN_7811_RNGSTS_RDY) == 0) ++ break; ++ ++ /* ++ * There are at least two words in the RNG FIFO ++ * at this point. ++ */ ++ if (rc < len) ++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); ++ if (rc < len) ++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); ++ } ++ } else ++ buf[rc++] = READ_REG_1(sc, HIFN_1_RNG_DATA); ++ ++ /* NB: discard first data read */ ++ if (sc->sc_rngfirst) { ++ sc->sc_rngfirst = 0; ++ rc = 0; ++ } ++ ++ return(rc); ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++static void ++hifn_puc_wait(struct hifn_softc *sc) ++{ ++ int i; ++ int reg = HIFN_0_PUCTRL; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ reg = HIFN_0_PUCTRL2; ++ } ++ ++ for (i = 5000; i > 0; i--) { ++ DELAY(1); ++ if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET)) ++ break; ++ } ++ if (!i) ++ device_printf(sc->sc_dev, "proc unit did not reset(0x%x)\n", ++ READ_REG_0(sc, HIFN_0_PUCTRL)); ++} ++ ++/* ++ * Reset the processing unit. ++ */ ++static void ++hifn_reset_puc(struct hifn_softc *sc) ++{ ++ /* Reset processing unit */ ++ int reg = HIFN_0_PUCTRL; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ reg = HIFN_0_PUCTRL2; ++ } ++ WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA); ++ ++ hifn_puc_wait(sc); ++} ++ ++/* ++ * Set the Retry and TRDY registers; note that we set them to ++ * zero because the 7811 locks up when forced to retry (section ++ * 3.6 of "Specification Update SU-0014-04". Not clear if we ++ * should do this for all Hifn parts, but it doesn't seem to hurt. ++ */ ++static void ++hifn_set_retry(struct hifn_softc *sc) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* NB: RETRY only responds to 8-bit reads/writes */ ++ pci_write_config_byte(sc->sc_pcidev, HIFN_RETRY_TIMEOUT, 0); ++ pci_write_config_dword(sc->sc_pcidev, HIFN_TRDY_TIMEOUT, 0); ++} ++ ++/* ++ * Resets the board. Values in the regesters are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++hifn_reset_board(struct hifn_softc *sc, int full) ++{ ++ u_int32_t reg; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* ++ * Set polling in the DMA configuration register to zero. 0x7 avoids ++ * resetting the board and zeros out the other fields. ++ */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ /* ++ * Now that polling has been disabled, we have to wait 1 ms ++ * before resetting the board. ++ */ ++ DELAY(1000); ++ ++ /* Reset the DMA unit */ ++ if (full) { ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); ++ DELAY(1000); ++ } else { ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, ++ HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET); ++ hifn_reset_puc(sc); ++ } ++ ++ KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!")); ++ bzero(sc->sc_dma, sizeof(*sc->sc_dma)); ++ ++ /* Bring dma unit out of reset */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ hifn_puc_wait(sc); ++ hifn_set_retry(sc); ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ for (reg = 0; reg < 1000; reg++) { ++ if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) & ++ HIFN_MIPSRST_CRAMINIT) ++ break; ++ DELAY(1000); ++ } ++ if (reg == 1000) ++ device_printf(sc->sc_dev, ": cram init timeout\n"); ++ } else { ++ /* set up DMA configuration register #2 */ ++ /* turn off all PK and BAR0 swaps */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG2, ++ (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)| ++ (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)| ++ (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)| ++ (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT)); ++ } ++} ++ ++static u_int32_t ++hifn_next_signature(u_int32_t a, u_int cnt) ++{ ++ int i; ++ u_int32_t v; ++ ++ for (i = 0; i < cnt; i++) { ++ ++ /* get the parity */ ++ v = a & 0x80080125; ++ v ^= v >> 16; ++ v ^= v >> 8; ++ v ^= v >> 4; ++ v ^= v >> 2; ++ v ^= v >> 1; ++ ++ a = (v & 1) ^ (a << 1); ++ } ++ ++ return a; ++} ++ ++ ++/* ++ * Checks to see if crypto is already enabled. If crypto isn't enable, ++ * "hifn_enable_crypto" is called to enable it. The check is important, ++ * as enabling crypto twice will lock the board. ++ */ ++static int ++hifn_enable_crypto(struct hifn_softc *sc) ++{ ++ u_int32_t dmacfg, ramcfg, encl, addr, i; ++ char offtbl[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00 }; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG); ++ dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG); ++ ++ /* ++ * The RAM config register's encrypt level bit needs to be set before ++ * every read performed on the encryption level register. ++ */ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); ++ ++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++ /* ++ * Make sure we don't re-unlock. Two unlocks kills chip until the ++ * next reboot. ++ */ ++ if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "Strong crypto already enabled!\n"); ++#endif ++ goto report; ++ } ++ ++ if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "Unknown encryption level 0x%x\n", encl); ++#endif ++ return 1; ++ } ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK | ++ HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ DELAY(1000); ++ addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1); ++ DELAY(1000); ++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0); ++ DELAY(1000); ++ ++ for (i = 0; i <= 12; i++) { ++ addr = hifn_next_signature(addr, offtbl[i] + 0x101); ++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr); ++ ++ DELAY(1000); ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); ++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2) ++ device_printf(sc->sc_dev, "Engine is permanently " ++ "locked until next system reset!\n"); ++ else ++ device_printf(sc->sc_dev, "Engine enabled " ++ "successfully!\n"); ++ } ++#endif ++ ++report: ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg); ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg); ++ ++ switch (encl) { ++ case HIFN_PUSTAT_ENA_1: ++ case HIFN_PUSTAT_ENA_2: ++ break; ++ case HIFN_PUSTAT_ENA_0: ++ default: ++ device_printf(sc->sc_dev, "disabled\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Give initial values to the registers listed in the "Register Space" ++ * section of the HIFN Software Development reference manual. ++ */ ++static void ++hifn_init_pci_registers(struct hifn_softc *sc) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* write fixed values needed by the Initialization registers */ ++ WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); ++ WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); ++ WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); ++ ++ /* write all 4 ring address registers */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, cmdr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, srcr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, dstr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, resr[0])); ++ ++ DELAY(2000); ++ ++ /* write status register */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | ++ HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | ++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | ++ HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | ++ HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | ++ HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | ++ HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | ++ HIFN_DMACSR_S_WAIT | ++ HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | ++ HIFN_DMACSR_C_WAIT | ++ HIFN_DMACSR_ENGINE | ++ ((sc->sc_flags & HIFN_HAS_PUBLIC) ? ++ HIFN_DMACSR_PUBDONE : 0) | ++ ((sc->sc_flags & HIFN_IS_7811) ? ++ HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0)); ++ ++ sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0; ++ sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | ++ HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | ++ HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | ++ ((sc->sc_flags & HIFN_IS_7811) ? ++ HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0); ++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ u_int32_t pll; ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | ++ HIFN_PUCNFG_TCALLPHASES | ++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32); ++ ++ /* turn off the clocks and insure bypass is set */ ++ pll = READ_REG_1(sc, HIFN_1_PLL); ++ pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL)) ++ | HIFN_PLL_BP | HIFN_PLL_MBSET; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ DELAY(10*1000); /* 10ms */ ++ ++ /* change configuration */ ++ pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ DELAY(10*1000); /* 10ms */ ++ ++ /* disable bypass */ ++ pll &= ~HIFN_PLL_BP; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ /* enable clocks with new configuration */ ++ pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ } else { ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | ++ HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | ++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | ++ (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM)); ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | ++ ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | ++ ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); ++} ++ ++/* ++ * The maximum number of sessions supported by the card ++ * is dependent on the amount of context ram, which ++ * encryption algorithms are enabled, and how compression ++ * is configured. This should be configured before this ++ * routine is called. ++ */ ++static void ++hifn_sessions(struct hifn_softc *sc) ++{ ++ u_int32_t pucnfg; ++ int ctxsize; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG); ++ ++ if (pucnfg & HIFN_PUCNFG_COMPSING) { ++ if (pucnfg & HIFN_PUCNFG_ENCCNFG) ++ ctxsize = 128; ++ else ++ ctxsize = 512; ++ /* ++ * 7955/7956 has internal context memory of 32K ++ */ ++ if (sc->sc_flags & HIFN_IS_7956) ++ sc->sc_maxses = 32768 / ctxsize; ++ else ++ sc->sc_maxses = 1 + ++ ((sc->sc_ramsize - 32768) / ctxsize); ++ } else ++ sc->sc_maxses = sc->sc_ramsize / 16384; ++ ++ if (sc->sc_maxses > 2048) ++ sc->sc_maxses = 2048; ++} ++ ++/* ++ * Determine ram type (sram or dram). Board should be just out of a reset ++ * state when this is called. ++ */ ++static int ++hifn_ramtype(struct hifn_softc *sc) ++{ ++ u_int8_t data[8], dataexpect[8]; ++ int i; ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = 0x55; ++ if (hifn_writeramaddr(sc, 0, data)) ++ return (-1); ++ if (hifn_readramaddr(sc, 0, data)) ++ return (-1); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) { ++ sc->sc_drammodel = 1; ++ return (0); ++ } ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = 0xaa; ++ if (hifn_writeramaddr(sc, 0, data)) ++ return (-1); ++ if (hifn_readramaddr(sc, 0, data)) ++ return (-1); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) { ++ sc->sc_drammodel = 1; ++ return (0); ++ } ++ ++ return (0); ++} ++ ++#define HIFN_SRAM_MAX (32 << 20) ++#define HIFN_SRAM_STEP_SIZE 16384 ++#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE) ++ ++static int ++hifn_sramsize(struct hifn_softc *sc) ++{ ++ u_int32_t a; ++ u_int8_t data[8]; ++ u_int8_t dataexpect[sizeof(data)]; ++ int32_t i; ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = i ^ 0x5a; ++ ++ for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) { ++ a = i * HIFN_SRAM_STEP_SIZE; ++ bcopy(&i, data, sizeof(i)); ++ hifn_writeramaddr(sc, a, data); ++ } ++ ++ for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) { ++ a = i * HIFN_SRAM_STEP_SIZE; ++ bcopy(&i, dataexpect, sizeof(i)); ++ if (hifn_readramaddr(sc, a, data) < 0) ++ return (0); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) ++ return (0); ++ sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE; ++ } ++ ++ return (0); ++} ++ ++/* ++ * XXX For dram boards, one should really try all of the ++ * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG ++ * is already set up correctly. ++ */ ++static int ++hifn_dramsize(struct hifn_softc *sc) ++{ ++ u_int32_t cnfg; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ /* ++ * 7955/7956 have a fixed internal ram of only 32K. ++ */ ++ sc->sc_ramsize = 32768; ++ } else { ++ cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) & ++ HIFN_PUCNFG_DRAMMASK; ++ sc->sc_ramsize = 1 << ((cnfg >> 13) + 18); ++ } ++ return (0); ++} ++ ++static void ++hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (dma->cmdi == HIFN_D_CMD_RSIZE) { ++ dma->cmdi = 0; ++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *cmdp = dma->cmdi++; ++ dma->cmdk = dma->cmdi; ++ ++ if (dma->srci == HIFN_D_SRC_RSIZE) { ++ dma->srci = 0; ++ dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->srcr[HIFN_D_SRC_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *srcp = dma->srci++; ++ dma->srck = dma->srci; ++ ++ if (dma->dsti == HIFN_D_DST_RSIZE) { ++ dma->dsti = 0; ++ dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->dstr[HIFN_D_DST_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *dstp = dma->dsti++; ++ dma->dstk = dma->dsti; ++ ++ if (dma->resi == HIFN_D_RES_RSIZE) { ++ dma->resi = 0; ++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *resp = dma->resi++; ++ dma->resk = dma->resi; ++} ++ ++static int ++hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ hifn_base_command_t wc; ++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; ++ int r, cmdi, resi, srci, dsti; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ wc.masks = htole16(3 << 13); ++ wc.session_num = htole16(addr >> 14); ++ wc.total_source_count = htole16(8); ++ wc.total_dest_count = htole16(addr & 0x3fff); ++ ++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | ++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); ++ ++ /* build write command */ ++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); ++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc; ++ bcopy(data, &dma->test_src, sizeof(dma->test_src)); ++ ++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr ++ + offsetof(struct hifn_dma, test_src)); ++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr ++ + offsetof(struct hifn_dma, test_dst)); ++ ++ dma->cmdr[cmdi].l = htole32(16 | masks); ++ dma->srcr[srci].l = htole32(8 | masks); ++ dma->dstr[dsti].l = htole32(4 | masks); ++ dma->resr[resi].l = htole32(4 | masks); ++ ++ for (r = 10000; r >= 0; r--) { ++ DELAY(10); ++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) ++ break; ++ } ++ if (r == 0) { ++ device_printf(sc->sc_dev, "writeramaddr -- " ++ "result[%d](addr %d) still valid\n", resi, addr); ++ r = -1; ++ return (-1); ++ } else ++ r = 0; ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); ++ ++ return (r); ++} ++ ++static int ++hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ hifn_base_command_t rc; ++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; ++ int r, cmdi, srci, dsti, resi; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ rc.masks = htole16(2 << 13); ++ rc.session_num = htole16(addr >> 14); ++ rc.total_source_count = htole16(addr & 0x3fff); ++ rc.total_dest_count = htole16(8); ++ ++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | ++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); ++ ++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); ++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc; ++ ++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, test_src)); ++ dma->test_src = 0; ++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, test_dst)); ++ dma->test_dst = 0; ++ dma->cmdr[cmdi].l = htole32(8 | masks); ++ dma->srcr[srci].l = htole32(8 | masks); ++ dma->dstr[dsti].l = htole32(8 | masks); ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks); ++ ++ for (r = 10000; r >= 0; r--) { ++ DELAY(10); ++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) ++ break; ++ } ++ if (r == 0) { ++ device_printf(sc->sc_dev, "readramaddr -- " ++ "result[%d](addr %d) still valid\n", resi, addr); ++ r = -1; ++ } else { ++ r = 0; ++ bcopy(&dma->test_dst, data, sizeof(dma->test_dst)); ++ } ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); ++ ++ return (r); ++} ++ ++/* ++ * Initialize the descriptor rings. ++ */ ++static void ++hifn_init_dma(struct hifn_softc *sc) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ hifn_set_retry(sc); ++ ++ /* initialize static pointer values */ ++ for (i = 0; i < HIFN_D_CMD_RSIZE; i++) ++ dma->cmdr[i].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, command_bufs[i][0])); ++ for (i = 0; i < HIFN_D_RES_RSIZE; i++) ++ dma->resr[i].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, result_bufs[i][0])); ++ ++ dma->cmdr[HIFN_D_CMD_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0])); ++ dma->srcr[HIFN_D_SRC_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0])); ++ dma->dstr[HIFN_D_DST_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0])); ++ dma->resr[HIFN_D_RES_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); ++ ++ dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; ++ dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; ++ dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; ++} ++ ++/* ++ * Writes out the raw command buffer space. Returns the ++ * command buffer size. ++ */ ++static u_int ++hifn_write_command(struct hifn_command *cmd, u_int8_t *buf) ++{ ++ struct hifn_softc *sc = NULL; ++ u_int8_t *buf_pos; ++ hifn_base_command_t *base_cmd; ++ hifn_mac_command_t *mac_cmd; ++ hifn_crypt_command_t *cry_cmd; ++ int using_mac, using_crypt, len, ivlen; ++ u_int32_t dlen, slen; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf_pos = buf; ++ using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC; ++ using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT; ++ ++ base_cmd = (hifn_base_command_t *)buf_pos; ++ base_cmd->masks = htole16(cmd->base_masks); ++ slen = cmd->src_mapsize; ++ if (cmd->sloplen) ++ dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t); ++ else ++ dlen = cmd->dst_mapsize; ++ base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO); ++ base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO); ++ dlen >>= 16; ++ slen >>= 16; ++ base_cmd->session_num = htole16( ++ ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | ++ ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); ++ buf_pos += sizeof(hifn_base_command_t); ++ ++ if (using_mac) { ++ mac_cmd = (hifn_mac_command_t *)buf_pos; ++ dlen = cmd->maccrd->crd_len; ++ mac_cmd->source_count = htole16(dlen & 0xffff); ++ dlen >>= 16; ++ mac_cmd->masks = htole16(cmd->mac_masks | ++ ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M)); ++ mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip); ++ mac_cmd->reserved = 0; ++ buf_pos += sizeof(hifn_mac_command_t); ++ } ++ ++ if (using_crypt) { ++ cry_cmd = (hifn_crypt_command_t *)buf_pos; ++ dlen = cmd->enccrd->crd_len; ++ cry_cmd->source_count = htole16(dlen & 0xffff); ++ dlen >>= 16; ++ cry_cmd->masks = htole16(cmd->cry_masks | ++ ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M)); ++ cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip); ++ cry_cmd->reserved = 0; ++ buf_pos += sizeof(hifn_crypt_command_t); ++ } ++ ++ if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) { ++ bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH); ++ buf_pos += HIFN_MAC_KEY_LENGTH; ++ } ++ ++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) { ++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { ++ case HIFN_CRYPT_CMD_ALG_3DES: ++ bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH); ++ buf_pos += HIFN_3DES_KEY_LENGTH; ++ break; ++ case HIFN_CRYPT_CMD_ALG_DES: ++ bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH); ++ buf_pos += HIFN_DES_KEY_LENGTH; ++ break; ++ case HIFN_CRYPT_CMD_ALG_RC4: ++ len = 256; ++ do { ++ int clen; ++ ++ clen = MIN(cmd->cklen, len); ++ bcopy(cmd->ck, buf_pos, clen); ++ len -= clen; ++ buf_pos += clen; ++ } while (len > 0); ++ bzero(buf_pos, 4); ++ buf_pos += 4; ++ break; ++ case HIFN_CRYPT_CMD_ALG_AES: ++ /* ++ * AES keys are variable 128, 192 and ++ * 256 bits (16, 24 and 32 bytes). ++ */ ++ bcopy(cmd->ck, buf_pos, cmd->cklen); ++ buf_pos += cmd->cklen; ++ break; ++ } ++ } ++ ++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) { ++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { ++ case HIFN_CRYPT_CMD_ALG_AES: ++ ivlen = HIFN_AES_IV_LENGTH; ++ break; ++ default: ++ ivlen = HIFN_IV_LENGTH; ++ break; ++ } ++ bcopy(cmd->iv, buf_pos, ivlen); ++ buf_pos += ivlen; ++ } ++ ++ if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) { ++ bzero(buf_pos, 8); ++ buf_pos += 8; ++ } ++ ++ return (buf_pos - buf); ++} ++ ++static int ++hifn_dmamap_aligned(struct hifn_operand *op) ++{ ++ struct hifn_softc *sc = NULL; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ for (i = 0; i < op->nsegs; i++) { ++ if (op->segs[i].ds_addr & 3) ++ return (0); ++ if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3)) ++ return (0); ++ } ++ return (1); ++} ++ ++static __inline int ++hifn_dmamap_dstwrap(struct hifn_softc *sc, int idx) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ if (++idx == HIFN_D_DST_RSIZE) { ++ dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | ++ HIFN_D_MASKDONEIRQ); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ idx = 0; ++ } ++ return (idx); ++} ++ ++static int ++hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_operand *dst = &cmd->dst; ++ u_int32_t p, l; ++ int idx, used = 0, i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ idx = dma->dsti; ++ for (i = 0; i < dst->nsegs - 1; i++) { ++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); ++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ } ++ ++ if (cmd->sloplen == 0) { ++ p = dst->segs[i].ds_addr; ++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | ++ dst->segs[i].ds_len; ++ } else { ++ p = sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, slop[cmd->slopidx]); ++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | ++ sizeof(u_int32_t); ++ ++ if ((dst->segs[i].ds_len - cmd->sloplen) != 0) { ++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); ++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | ++ (dst->segs[i].ds_len - cmd->sloplen)); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ } ++ } ++ dma->dstr[idx].p = htole32(p); ++ dma->dstr[idx].l = htole32(l); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ ++ dma->dsti = idx; ++ dma->dstu += used; ++ return (idx); ++} ++ ++static __inline int ++hifn_dmamap_srcwrap(struct hifn_softc *sc, int idx) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ if (++idx == HIFN_D_SRC_RSIZE) { ++ dma->srcr[idx].l = htole32(HIFN_D_VALID | ++ HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); ++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ idx = 0; ++ } ++ return (idx); ++} ++ ++static int ++hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_operand *src = &cmd->src; ++ int idx, i; ++ u_int32_t last = 0; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ idx = dma->srci; ++ for (i = 0; i < src->nsegs; i++) { ++ if (i == src->nsegs - 1) ++ last = HIFN_D_LAST; ++ ++ dma->srcr[idx].p = htole32(src->segs[i].ds_addr); ++ dma->srcr[idx].l = htole32(src->segs[i].ds_len | ++ HIFN_D_MASKDONEIRQ | last); ++ wmb(); ++ dma->srcr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_SRCR_SYNC(sc, idx, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ ++ idx = hifn_dmamap_srcwrap(sc, idx); ++ } ++ dma->srci = idx; ++ dma->srcu += src->nsegs; ++ return (idx); ++} ++ ++ ++static int ++hifn_crypto( ++ struct hifn_softc *sc, ++ struct hifn_command *cmd, ++ struct cryptop *crp, ++ int hint) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ u_int32_t cmdlen, csr; ++ int cmdi, resi, err = 0; ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* ++ * need 1 cmd, and 1 res ++ * ++ * NB: check this first since it's easy. ++ */ ++ HIFN_LOCK(sc); ++ if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE || ++ (dma->resu + 1) > HIFN_D_RES_RSIZE) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "cmd/result exhaustion, cmdu %u resu %u\n", ++ dma->cmdu, dma->resu); ++ } ++#endif ++ hifnstats.hst_nomem_cr++; ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ HIFN_UNLOCK(sc); ++ return (ERESTART); ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &cmd->src, cmd->src_skb)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &cmd->src, cmd->src_io)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } else { ++ if (pci_map_buf(sc, &cmd->src, cmd->src_buf, crp->crp_ilen)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } ++ ++ if (hifn_dmamap_aligned(&cmd->src)) { ++ cmd->sloplen = cmd->src_mapsize & 3; ++ cmd->dst = cmd->src; ++ } else { ++ if (crp->crp_flags & CRYPTO_F_IOV) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto err_srcmap; ++ } else if (crp->crp_flags & CRYPTO_F_SKBUF) { ++#ifdef NOTYET ++ int totlen, len; ++ struct mbuf *m, *m0, *mlast; ++ ++ KASSERT(cmd->dst_m == cmd->src_m, ++ ("hifn_crypto: dst_m initialized improperly")); ++ hifnstats.hst_unaligned++; ++ /* ++ * Source is not aligned on a longword boundary. ++ * Copy the data to insure alignment. If we fail ++ * to allocate mbufs or clusters while doing this ++ * we return ERESTART so the operation is requeued ++ * at the crypto later, but only if there are ++ * ops already posted to the hardware; otherwise we ++ * have no guarantee that we'll be re-entered. ++ */ ++ totlen = cmd->src_mapsize; ++ if (cmd->src_m->m_flags & M_PKTHDR) { ++ len = MHLEN; ++ MGETHDR(m0, M_DONTWAIT, MT_DATA); ++ if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) { ++ m_free(m0); ++ m0 = NULL; ++ } ++ } else { ++ len = MLEN; ++ MGET(m0, M_DONTWAIT, MT_DATA); ++ } ++ if (m0 == NULL) { ++ hifnstats.hst_nomem_mbuf++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ goto err_srcmap; ++ } ++ if (totlen >= MINCLSIZE) { ++ MCLGET(m0, M_DONTWAIT); ++ if ((m0->m_flags & M_EXT) == 0) { ++ hifnstats.hst_nomem_mcl++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MCLBYTES; ++ } ++ totlen -= len; ++ m0->m_pkthdr.len = m0->m_len = len; ++ mlast = m0; ++ ++ while (totlen > 0) { ++ MGET(m, M_DONTWAIT, MT_DATA); ++ if (m == NULL) { ++ hifnstats.hst_nomem_mbuf++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MLEN; ++ if (totlen >= MINCLSIZE) { ++ MCLGET(m, M_DONTWAIT); ++ if ((m->m_flags & M_EXT) == 0) { ++ hifnstats.hst_nomem_mcl++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ mlast->m_next = m; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MCLBYTES; ++ } ++ ++ m->m_len = len; ++ m0->m_pkthdr.len += len; ++ totlen -= len; ++ ++ mlast->m_next = m; ++ mlast = m; ++ } ++ cmd->dst_m = m0; ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n", ++ __FILE__, __LINE__); ++ err = EINVAL; ++ goto err_srcmap; ++#endif ++ } else { ++ device_printf(sc->sc_dev, ++ "%s,%d: unaligned contig buffers not implemented\n", ++ __FILE__, __LINE__); ++ err = EINVAL; ++ goto err_srcmap; ++ } ++ } ++ ++ if (cmd->dst_map == NULL) { ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &cmd->dst, cmd->dst_skb)) { ++ hifnstats.hst_nomem_map++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &cmd->dst, cmd->dst_io)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } else { ++ if (pci_map_buf(sc, &cmd->dst, cmd->dst_buf, crp->crp_ilen)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } ++ } ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", ++ READ_REG_1(sc, HIFN_1_DMA_CSR), ++ READ_REG_1(sc, HIFN_1_DMA_IER), ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu, ++ cmd->src_nsegs, cmd->dst_nsegs); ++ } ++#endif ++ ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_PREWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_PREREAD); ++ } ++#endif ++ ++ /* ++ * need N src, and N dst ++ */ ++ if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || ++ (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", ++ dma->srcu, cmd->src_nsegs, ++ dma->dstu, cmd->dst_nsegs); ++ } ++#endif ++ hifnstats.hst_nomem_sd++; ++ err = ERESTART; ++ goto err_dstmap; ++ } ++ ++ if (dma->cmdi == HIFN_D_CMD_RSIZE) { ++ dma->cmdi = 0; ++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ cmdi = dma->cmdi++; ++ cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); ++ HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); ++ ++ /* .p for command/result already set */ ++ dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_LAST | ++ HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[cmdi].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, cmdi, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ dma->cmdu++; ++ ++ /* ++ * We don't worry about missing an interrupt (which a "command wait" ++ * interrupt salvages us from), unless there is more than one command ++ * in the queue. ++ */ ++ if (dma->cmdu > 1) { ++ sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ } ++ ++ hifnstats.hst_ipackets++; ++ hifnstats.hst_ibytes += cmd->src_mapsize; ++ ++ hifn_dmamap_load_src(sc, cmd); ++ ++ /* ++ * Unlike other descriptors, we don't mask done interrupt from ++ * result descriptor. ++ */ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, "load res\n"); ++#endif ++ if (dma->resi == HIFN_D_RES_RSIZE) { ++ dma->resi = 0; ++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ } ++ resi = dma->resi++; ++ KASSERT(dma->hifn_commands[resi] == NULL, ++ ("hifn_crypto: command slot %u busy", resi)); ++ dma->hifn_commands[resi] = cmd; ++ HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); ++ if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | ++ HIFN_D_LAST | HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[resi].l |= htole32(HIFN_D_VALID); ++ sc->sc_curbatch++; ++ if (sc->sc_curbatch > hifnstats.hst_maxbatch) ++ hifnstats.hst_maxbatch = sc->sc_curbatch; ++ hifnstats.hst_totbatch++; ++ } else { ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | HIFN_D_LAST); ++ wmb(); ++ dma->resr[resi].l |= htole32(HIFN_D_VALID); ++ sc->sc_curbatch = 0; ++ } ++ HIFN_RESR_SYNC(sc, resi, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ dma->resu++; ++ ++ if (cmd->sloplen) ++ cmd->slopidx = resi; ++ ++ hifn_dmamap_load_dst(sc, cmd); ++ ++ csr = 0; ++ if (sc->sc_c_busy == 0) { ++ csr |= HIFN_DMACSR_C_CTRL_ENA; ++ sc->sc_c_busy = 1; ++ } ++ if (sc->sc_s_busy == 0) { ++ csr |= HIFN_DMACSR_S_CTRL_ENA; ++ sc->sc_s_busy = 1; ++ } ++ if (sc->sc_r_busy == 0) { ++ csr |= HIFN_DMACSR_R_CTRL_ENA; ++ sc->sc_r_busy = 1; ++ } ++ if (sc->sc_d_busy == 0) { ++ csr |= HIFN_DMACSR_D_CTRL_ENA; ++ sc->sc_d_busy = 1; ++ } ++ if (csr) ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr); ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, "command: stat %8x ier %8x\n", ++ READ_REG_1(sc, HIFN_1_DMA_CSR), ++ READ_REG_1(sc, HIFN_1_DMA_IER)); ++ } ++#endif ++ ++ sc->sc_active = 5; ++ HIFN_UNLOCK(sc); ++ KASSERT(err == 0, ("hifn_crypto: success with error %u", err)); ++ return (err); /* success */ ++ ++err_dstmap: ++ if (cmd->src_map != cmd->dst_map) ++ pci_unmap_buf(sc, &cmd->dst); ++err_dstmap1: ++err_srcmap: ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (cmd->src_skb != cmd->dst_skb) ++#ifdef NOTYET ++ m_freem(cmd->dst_m); ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ pci_unmap_buf(sc, &cmd->src); ++err_srcmap1: ++ HIFN_UNLOCK(sc); ++ return (err); ++} ++ ++static void ++hifn_tick(unsigned long arg) ++{ ++ struct hifn_softc *sc; ++ unsigned long l_flags; ++ ++ if (arg >= HIFN_MAX_CHIPS) ++ return; ++ sc = hifn_chip_idx[arg]; ++ if (!sc) ++ return; ++ ++ HIFN_LOCK(sc); ++ if (sc->sc_active == 0) { ++ struct hifn_dma *dma = sc->sc_dma; ++ u_int32_t r = 0; ++ ++ if (dma->cmdu == 0 && sc->sc_c_busy) { ++ sc->sc_c_busy = 0; ++ r |= HIFN_DMACSR_C_CTRL_DIS; ++ } ++ if (dma->srcu == 0 && sc->sc_s_busy) { ++ sc->sc_s_busy = 0; ++ r |= HIFN_DMACSR_S_CTRL_DIS; ++ } ++ if (dma->dstu == 0 && sc->sc_d_busy) { ++ sc->sc_d_busy = 0; ++ r |= HIFN_DMACSR_D_CTRL_DIS; ++ } ++ if (dma->resu == 0 && sc->sc_r_busy) { ++ sc->sc_r_busy = 0; ++ r |= HIFN_DMACSR_R_CTRL_DIS; ++ } ++ if (r) ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, r); ++ } else ++ sc->sc_active--; ++ HIFN_UNLOCK(sc); ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++} ++ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++hifn_intr(int irq, void *arg) ++#else ++hifn_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct hifn_softc *sc = arg; ++ struct hifn_dma *dma; ++ u_int32_t dmacsr, restart; ++ int i, u; ++ unsigned long l_flags; ++ ++ dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR); ++ ++ /* Nothing in the DMA unit interrupted */ ++ if ((dmacsr & sc->sc_dmaier) == 0) ++ return IRQ_NONE; ++ ++ HIFN_LOCK(sc); ++ ++ dma = sc->sc_dma; ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", ++ dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, ++ dma->cmdi, dma->srci, dma->dsti, dma->resi, ++ dma->cmdk, dma->srck, dma->dstk, dma->resk, ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu); ++ } ++#endif ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier); ++ ++ if ((sc->sc_flags & HIFN_HAS_PUBLIC) && ++ (dmacsr & HIFN_DMACSR_PUBDONE)) ++ WRITE_REG_1(sc, HIFN_1_PUB_STATUS, ++ READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); ++ ++ restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER); ++ if (restart) ++ device_printf(sc->sc_dev, "overrun %x\n", dmacsr); ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (dmacsr & HIFN_DMACSR_ILLR) ++ device_printf(sc->sc_dev, "illegal read\n"); ++ if (dmacsr & HIFN_DMACSR_ILLW) ++ device_printf(sc->sc_dev, "illegal write\n"); ++ } ++ ++ restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | ++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); ++ if (restart) { ++ device_printf(sc->sc_dev, "abort, resetting.\n"); ++ hifnstats.hst_abort++; ++ hifn_abort(sc); ++ HIFN_UNLOCK(sc); ++ return IRQ_HANDLED; ++ } ++ ++ if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { ++ /* ++ * If no slots to process and we receive a "waiting on ++ * command" interrupt, we disable the "waiting on command" ++ * (by clearing it). ++ */ ++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ } ++ ++ /* clear the rings */ ++ i = dma->resk; u = dma->resu; ++ while (u != 0) { ++ HIFN_RESR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->resr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_RESR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ ++ if (i != HIFN_D_RES_RSIZE) { ++ struct hifn_command *cmd; ++ u_int8_t *macbuf = NULL; ++ ++ HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); ++ cmd = dma->hifn_commands[i]; ++ KASSERT(cmd != NULL, ++ ("hifn_intr: null command slot %u", i)); ++ dma->hifn_commands[i] = NULL; ++ ++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) { ++ macbuf = dma->result_bufs[i]; ++ macbuf += 12; ++ } ++ ++ hifn_callback(sc, cmd, macbuf); ++ hifnstats.hst_opackets++; ++ u--; ++ } ++ ++ if (++i == (HIFN_D_RES_RSIZE + 1)) ++ i = 0; ++ } ++ dma->resk = i; dma->resu = u; ++ ++ i = dma->srck; u = dma->srcu; ++ while (u != 0) { ++ if (i == HIFN_D_SRC_RSIZE) ++ i = 0; ++ HIFN_SRCR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->srcr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_SRCR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ i++, u--; ++ } ++ dma->srck = i; dma->srcu = u; ++ ++ i = dma->cmdk; u = dma->cmdu; ++ while (u != 0) { ++ HIFN_CMDR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_CMDR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ if (i != HIFN_D_CMD_RSIZE) { ++ u--; ++ HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE); ++ } ++ if (++i == (HIFN_D_CMD_RSIZE + 1)) ++ i = 0; ++ } ++ dma->cmdk = i; dma->cmdu = u; ++ ++ HIFN_UNLOCK(sc); ++ ++ if (sc->sc_needwakeup) { /* XXX check high watermark */ ++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "wakeup crypto (%x) u %d/%d/%d/%d\n", ++ sc->sc_needwakeup, ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu); ++#endif ++ sc->sc_needwakeup &= ~wakeup; ++ crypto_unblock(sc->sc_cid, wakeup); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Allocate a new 'session' and return an encoded session id. 'sidp' ++ * contains our registration id, and should contain an encoded session ++ * id on successful allocation. ++ */ ++static int ++hifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ struct cryptoini *c; ++ int mac = 0, cry = 0, sesn; ++ struct hifn_session *ses = NULL; ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_newsession: null softc")); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n", __FILE__, __LINE__, __FUNCTION__); ++ return (EINVAL); ++ } ++ ++ HIFN_LOCK(sc); ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct hifn_session *)kmalloc(sizeof(*ses), ++ SLAB_ATOMIC); ++ if (ses == NULL) { ++ HIFN_UNLOCK(sc); ++ return (ENOMEM); ++ } ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (!sc->sc_sessions[sesn].hs_used) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sesn = sc->sc_nsessions; ++ ses = (struct hifn_session *)kmalloc((sesn + 1) * sizeof(*ses), ++ SLAB_ATOMIC); ++ if (ses == NULL) { ++ HIFN_UNLOCK(sc); ++ return (ENOMEM); ++ } ++ bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); ++ bzero(sc->sc_sessions, sesn * sizeof(*ses)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ HIFN_UNLOCK(sc); ++ ++ bzero(ses, sizeof(*ses)); ++ ses->hs_used = 1; ++ ++ for (c = cri; c != NULL; c = c->cri_next) { ++ switch (c->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_SHA1: ++ case CRYPTO_MD5_HMAC: ++ case CRYPTO_SHA1_HMAC: ++ if (mac) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ mac = 1; ++ ses->hs_mlen = c->cri_mlen; ++ if (ses->hs_mlen == 0) { ++ switch (c->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ ses->hs_mlen = 16; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ ses->hs_mlen = 20; ++ break; ++ } ++ } ++ break; ++ case CRYPTO_DES_CBC: ++ case CRYPTO_3DES_CBC: ++ case CRYPTO_AES_CBC: ++ /* XXX this may read fewer, does it matter? */ ++ read_random(ses->hs_iv, ++ c->cri_alg == CRYPTO_AES_CBC ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ /*FALLTHROUGH*/ ++ case CRYPTO_ARC4: ++ if (cry) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ cry = 1; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ } ++ if (mac == 0 && cry == 0) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ ++ *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn); ++ ++ return (0); ++} ++ ++/* ++ * Deallocate a session. ++ * XXX this routine should run a zero'd mac/encrypt key into context ram. ++ * XXX to blow away any keys already stored there. ++ */ ++static int ++hifn_freesession(device_t dev, u_int64_t tid) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ int session, error; ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_freesession: null softc")); ++ if (sc == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ ++ HIFN_LOCK(sc); ++ session = HIFN_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ bzero(&sc->sc_sessions[session], sizeof(struct hifn_session)); ++ error = 0; ++ } else { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ error = EINVAL; ++ } ++ HIFN_UNLOCK(sc); ++ ++ return (error); ++} ++ ++static int ++hifn_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ struct hifn_command *cmd = NULL; ++ int session, err, ivlen; ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL) { ++ hifnstats.hst_invalid++; ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ session = HIFN_SESSION(crp->crp_sid); ++ ++ if (sc == NULL || session >= sc->sc_nsessions) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ ++ cmd = kmalloc(sizeof(struct hifn_command), SLAB_ATOMIC); ++ if (cmd == NULL) { ++ hifnstats.hst_nomem++; ++ err = ENOMEM; ++ goto errout; ++ } ++ memset(cmd, 0, sizeof(*cmd)); ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ cmd->src_skb = (struct sk_buff *)crp->crp_buf; ++ cmd->dst_skb = (struct sk_buff *)crp->crp_buf; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ cmd->src_io = (struct uio *)crp->crp_buf; ++ cmd->dst_io = (struct uio *)crp->crp_buf; ++ } else { ++ cmd->src_buf = crp->crp_buf; ++ cmd->dst_buf = crp->crp_buf; ++ } ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ if (crd2 == NULL) { ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1 || ++ crd1->crd_alg == CRYPTO_MD5) { ++ maccrd = crd1; ++ enccrd = NULL; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4) { ++ if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0) ++ cmd->base_masks |= HIFN_BASE_CMD_DECODE; ++ maccrd = NULL; ++ enccrd = crd1; ++ } else { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_MD5 || ++ crd1->crd_alg == CRYPTO_SHA1) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_ARC4) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ cmd->base_masks = HIFN_BASE_CMD_DECODE; ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4 || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_MD5 || ++ crd2->crd_alg == CRYPTO_SHA1) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ /* ++ * We cannot order the 7751 as requested ++ */ ++ DPRINTF("%s,%d: %s %d,%d,%d - EINVAL\n",__FILE__,__LINE__,__FUNCTION__, crd1->crd_alg, crd2->crd_alg, crd1->crd_flags & CRD_F_ENCRYPT); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ ++ if (enccrd) { ++ cmd->enccrd = enccrd; ++ cmd->base_masks |= HIFN_BASE_CMD_CRYPT; ++ switch (enccrd->crd_alg) { ++ case CRYPTO_ARC4: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4; ++ break; ++ case CRYPTO_DES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ case CRYPTO_3DES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ case CRYPTO_AES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ if (enccrd->crd_alg != CRYPTO_ARC4) { ++ ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ bcopy(enccrd->crd_iv, cmd->iv, ivlen); ++ else ++ bcopy(sc->sc_sessions[session].hs_iv, ++ cmd->iv, ivlen); ++ ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) ++ == 0) { ++ crypto_copyback(crp->crp_flags, ++ crp->crp_buf, enccrd->crd_inject, ++ ivlen, cmd->iv); ++ } ++ } else { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ bcopy(enccrd->crd_iv, cmd->iv, ivlen); ++ else { ++ crypto_copydata(crp->crp_flags, ++ crp->crp_buf, enccrd->crd_inject, ++ ivlen, cmd->iv); ++ } ++ } ++ } ++ ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) ++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; ++ cmd->ck = enccrd->crd_key; ++ cmd->cklen = enccrd->crd_klen >> 3; ++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; ++ ++ /* ++ * Need to specify the size for the AES key in the masks. ++ */ ++ if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) == ++ HIFN_CRYPT_CMD_ALG_AES) { ++ switch (cmd->cklen) { ++ case 16: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128; ++ break; ++ case 24: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192; ++ break; ++ case 32: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ } ++ ++ if (maccrd) { ++ cmd->maccrd = maccrd; ++ cmd->base_masks |= HIFN_BASE_CMD_MAC; ++ ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | ++ HIFN_MAC_CMD_POS_IPSEC; ++ break; ++ case CRYPTO_MD5_HMAC: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | ++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; ++ break; ++ case CRYPTO_SHA1: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | ++ HIFN_MAC_CMD_POS_IPSEC; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | ++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; ++ break; ++ } ++ ++ if (maccrd->crd_alg == CRYPTO_SHA1_HMAC || ++ maccrd->crd_alg == CRYPTO_MD5_HMAC) { ++ cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY; ++ bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3); ++ bzero(cmd->mac + (maccrd->crd_klen >> 3), ++ HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3)); ++ } ++ } ++ ++ cmd->crp = crp; ++ cmd->session_num = session; ++ cmd->softc = sc; ++ ++ err = hifn_crypto(sc, cmd, crp, hint); ++ if (!err) { ++ return 0; ++ } else if (err == ERESTART) { ++ /* ++ * There weren't enough resources to dispatch the request ++ * to the part. Notify the caller so they'll requeue this ++ * request and resubmit it again soon. ++ */ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, "requeue request\n"); ++#endif ++ kfree(cmd); ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ return (err); ++ } ++ ++errout: ++ if (cmd != NULL) ++ kfree(cmd); ++ if (err == EINVAL) ++ hifnstats.hst_invalid++; ++ else ++ hifnstats.hst_nomem++; ++ crp->crp_etype = err; ++ crypto_done(crp); ++ return (err); ++} ++ ++static void ++hifn_abort(struct hifn_softc *sc) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_command *cmd; ++ struct cryptop *crp; ++ int i, u; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ i = dma->resk; u = dma->resu; ++ while (u != 0) { ++ cmd = dma->hifn_commands[i]; ++ KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); ++ dma->hifn_commands[i] = NULL; ++ crp = cmd->crp; ++ ++ if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { ++ /* Salvage what we can. */ ++ u_int8_t *macbuf; ++ ++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) { ++ macbuf = dma->result_bufs[i]; ++ macbuf += 12; ++ } else ++ macbuf = NULL; ++ hifnstats.hst_opackets++; ++ hifn_callback(sc, cmd, macbuf); ++ } else { ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_POSTREAD); ++ } ++#endif ++ ++ if (cmd->src_skb != cmd->dst_skb) { ++#ifdef NOTYET ++ m_freem(cmd->src_m); ++ crp->crp_buf = (caddr_t)cmd->dst_m; ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ ++ /* non-shared buffers cannot be restarted */ ++ if (cmd->src_map != cmd->dst_map) { ++ /* ++ * XXX should be EAGAIN, delayed until ++ * after the reset. ++ */ ++ crp->crp_etype = ENOMEM; ++ pci_unmap_buf(sc, &cmd->dst); ++ } else ++ crp->crp_etype = ENOMEM; ++ ++ pci_unmap_buf(sc, &cmd->src); ++ ++ kfree(cmd); ++ if (crp->crp_etype != EAGAIN) ++ crypto_done(crp); ++ } ++ ++ if (++i == HIFN_D_RES_RSIZE) ++ i = 0; ++ u--; ++ } ++ dma->resk = i; dma->resu = u; ++ ++ hifn_reset_board(sc, 1); ++ hifn_init_dma(sc); ++ hifn_init_pci_registers(sc); ++} ++ ++static void ++hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct cryptop *crp = cmd->crp; ++ struct cryptodesc *crd; ++ int i, u, ivlen; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_POSTREAD); ++ } ++#endif ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (cmd->src_skb != cmd->dst_skb) { ++#ifdef NOTYET ++ crp->crp_buf = (caddr_t)cmd->dst_m; ++ totlen = cmd->src_mapsize; ++ for (m = cmd->dst_m; m != NULL; m = m->m_next) { ++ if (totlen < m->m_len) { ++ m->m_len = totlen; ++ totlen = 0; ++ } else ++ totlen -= m->m_len; ++ } ++ cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len; ++ m_freem(cmd->src_m); ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ } ++ ++ if (cmd->sloplen != 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ cmd->src_mapsize - cmd->sloplen, cmd->sloplen, ++ (caddr_t)&dma->slop[cmd->slopidx]); ++ } ++ ++ i = dma->dstk; u = dma->dstu; ++ while (u != 0) { ++ if (i == HIFN_D_DST_RSIZE) ++ i = 0; ++#if 0 ++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++#endif ++ if (dma->dstr[i].l & htole32(HIFN_D_VALID)) { ++#if 0 ++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++#endif ++ break; ++ } ++ i++, u--; ++ } ++ dma->dstk = i; dma->dstu = u; ++ ++ hifnstats.hst_obytes += cmd->dst_mapsize; ++ ++ if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) == ++ HIFN_BASE_CMD_CRYPT) { ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ if (crd->crd_alg != CRYPTO_DES_CBC && ++ crd->crd_alg != CRYPTO_3DES_CBC && ++ crd->crd_alg != CRYPTO_AES_CBC) ++ continue; ++ ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_skip + crd->crd_len - ivlen, ivlen, ++ cmd->softc->sc_sessions[cmd->session_num].hs_iv); ++ break; ++ } ++ } ++ ++ if (macbuf != NULL) { ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ int len; ++ ++ if (crd->crd_alg != CRYPTO_MD5 && ++ crd->crd_alg != CRYPTO_SHA1 && ++ crd->crd_alg != CRYPTO_MD5_HMAC && ++ crd->crd_alg != CRYPTO_SHA1_HMAC) { ++ continue; ++ } ++ len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen; ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, len, macbuf); ++ break; ++ } ++ } ++ ++ if (cmd->src_map != cmd->dst_map) ++ pci_unmap_buf(sc, &cmd->dst); ++ pci_unmap_buf(sc, &cmd->src); ++ kfree(cmd); ++ crypto_done(crp); ++} ++ ++/* ++ * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0 ++ * and Group 1 registers; avoid conditions that could create ++ * burst writes by doing a read in between the writes. ++ * ++ * NB: The read we interpose is always to the same register; ++ * we do this because reading from an arbitrary (e.g. last) ++ * register may not always work. ++ */ ++static void ++hifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) ++{ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (sc->sc_bar0_lastreg == reg - 4) ++ readl(sc->sc_bar0 + HIFN_0_PUCNFG); ++ sc->sc_bar0_lastreg = reg; ++ } ++ writel(val, sc->sc_bar0 + reg); ++} ++ ++static void ++hifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) ++{ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (sc->sc_bar1_lastreg == reg - 4) ++ readl(sc->sc_bar1 + HIFN_1_REVID); ++ sc->sc_bar1_lastreg = reg; ++ } ++ writel(val, sc->sc_bar1 + reg); ++} ++ ++ ++static struct pci_device_id hifn_pci_tbl[] = { ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ /* ++ * Other vendors share this PCI ID as well, such as ++ * http://www.powercrypt.com, and obviously they also ++ * use the same key. ++ */ ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { 0, 0, 0, 0, 0, 0, } ++}; ++MODULE_DEVICE_TABLE(pci, hifn_pci_tbl); ++ ++static struct pci_driver hifn_driver = { ++ .name = "hifn", ++ .id_table = hifn_pci_tbl, ++ .probe = hifn_probe, ++ .remove = hifn_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init hifn_init (void) ++{ ++ struct hifn_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF("%s(%p)\n", __FUNCTION__, hifn_init); ++ ++ rc = pci_register_driver(&hifn_driver); ++ pci_register_driver_compat(&hifn_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit hifn_exit (void) ++{ ++ pci_unregister_driver(&hifn_driver); ++} ++ ++module_init(hifn_init); ++module_exit(hifn_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF driver for hifn PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751reg.h linux-2.6.30/crypto/ocf/hifn/hifn7751reg.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751reg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751reg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,540 @@ ++/* $FreeBSD: src/sys/dev/hifn/hifn7751reg.h,v 1.7 2007/03/21 03:42:49 sam Exp $ */ ++/* $OpenBSD: hifn7751reg.h,v 1.35 2002/04/08 17:49:42 jason Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * ++ * Please send any comments, feedback, bug-fixes, or feature requests to ++ * software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++#ifndef __HIFN_H__ ++#define __HIFN_H__ ++ ++/* ++ * Some PCI configuration space offset defines. The names were made ++ * identical to the names used by the Linux kernel. ++ */ ++#define HIFN_BAR0 PCIR_BAR(0) /* PUC register map */ ++#define HIFN_BAR1 PCIR_BAR(1) /* DMA register map */ ++#define HIFN_TRDY_TIMEOUT 0x40 ++#define HIFN_RETRY_TIMEOUT 0x41 ++ ++/* ++ * PCI vendor and device identifiers ++ * (the names are preserved from their OpenBSD source). ++ */ ++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ ++#define PCI_PRODUCT_HIFN_7751 0x0005 /* 7751 */ ++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ ++#define PCI_PRODUCT_HIFN_7811 0x0007 /* 7811 */ ++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ ++#define PCI_PRODUCT_HIFN_7951 0x0012 /* 7951 */ ++#define PCI_PRODUCT_HIFN_7955 0x0020 /* 7954/7955 */ ++#define PCI_PRODUCT_HIFN_7956 0x001d /* 7956 */ ++ ++#define PCI_VENDOR_INVERTEX 0x14e1 /* Invertex */ ++#define PCI_PRODUCT_INVERTEX_AEON 0x0005 /* AEON */ ++ ++#define PCI_VENDOR_NETSEC 0x1660 /* NetSec */ ++#define PCI_PRODUCT_NETSEC_7751 0x7751 /* 7751 */ ++ ++/* ++ * The values below should multiple of 4 -- and be large enough to handle ++ * any command the driver implements. ++ * ++ * MAX_COMMAND = base command + mac command + encrypt command + ++ * mac-key + rc4-key ++ * MAX_RESULT = base result + mac result + mac + encrypt result ++ * ++ * ++ */ ++#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) ++#define HIFN_MAX_RESULT (8 + 4 + 20 + 4) ++ ++/* ++ * hifn_desc_t ++ * ++ * Holds an individual descriptor for any of the rings. ++ */ ++typedef struct hifn_desc { ++ volatile u_int32_t l; /* length and status bits */ ++ volatile u_int32_t p; ++} hifn_desc_t; ++ ++/* ++ * Masks for the "length" field of struct hifn_desc. ++ */ ++#define HIFN_D_LENGTH 0x0000ffff /* length bit mask */ ++#define HIFN_D_MASKDONEIRQ 0x02000000 /* mask the done interrupt */ ++#define HIFN_D_DESTOVER 0x04000000 /* destination overflow */ ++#define HIFN_D_OVER 0x08000000 /* overflow */ ++#define HIFN_D_LAST 0x20000000 /* last descriptor in chain */ ++#define HIFN_D_JUMP 0x40000000 /* jump descriptor */ ++#define HIFN_D_VALID 0x80000000 /* valid bit */ ++ ++ ++/* ++ * Processing Unit Registers (offset from BASEREG0) ++ */ ++#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ ++#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ ++#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ ++#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ ++#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ ++#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ ++#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ ++#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ ++#define HIFN_0_PUCTRL2 0x28 /* Processing Unit Control (2nd map) */ ++#define HIFN_0_MUTE1 0x80 ++#define HIFN_0_MUTE2 0x90 ++#define HIFN_0_SPACESIZE 0x100 /* Register space size */ ++ ++/* Processing Unit Control Register (HIFN_0_PUCTRL) */ ++#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ ++#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ ++#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ ++#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ ++#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ ++ ++/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ ++#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ ++ ++/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ ++#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ ++#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ ++#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ ++#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ ++#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ ++#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ ++#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ ++#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ ++#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ ++#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ ++#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ ++#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ ++#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ ++#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ ++#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ ++#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ ++#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ ++#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ ++#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ ++#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ ++#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ ++#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ ++#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ ++ ++/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ ++#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ ++ ++/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ ++#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ ++#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ ++#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ ++#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ ++#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ ++#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ ++#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ ++#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ ++ ++/* FIFO Status Register (HIFN_0_FIFOSTAT) */ ++#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ ++#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ ++ ++/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ ++#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as this value */ ++ ++/* ++ * DMA Interface Registers (offset from BASEREG1) ++ */ ++#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ ++#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ ++#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ ++#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ ++#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ ++#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ ++#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ ++#define HIFN_1_PLL 0x4c /* 7955/7956: PLL config */ ++#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ ++#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ ++#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ ++#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ ++#define HIFN_1_DMA_CNFG2 0x6c /* 7955/7956: dma config #2 */ ++#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ ++#define HIFN_1_REVID 0x98 /* Revision ID */ ++ ++#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ ++#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ ++#define HIFN_1_PUB_OPLEN 0x304 /* 7951-compat Public Operand Length */ ++#define HIFN_1_PUB_OP 0x308 /* 7951-compat Public Operand */ ++#define HIFN_1_PUB_STATUS 0x30c /* 7951-compat Public Status */ ++#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ ++#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ ++#define HIFN_1_RNG_DATA 0x318 /* RNG data */ ++#define HIFN_1_PUB_MODE 0x320 /* PK mode */ ++#define HIFN_1_PUB_FIFO_OPLEN 0x380 /* first element of oplen fifo */ ++#define HIFN_1_PUB_FIFO_OP 0x384 /* first element of op fifo */ ++#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ ++#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ ++ ++/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ ++#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ ++#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ ++#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ ++#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ ++#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ ++#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ ++#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ ++#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ ++#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ ++#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ ++#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ ++#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ ++#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ ++#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ ++#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ ++#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ ++#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ ++#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ ++#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ ++#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ ++#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ ++#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ ++#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ ++#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ ++#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ ++#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ ++#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ ++#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ ++#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ ++#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ ++#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ ++#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ ++#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ ++#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ ++#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ ++#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ ++#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ ++#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ ++ ++/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ ++#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ ++#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ ++#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ ++#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ ++#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ ++#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ ++#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ ++#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ ++#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ ++#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ ++#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ ++#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ ++#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ ++#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ ++#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ ++#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ ++#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ ++#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ ++#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ ++#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ ++#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ ++#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ ++ ++/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ ++#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ ++#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ ++#define HIFN_DMACNFG_UNLOCK 0x00000800 ++#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ ++#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ ++#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ ++#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ ++#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ ++ ++/* DMA Configuration Register (HIFN_1_DMA_CNFG2) */ ++#define HIFN_DMACNFG2_PKSWAP32 (1 << 19) /* swap the OPLEN/OP reg */ ++#define HIFN_DMACNFG2_PKSWAP8 (1 << 18) /* swap the bits of OPLEN/OP */ ++#define HIFN_DMACNFG2_BAR0_SWAP32 (1<<17) /* swap the bytes of BAR0 */ ++#define HIFN_DMACNFG2_BAR1_SWAP8 (1<<16) /* swap the bits of BAR0 */ ++#define HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT 12 ++#define HIFN_DMACNFG2_INIT_READ_BURST_SHIFT 8 ++#define HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT 4 ++#define HIFN_DMACNFG2_TGT_READ_BURST_SHIFT 0 ++ ++/* 7811 RNG Enable Register (HIFN_1_7811_RNGENA) */ ++#define HIFN_7811_RNGENA_ENA 0x00000001 /* enable RNG */ ++ ++/* 7811 RNG Config Register (HIFN_1_7811_RNGCFG) */ ++#define HIFN_7811_RNGCFG_PRE1 0x00000f00 /* first prescalar */ ++#define HIFN_7811_RNGCFG_OPRE 0x00000080 /* output prescalar */ ++#define HIFN_7811_RNGCFG_DEFL 0x00000f80 /* 2 words/ 1/100 sec */ ++ ++/* 7811 RNG Status Register (HIFN_1_7811_RNGSTS) */ ++#define HIFN_7811_RNGSTS_RDY 0x00004000 /* two numbers in FIFO */ ++#define HIFN_7811_RNGSTS_UFL 0x00001000 /* rng underflow */ ++ ++/* 7811 MIPS Reset Register (HIFN_1_7811_MIPSRST) */ ++#define HIFN_MIPSRST_BAR2SIZE 0xffff0000 /* sdram size */ ++#define HIFN_MIPSRST_GPRAMINIT 0x00008000 /* gpram can be accessed */ ++#define HIFN_MIPSRST_CRAMINIT 0x00004000 /* ctxram can be accessed */ ++#define HIFN_MIPSRST_LED2 0x00000400 /* external LED2 */ ++#define HIFN_MIPSRST_LED1 0x00000200 /* external LED1 */ ++#define HIFN_MIPSRST_LED0 0x00000100 /* external LED0 */ ++#define HIFN_MIPSRST_MIPSDIS 0x00000004 /* disable MIPS */ ++#define HIFN_MIPSRST_MIPSRST 0x00000002 /* warm reset MIPS */ ++#define HIFN_MIPSRST_MIPSCOLD 0x00000001 /* cold reset MIPS */ ++ ++/* Public key reset register (HIFN_1_PUB_RESET) */ ++#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ ++ ++/* Public operation register (HIFN_1_PUB_OP) */ ++#define HIFN_PUBOP_AOFFSET 0x0000003e /* A offset */ ++#define HIFN_PUBOP_BOFFSET 0x00000fc0 /* B offset */ ++#define HIFN_PUBOP_MOFFSET 0x0003f000 /* M offset */ ++#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ ++#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ ++#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ ++#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ ++#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ ++#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ ++#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ ++#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ ++#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ ++#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ ++#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ ++#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ ++#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular Red */ ++#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular Exp */ ++ ++/* Public operand length register (HIFN_1_PUB_OPLEN) */ ++#define HIFN_PUBOPLEN_MODLEN 0x0000007f ++#define HIFN_PUBOPLEN_EXPLEN 0x0003ff80 ++#define HIFN_PUBOPLEN_REDLEN 0x003c0000 ++ ++/* Public status register (HIFN_1_PUB_STATUS) */ ++#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ ++#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ ++#define HIFN_PUBSTS_FIFO_EMPTY 0x00000100 /* fifo empty */ ++#define HIFN_PUBSTS_FIFO_FULL 0x00000200 /* fifo full */ ++#define HIFN_PUBSTS_FIFO_OVFL 0x00000400 /* fifo overflow */ ++#define HIFN_PUBSTS_FIFO_WRITE 0x000f0000 /* fifo write */ ++#define HIFN_PUBSTS_FIFO_READ 0x0f000000 /* fifo read */ ++ ++/* Public interrupt enable register (HIFN_1_PUB_IEN) */ ++#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ ++ ++/* Random number generator config register (HIFN_1_RNG_CONFIG) */ ++#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ ++ ++/* ++ * Register offsets in register set 1 ++ */ ++ ++#define HIFN_UNLOCK_SECRET1 0xf4 ++#define HIFN_UNLOCK_SECRET2 0xfc ++ ++/* ++ * PLL config register ++ * ++ * This register is present only on 7954/7955/7956 parts. It must be ++ * programmed according to the bus interface method used by the h/w. ++ * Note that the parts require a stable clock. Since the PCI clock ++ * may vary the reference clock must usually be used. To avoid ++ * overclocking the core logic, setup must be done carefully, refer ++ * to the driver for details. The exact multiplier required varies ++ * by part and system configuration; refer to the Hifn documentation. ++ */ ++#define HIFN_PLL_REF_SEL 0x00000001 /* REF/HBI clk selection */ ++#define HIFN_PLL_BP 0x00000002 /* bypass (used during setup) */ ++/* bit 2 reserved */ ++#define HIFN_PLL_PK_CLK_SEL 0x00000008 /* public key clk select */ ++#define HIFN_PLL_PE_CLK_SEL 0x00000010 /* packet engine clk select */ ++/* bits 5-9 reserved */ ++#define HIFN_PLL_MBSET 0x00000400 /* must be set to 1 */ ++#define HIFN_PLL_ND 0x00003800 /* Fpll_ref multiplier select */ ++#define HIFN_PLL_ND_SHIFT 11 ++#define HIFN_PLL_ND_2 0x00000000 /* 2x */ ++#define HIFN_PLL_ND_4 0x00000800 /* 4x */ ++#define HIFN_PLL_ND_6 0x00001000 /* 6x */ ++#define HIFN_PLL_ND_8 0x00001800 /* 8x */ ++#define HIFN_PLL_ND_10 0x00002000 /* 10x */ ++#define HIFN_PLL_ND_12 0x00002800 /* 12x */ ++/* bits 14-15 reserved */ ++#define HIFN_PLL_IS 0x00010000 /* charge pump current select */ ++/* bits 17-31 reserved */ ++ ++/* ++ * Board configuration specifies only these bits. ++ */ ++#define HIFN_PLL_CONFIG (HIFN_PLL_IS|HIFN_PLL_ND|HIFN_PLL_REF_SEL) ++ ++/* ++ * Public Key Engine Mode Register ++ */ ++#define HIFN_PKMODE_HOSTINVERT (1 << 0) /* HOST INVERT */ ++#define HIFN_PKMODE_ENHANCED (1 << 1) /* Enable enhanced mode */ ++ ++ ++/********************************************************************* ++ * Structs for board commands ++ * ++ *********************************************************************/ ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_base_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t session_num; ++ volatile u_int16_t total_source_count; ++ volatile u_int16_t total_dest_count; ++} hifn_base_command_t; ++ ++#define HIFN_BASE_CMD_MAC 0x0400 ++#define HIFN_BASE_CMD_CRYPT 0x0800 ++#define HIFN_BASE_CMD_DECODE 0x2000 ++#define HIFN_BASE_CMD_SRCLEN_M 0xc000 ++#define HIFN_BASE_CMD_SRCLEN_S 14 ++#define HIFN_BASE_CMD_DSTLEN_M 0x3000 ++#define HIFN_BASE_CMD_DSTLEN_S 12 ++#define HIFN_BASE_CMD_LENMASK_HI 0x30000 ++#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_crypt_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t header_skip; ++ volatile u_int16_t source_count; ++ volatile u_int16_t reserved; ++} hifn_crypt_command_t; ++ ++#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ ++#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ ++#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ ++#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ ++#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ ++#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ ++#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ ++#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ ++#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ ++#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ ++#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ ++#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ ++#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ ++ ++#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 ++#define HIFN_CRYPT_CMD_SRCLEN_S 14 ++ ++#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ ++#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ ++#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ ++#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_mac_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t header_skip; ++ volatile u_int16_t source_count; ++ volatile u_int16_t reserved; ++} hifn_mac_command_t; ++ ++#define HIFN_MAC_CMD_ALG_MASK 0x0001 ++#define HIFN_MAC_CMD_ALG_SHA1 0x0000 ++#define HIFN_MAC_CMD_ALG_MD5 0x0001 ++#define HIFN_MAC_CMD_MODE_MASK 0x000c ++#define HIFN_MAC_CMD_MODE_HMAC 0x0000 ++#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 ++#define HIFN_MAC_CMD_MODE_HASH 0x0008 ++#define HIFN_MAC_CMD_MODE_FULL 0x0004 ++#define HIFN_MAC_CMD_TRUNC 0x0010 ++#define HIFN_MAC_CMD_RESULT 0x0020 ++#define HIFN_MAC_CMD_APPEND 0x0040 ++#define HIFN_MAC_CMD_SRCLEN_M 0xc000 ++#define HIFN_MAC_CMD_SRCLEN_S 14 ++ ++/* ++ * MAC POS IPsec initiates authentication after encryption on encodes ++ * and before decryption on decodes. ++ */ ++#define HIFN_MAC_CMD_POS_IPSEC 0x0200 ++#define HIFN_MAC_CMD_NEW_KEY 0x0800 ++ ++/* ++ * The poll frequency and poll scalar defines are unshifted values used ++ * to set fields in the DMA Configuration Register. ++ */ ++#ifndef HIFN_POLL_FREQUENCY ++#define HIFN_POLL_FREQUENCY 0x1 ++#endif ++ ++#ifndef HIFN_POLL_SCALAR ++#define HIFN_POLL_SCALAR 0x0 ++#endif ++ ++#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ ++#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ ++#endif /* __HIFN_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751var.h linux-2.6.30/crypto/ocf/hifn/hifn7751var.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751var.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751var.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,369 @@ ++/* $FreeBSD: src/sys/dev/hifn/hifn7751var.h,v 1.9 2007/03/21 03:42:49 sam Exp $ */ ++/* $OpenBSD: hifn7751var.h,v 1.42 2002/04/08 17:49:42 jason Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * ++ * Please send any comments, feedback, bug-fixes, or feature requests to ++ * software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++ ++#ifndef __HIFN7751VAR_H__ ++#define __HIFN7751VAR_H__ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Some configurable values for the driver. By default command+result ++ * descriptor rings are the same size. The src+dst descriptor rings ++ * are sized at 3.5x the number of potential commands. Slower parts ++ * (e.g. 7951) tend to run out of src descriptors; faster parts (7811) ++ * src+cmd/result descriptors. It's not clear that increasing the size ++ * of the descriptor rings helps performance significantly as other ++ * factors tend to come into play (e.g. copying misaligned packets). ++ */ ++#define HIFN_D_CMD_RSIZE 24 /* command descriptors */ ++#define HIFN_D_SRC_RSIZE ((HIFN_D_CMD_RSIZE * 7) / 2) /* source descriptors */ ++#define HIFN_D_RES_RSIZE HIFN_D_CMD_RSIZE /* result descriptors */ ++#define HIFN_D_DST_RSIZE HIFN_D_SRC_RSIZE /* destination descriptors */ ++ ++/* ++ * Length values for cryptography ++ */ ++#define HIFN_DES_KEY_LENGTH 8 ++#define HIFN_3DES_KEY_LENGTH 24 ++#define HIFN_MAX_CRYPT_KEY_LENGTH HIFN_3DES_KEY_LENGTH ++#define HIFN_IV_LENGTH 8 ++#define HIFN_AES_IV_LENGTH 16 ++#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH ++ ++/* ++ * Length values for authentication ++ */ ++#define HIFN_MAC_KEY_LENGTH 64 ++#define HIFN_MD5_LENGTH 16 ++#define HIFN_SHA1_LENGTH 20 ++#define HIFN_MAC_TRUNC_LENGTH 12 ++ ++#define MAX_SCATTER 64 ++ ++/* ++ * Data structure to hold all 4 rings and any other ring related data. ++ */ ++struct hifn_dma { ++ /* ++ * Descriptor rings. We add +1 to the size to accomidate the ++ * jump descriptor. ++ */ ++ struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1]; ++ struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1]; ++ struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; ++ struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; ++ ++ struct hifn_command *hifn_commands[HIFN_D_RES_RSIZE]; ++ ++ u_char command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; ++ u_char result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; ++ u_int32_t slop[HIFN_D_CMD_RSIZE]; ++ ++ u_int64_t test_src, test_dst; ++ ++ /* ++ * Our current positions for insertion and removal from the desriptor ++ * rings. ++ */ ++ int cmdi, srci, dsti, resi; ++ volatile int cmdu, srcu, dstu, resu; ++ int cmdk, srck, dstk, resk; ++}; ++ ++struct hifn_session { ++ int hs_used; ++ int hs_mlen; ++ u_int8_t hs_iv[HIFN_MAX_IV_LENGTH]; ++}; ++ ++#define HIFN_RING_SYNC(sc, r, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++#define HIFN_CMDR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), cmdr, (i), (f)) ++#define HIFN_RESR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), resr, (i), (f)) ++#define HIFN_SRCR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), srcr, (i), (f)) ++#define HIFN_DSTR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), dstr, (i), (f)) ++ ++#define HIFN_CMD_SYNC(sc, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++#define HIFN_RES_SYNC(sc, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++typedef int bus_size_t; ++ ++/* ++ * Holds data specific to a single HIFN board. ++ */ ++struct hifn_softc { ++ softc_device_decl sc_dev; ++ ++ struct pci_dev *sc_pcidev; /* PCI device pointer */ ++ spinlock_t sc_mtx; /* per-instance lock */ ++ ++ int sc_num; /* for multiple devs */ ++ ++ ocf_iomem_t sc_bar0; ++ bus_size_t sc_bar0_lastreg;/* bar0 last reg written */ ++ ocf_iomem_t sc_bar1; ++ bus_size_t sc_bar1_lastreg;/* bar1 last reg written */ ++ ++ int sc_irq; ++ ++ u_int32_t sc_dmaier; ++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */ ++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ ++ ++ struct hifn_dma *sc_dma; ++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ ++ ++ int sc_dmansegs; ++ int32_t sc_cid; ++ int sc_maxses; ++ int sc_nsessions; ++ struct hifn_session *sc_sessions; ++ int sc_ramsize; ++ int sc_flags; ++#define HIFN_HAS_RNG 0x1 /* includes random number generator */ ++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ ++#define HIFN_HAS_AES 0x4 /* includes AES support */ ++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ ++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ ++ ++ struct timer_list sc_tickto; /* for managing DMA */ ++ ++ int sc_rngfirst; ++ int sc_rnghz; /* RNG polling frequency */ ++ ++ int sc_c_busy; /* command ring busy */ ++ int sc_s_busy; /* source data ring busy */ ++ int sc_d_busy; /* destination data ring busy */ ++ int sc_r_busy; /* result ring busy */ ++ int sc_active; /* for initial countdown */ ++ int sc_needwakeup; /* ops q'd wating on resources */ ++ int sc_curbatch; /* # ops submitted w/o int */ ++ int sc_suspended; ++#ifdef HIFN_VULCANDEV ++ struct cdev *sc_pkdev; ++#endif ++}; ++ ++#define HIFN_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) ++#define HIFN_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) ++ ++/* ++ * hifn_command_t ++ * ++ * This is the control structure used to pass commands to hifn_encrypt(). ++ * ++ * flags ++ * ----- ++ * Flags is the bitwise "or" values for command configuration. A single ++ * encrypt direction needs to be set: ++ * ++ * HIFN_ENCODE or HIFN_DECODE ++ * ++ * To use cryptography, a single crypto algorithm must be included: ++ * ++ * HIFN_CRYPT_3DES or HIFN_CRYPT_DES ++ * ++ * To use authentication is used, a single MAC algorithm must be included: ++ * ++ * HIFN_MAC_MD5 or HIFN_MAC_SHA1 ++ * ++ * By default MD5 uses a 16 byte hash and SHA-1 uses a 20 byte hash. ++ * If the value below is set, hash values are truncated or assumed ++ * truncated to 12 bytes: ++ * ++ * HIFN_MAC_TRUNC ++ * ++ * Keys for encryption and authentication can be sent as part of a command, ++ * or the last key value used with a particular session can be retrieved ++ * and used again if either of these flags are not specified. ++ * ++ * HIFN_CRYPT_NEW_KEY, HIFN_MAC_NEW_KEY ++ * ++ * session_num ++ * ----------- ++ * A number between 0 and 2048 (for DRAM models) or a number between ++ * 0 and 768 (for SRAM models). Those who don't want to use session ++ * numbers should leave value at zero and send a new crypt key and/or ++ * new MAC key on every command. If you use session numbers and ++ * don't send a key with a command, the last key sent for that same ++ * session number will be used. ++ * ++ * Warning: Using session numbers and multiboard at the same time ++ * is currently broken. ++ * ++ * mbuf ++ * ---- ++ * Either fill in the mbuf pointer and npa=0 or ++ * fill packp[] and packl[] and set npa to > 0 ++ * ++ * mac_header_skip ++ * --------------- ++ * The number of bytes of the source_buf that are skipped over before ++ * authentication begins. This must be a number between 0 and 2^16-1 ++ * and can be used by IPsec implementers to skip over IP headers. ++ * *** Value ignored if authentication not used *** ++ * ++ * crypt_header_skip ++ * ----------------- ++ * The number of bytes of the source_buf that are skipped over before ++ * the cryptographic operation begins. This must be a number between 0 ++ * and 2^16-1. For IPsec, this number will always be 8 bytes larger ++ * than the auth_header_skip (to skip over the ESP header). ++ * *** Value ignored if cryptography not used *** ++ * ++ */ ++struct hifn_operand { ++ union { ++ struct sk_buff *skb; ++ struct uio *io; ++ unsigned char *buf; ++ } u; ++ void *map; ++ bus_size_t mapsize; ++ int nsegs; ++ struct { ++ dma_addr_t ds_addr; ++ int ds_len; ++ } segs[MAX_SCATTER]; ++}; ++ ++struct hifn_command { ++ u_int16_t session_num; ++ u_int16_t base_masks, cry_masks, mac_masks; ++ u_int8_t iv[HIFN_MAX_IV_LENGTH], *ck, mac[HIFN_MAC_KEY_LENGTH]; ++ int cklen; ++ int sloplen, slopidx; ++ ++ struct hifn_operand src; ++ struct hifn_operand dst; ++ ++ struct hifn_softc *softc; ++ struct cryptop *crp; ++ struct cryptodesc *enccrd, *maccrd; ++}; ++ ++#define src_skb src.u.skb ++#define src_io src.u.io ++#define src_map src.map ++#define src_mapsize src.mapsize ++#define src_segs src.segs ++#define src_nsegs src.nsegs ++#define src_buf src.u.buf ++ ++#define dst_skb dst.u.skb ++#define dst_io dst.u.io ++#define dst_map dst.map ++#define dst_mapsize dst.mapsize ++#define dst_segs dst.segs ++#define dst_nsegs dst.nsegs ++#define dst_buf dst.u.buf ++ ++/* ++ * Return values for hifn_crypto() ++ */ ++#define HIFN_CRYPTO_SUCCESS 0 ++#define HIFN_CRYPTO_BAD_INPUT (-1) ++#define HIFN_CRYPTO_RINGS_FULL (-2) ++ ++/************************************************************************** ++ * ++ * Function: hifn_crypto ++ * ++ * Purpose: Called by external drivers to begin an encryption on the ++ * HIFN board. ++ * ++ * Blocking/Non-blocking Issues ++ * ============================ ++ * The driver cannot block in hifn_crypto (no calls to tsleep) currently. ++ * hifn_crypto() returns HIFN_CRYPTO_RINGS_FULL if there is not enough ++ * room in any of the rings for the request to proceed. ++ * ++ * Return Values ++ * ============= ++ * 0 for success, negative values on error ++ * ++ * Defines for negative error codes are: ++ * ++ * HIFN_CRYPTO_BAD_INPUT : The passed in command had invalid settings. ++ * HIFN_CRYPTO_RINGS_FULL : All DMA rings were full and non-blocking ++ * behaviour was requested. ++ * ++ *************************************************************************/ ++ ++/* ++ * Convert back and forth from 'sid' to 'card' and 'session' ++ */ ++#define HIFN_CARD(sid) (((sid) & 0xf0000000) >> 28) ++#define HIFN_SESSION(sid) ((sid) & 0x000007ff) ++#define HIFN_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff)) ++ ++#endif /* _KERNEL */ ++ ++struct hifn_stats { ++ u_int64_t hst_ibytes; ++ u_int64_t hst_obytes; ++ u_int32_t hst_ipackets; ++ u_int32_t hst_opackets; ++ u_int32_t hst_invalid; ++ u_int32_t hst_nomem; /* malloc or one of hst_nomem_* */ ++ u_int32_t hst_abort; ++ u_int32_t hst_noirq; /* IRQ for no reason */ ++ u_int32_t hst_totbatch; /* ops submitted w/o interrupt */ ++ u_int32_t hst_maxbatch; /* max ops submitted together */ ++ u_int32_t hst_unaligned; /* unaligned src caused copy */ ++ /* ++ * The following divides hst_nomem into more specific buckets. ++ */ ++ u_int32_t hst_nomem_map; /* bus_dmamap_create failed */ ++ u_int32_t hst_nomem_load; /* bus_dmamap_load_* failed */ ++ u_int32_t hst_nomem_mbuf; /* MGET* failed */ ++ u_int32_t hst_nomem_mcl; /* MCLGET* failed */ ++ u_int32_t hst_nomem_cr; /* out of command/result descriptor */ ++ u_int32_t hst_nomem_sd; /* out of src/dst descriptors */ ++}; ++ ++#endif /* __HIFN7751VAR_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPP.c linux-2.6.30/crypto/ocf/hifn/hifnHIPP.c +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPP.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPP.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,420 @@ ++/*- ++ * Driver for Hifn HIPP-I/II chipset ++ * Copyright (c) 2006 Michael Richardson ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn Inc. ++ * ++ */ ++ ++/* ++ * Driver for various Hifn encryption processors. ++ */ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "hifnHIPPreg.h" ++#include "hifnHIPPvar.h" ++ ++#if 1 ++#define DPRINTF(a...) if (hipp_debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "hifn"); \ ++ printk(a); \ ++ } else ++#else ++#define DPRINTF(a...) ++#endif ++ ++typedef int bus_size_t; ++ ++static inline int ++pci_get_revid(struct pci_dev *dev) ++{ ++ u8 rid = 0; ++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid); ++ return rid; ++} ++ ++#define debug hipp_debug ++int hipp_debug = 0; ++module_param(hipp_debug, int, 0644); ++MODULE_PARM_DESC(hipp_debug, "Enable debug"); ++ ++int hipp_maxbatch = 1; ++module_param(hipp_maxbatch, int, 0644); ++MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt"); ++ ++static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent); ++static void hipp_remove(struct pci_dev *dev); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hipp_intr(int irq, void *arg); ++#else ++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs); ++#endif ++ ++static int hipp_num_chips = 0; ++static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS]; ++ ++static int hipp_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int hipp_freesession(device_t, u_int64_t); ++static int hipp_process(device_t, struct cryptop *, int); ++ ++static device_method_t hipp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, hipp_newsession), ++ DEVMETHOD(cryptodev_freesession,hipp_freesession), ++ DEVMETHOD(cryptodev_process, hipp_process), ++}; ++ ++static __inline u_int32_t ++READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar[barno] + reg); ++ //sc->sc_bar0_lastreg = (bus_size_t) -1; ++ return (v); ++} ++static __inline void ++WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val) ++{ ++ writel(val, sc->sc_bar[barno] + reg); ++} ++ ++#define READ_REG_0(sc, reg) READ_REG(sc, 0, reg) ++#define WRITE_REG_0(sc, reg, val) WRITE_REG(sc,0, reg, val) ++#define READ_REG_1(sc, reg) READ_REG(sc, 1, reg) ++#define WRITE_REG_1(sc, reg, val) WRITE_REG(sc,1, reg, val) ++ ++static int ++hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ return EINVAL; ++} ++ ++static int ++hipp_freesession(device_t dev, u_int64_t tid) ++{ ++ return EINVAL; ++} ++ ++static int ++hipp_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ return EINVAL; ++} ++ ++static const char* ++hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen) ++{ ++ char *n = NULL; ++ ++ switch (pci_get_vendor(sc->sc_pcidev)) { ++ case PCI_VENDOR_HIFN: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_HIFN_7855: n = "Hifn 7855"; ++ case PCI_PRODUCT_HIFN_8155: n = "Hifn 8155"; ++ case PCI_PRODUCT_HIFN_6500: n = "Hifn 6500"; ++ } ++ } ++ ++ if(n==NULL) { ++ snprintf(buf, blen, "VID=%02x,PID=%02x", ++ pci_get_vendor(sc->sc_pcidev), ++ pci_get_device(sc->sc_pcidev)); ++ } else { ++ buf[0]='\0'; ++ strncat(buf, n, blen); ++ } ++ return buf; ++} ++ ++struct hipp_fs_entry { ++ struct attribute attr; ++ /* other stuff */ ++}; ++ ++ ++static ssize_t ++cryptoid_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct hipp_softc *sc; ++ ++ sc = pci_get_drvdata(to_pci_dev (dev)); ++ return sprintf (buf, "%d\n", sc->sc_cid); ++} ++ ++struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid); ++ ++/* ++ * Attach an interface that successfully probed. ++ */ ++static int ++hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct hipp_softc *sc = NULL; ++ int i; ++ //char rbase; ++ //u_int16_t ena; ++ int rev; ++ //int rseg; ++ int rc; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (pci_set_mwi(dev)) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("hifn: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods); ++ ++ sc->sc_pcidev = dev; ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_num = hipp_num_chips++; ++ ++ if (sc->sc_num < HIPP_MAX_CHIPS) ++ hipp_chip_idx[sc->sc_num] = sc; ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ spin_lock_init(&sc->sc_mtx); ++ ++ /* ++ * Setup PCI resources. ++ * The READ_REG_0, WRITE_REG_0, READ_REG_1, ++ * and WRITE_REG_1 macros throughout the driver are used ++ * to permit better debugging. ++ */ ++ for(i=0; i<4; i++) { ++ unsigned long mem_start, mem_len; ++ mem_start = pci_resource_start(sc->sc_pcidev, i); ++ mem_len = pci_resource_len(sc->sc_pcidev, i); ++ sc->sc_barphy[i] = (caddr_t)mem_start; ++ sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar[i]) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", i); ++ goto fail; ++ } ++ } ++ ++ //hipp_reset_board(sc, 0); ++ pci_set_master(sc->sc_pcidev); ++ ++ /* ++ * Arrange the interrupt line. ++ */ ++ rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); ++ goto fail; ++ } ++ sc->sc_irq = dev->irq; ++ ++ rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff; ++ ++ { ++ char b[32]; ++ device_printf(sc->sc_dev, "%s, rev %u", ++ hipp_partname(sc, b, sizeof(b)), rev); ++ } ++ ++#if 0 ++ if (sc->sc_flags & HIFN_IS_7956) ++ printf(", pll=0x%x<%s clk, %ux mult>", ++ sc->sc_pllconfig, ++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", ++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); ++#endif ++ printf("\n"); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto fail; ++ } ++ ++#if 0 /* cannot work with a non-GPL module */ ++ /* make a sysfs entry to let the world know what entry we got */ ++ sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr); ++#endif ++ ++#if 0 ++ init_timer(&sc->sc_tickto); ++ sc->sc_tickto.function = hifn_tick; ++ sc->sc_tickto.data = (unsigned long) sc->sc_num; ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++#endif ++ ++#if 0 /* no code here yet ?? */ ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++#endif ++ ++ return (0); ++ ++fail: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ ++#if 0 ++ if (sc->sc_dma) { ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ pci_free_consistent(sc->sc_pcidev, ++ sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++ } ++#endif ++ kfree(sc); ++ return (-ENXIO); ++} ++ ++/* ++ * Detach an interface that successfully probed. ++ */ ++static void ++hipp_remove(struct pci_dev *dev) ++{ ++ struct hipp_softc *sc = pci_get_drvdata(dev); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* disable interrupts */ ++ HIPP_LOCK(sc); ++ ++#if 0 ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); ++ HIFN_UNLOCK(sc); ++ ++ /*XXX other resources */ ++ del_timer_sync(&sc->sc_tickto); ++ ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++#endif ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ free_irq(sc->sc_irq, sc); ++ ++#if 0 ++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++#endif ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hipp_intr(int irq, void *arg) ++#else ++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct hipp_softc *sc = arg; ++ ++ sc = sc; /* shut up compiler */ ++ ++ return IRQ_HANDLED; ++} ++ ++static struct pci_device_id hipp_pci_tbl[] = { ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++}; ++MODULE_DEVICE_TABLE(pci, hipp_pci_tbl); ++ ++static struct pci_driver hipp_driver = { ++ .name = "hipp", ++ .id_table = hipp_pci_tbl, ++ .probe = hipp_probe, ++ .remove = hipp_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init hipp_init (void) ++{ ++ struct hipp_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init); ++ ++ rc = pci_register_driver(&hipp_driver); ++ pci_register_driver_compat(&hipp_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit hipp_exit (void) ++{ ++ pci_unregister_driver(&hipp_driver); ++} ++ ++module_init(hipp_init); ++module_exit(hipp_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("Michael Richardson "); ++MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPreg.h linux-2.6.30/crypto/ocf/hifn/hifnHIPPreg.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPreg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPPreg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,46 @@ ++/*- ++ * Hifn HIPP-I/HIPP-II (7855/8155) driver. ++ * Copyright (c) 2006 Michael Richardson ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn inc. ++ * ++ */ ++ ++#ifndef __HIFNHIPP_H__ ++#define __HIFNHIPP_H__ ++ ++/* ++ * PCI vendor and device identifiers ++ */ ++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ ++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ ++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ ++#define PCI_PRODUCT_HIFN_8155 0x999 /* XXX 8155 */ ++ ++#define HIPP_1_REVID 0x01 /* BOGUS */ ++ ++#endif /* __HIPP_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPvar.h linux-2.6.30/crypto/ocf/hifn/hifnHIPPvar.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPvar.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPPvar.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,93 @@ ++/* ++ * Hifn HIPP-I/HIPP-II (7855/8155) driver. ++ * Copyright (c) 2006 Michael Richardson * ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn inc. ++ * ++ */ ++ ++#ifndef __HIFNHIPPVAR_H__ ++#define __HIFNHIPPVAR_H__ ++ ++#define HIPP_MAX_CHIPS 8 ++ ++/* ++ * Holds data specific to a single Hifn HIPP-I board. ++ */ ++struct hipp_softc { ++ softc_device_decl sc_dev; ++ ++ struct pci_dev *sc_pcidev; /* device backpointer */ ++ ocf_iomem_t sc_bar[5]; ++ caddr_t sc_barphy[5]; /* physical address */ ++ int sc_num; /* for multiple devs */ ++ spinlock_t sc_mtx; /* per-instance lock */ ++ int32_t sc_cid; ++ int sc_irq; ++ ++#if 0 ++ ++ u_int32_t sc_dmaier; ++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */ ++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ ++ ++ struct hifn_dma *sc_dma; ++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ ++ ++ int sc_dmansegs; ++ int sc_maxses; ++ int sc_nsessions; ++ struct hifn_session *sc_sessions; ++ int sc_ramsize; ++ int sc_flags; ++#define HIFN_HAS_RNG 0x1 /* includes random number generator */ ++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ ++#define HIFN_HAS_AES 0x4 /* includes AES support */ ++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ ++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ ++ ++ struct timer_list sc_tickto; /* for managing DMA */ ++ ++ int sc_rngfirst; ++ int sc_rnghz; /* RNG polling frequency */ ++ ++ int sc_c_busy; /* command ring busy */ ++ int sc_s_busy; /* source data ring busy */ ++ int sc_d_busy; /* destination data ring busy */ ++ int sc_r_busy; /* result ring busy */ ++ int sc_active; /* for initial countdown */ ++ int sc_needwakeup; /* ops q'd wating on resources */ ++ int sc_curbatch; /* # ops submitted w/o int */ ++ int sc_suspended; ++ struct miscdevice sc_miscdev; ++#endif ++}; ++ ++#define HIPP_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) ++#define HIPP_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) ++ ++#endif /* __HIFNHIPPVAR_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/Makefile linux-2.6.30/crypto/ocf/hifn/Makefile +--- linux-2.6.30.orig/crypto/ocf/hifn/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,13 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_HIFN) += hifn7751.o ++obj-$(CONFIG_OCF_HIFNHIPP) += hifnHIPP.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ixp4xx/ixp4xx.c linux-2.6.30/crypto/ocf/ixp4xx/ixp4xx.c +--- linux-2.6.30.orig/crypto/ocf/ixp4xx/ixp4xx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ixp4xx/ixp4xx.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1328 @@ ++/* ++ * An OCF module that uses Intels IXP CryptACC API to do the crypto. ++ * This driver requires the IXP400 Access Library that is available ++ * from Intel in order to operate (or compile). ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifndef IX_MBUF_PRIV ++#define IX_MBUF_PRIV(x) ((x)->priv) ++#endif ++ ++struct ixp_data; ++ ++struct ixp_q { ++ struct list_head ixp_q_list; ++ struct ixp_data *ixp_q_data; ++ struct cryptop *ixp_q_crp; ++ struct cryptodesc *ixp_q_ccrd; ++ struct cryptodesc *ixp_q_acrd; ++ IX_MBUF ixp_q_mbuf; ++ UINT8 *ixp_hash_dest; /* Location for hash in client buffer */ ++ UINT8 *ixp_hash_src; /* Location of hash in internal buffer */ ++ unsigned char ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH]; ++ unsigned char *ixp_q_iv; ++}; ++ ++struct ixp_data { ++ int ixp_registered; /* is the context registered */ ++ int ixp_crd_flags; /* detect direction changes */ ++ ++ int ixp_cipher_alg; ++ int ixp_auth_alg; ++ ++ UINT32 ixp_ctx_id; ++ UINT32 ixp_hash_key_id; /* used when hashing */ ++ IxCryptoAccCtx ixp_ctx; ++ IX_MBUF ixp_pri_mbuf; ++ IX_MBUF ixp_sec_mbuf; ++ ++ struct work_struct ixp_pending_work; ++ struct work_struct ixp_registration_work; ++ struct list_head ixp_q; /* unprocessed requests */ ++}; ++ ++#ifdef __ixp46X ++ ++#define MAX_IOP_SIZE 64 /* words */ ++#define MAX_OOP_SIZE 128 ++ ++#define MAX_PARAMS 3 ++ ++struct ixp_pkq { ++ struct list_head pkq_list; ++ struct cryptkop *pkq_krp; ++ ++ IxCryptoAccPkeEauInOperands pkq_op; ++ IxCryptoAccPkeEauOpResult pkq_result; ++ ++ UINT32 pkq_ibuf0[MAX_IOP_SIZE]; ++ UINT32 pkq_ibuf1[MAX_IOP_SIZE]; ++ UINT32 pkq_ibuf2[MAX_IOP_SIZE]; ++ UINT32 pkq_obuf[MAX_OOP_SIZE]; ++}; ++ ++static LIST_HEAD(ixp_pkq); /* current PK wait list */ ++static struct ixp_pkq *ixp_pk_cur; ++static spinlock_t ixp_pkq_lock; ++ ++#endif /* __ixp46X */ ++ ++static int ixp_blocked = 0; ++ ++static int32_t ixp_id = -1; ++static struct ixp_data **ixp_sessions = NULL; ++static u_int32_t ixp_sesnum = 0; ++ ++static int ixp_process(device_t, struct cryptop *, int); ++static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int ixp_freesession(device_t, u_int64_t); ++#ifdef __ixp46X ++static int ixp_kprocess(device_t, struct cryptkop *krp, int hint); ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static kmem_cache_t *qcache; ++#else ++static struct kmem_cache *qcache; ++#endif ++ ++#define debug ixp_debug ++static int ixp_debug = 0; ++module_param(ixp_debug, int, 0644); ++MODULE_PARM_DESC(ixp_debug, "Enable debug"); ++ ++static int ixp_init_crypto = 1; ++module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */ ++MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)"); ++ ++static void ixp_process_pending(void *arg); ++static void ixp_registration(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ixp_process_pending_wq(struct work_struct *work); ++static void ixp_registration_wq(struct work_struct *work); ++#endif ++ ++/* ++ * dummy device structure ++ */ ++ ++static struct { ++ softc_device_decl sc_dev; ++} ixpdev; ++ ++static device_method_t ixp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, ixp_newsession), ++ DEVMETHOD(cryptodev_freesession,ixp_freesession), ++ DEVMETHOD(cryptodev_process, ixp_process), ++#ifdef __ixp46X ++ DEVMETHOD(cryptodev_kprocess, ixp_kprocess), ++#endif ++}; ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) ++{ ++ struct ixp_data *ixp; ++ u_int32_t i; ++#define AUTH_LEN(cri, def) \ ++ (cri->cri_mlen ? cri->cri_mlen : (def)) ++ ++ dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (ixp_sessions) { ++ for (i = 1; i < ixp_sesnum; i++) ++ if (ixp_sessions[i] == NULL) ++ break; ++ } else ++ i = 1; /* NB: to silence compiler warning */ ++ ++ if (ixp_sessions == NULL || i == ixp_sesnum) { ++ struct ixp_data **ixpd; ++ ++ if (ixp_sessions == NULL) { ++ i = 1; /* We leave ixp_sessions[0] empty */ ++ ixp_sesnum = CRYPTO_SW_SESSIONS; ++ } else ++ ixp_sesnum *= 2; ++ ++ ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC); ++ if (ixpd == NULL) { ++ /* Reset session number */ ++ if (ixp_sesnum == CRYPTO_SW_SESSIONS) ++ ixp_sesnum = 0; ++ else ++ ixp_sesnum /= 2; ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *)); ++ ++ /* Copy existing sessions */ ++ if (ixp_sessions) { ++ memcpy(ixpd, ixp_sessions, ++ (ixp_sesnum / 2) * sizeof(struct ixp_data *)); ++ kfree(ixp_sessions); ++ } ++ ++ ixp_sessions = ixpd; ++ } ++ ++ ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data), ++ SLAB_ATOMIC); ++ if (ixp_sessions[i] == NULL) { ++ ixp_freesession(NULL, i); ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ ++ *sid = i; ++ ++ ixp = ixp_sessions[i]; ++ memset(ixp, 0, sizeof(*ixp)); ++ ++ ixp->ixp_cipher_alg = -1; ++ ixp->ixp_auth_alg = -1; ++ ixp->ixp_ctx_id = -1; ++ INIT_LIST_HEAD(&ixp->ixp_q); ++ ++ ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0; ++ ++ while (cri) { ++ switch (cri->cri_alg) { ++ case CRYPTO_DES_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = ++ IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_3DES_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = ++ IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_RIJNDAEL128_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ ixp->ixp_auth_alg = cri->cri_alg; ++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5; ++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN); ++ ixp->ixp_ctx.authCtx.aadLen = 0; ++ /* Only MD5_HMAC needs a key */ ++ if (cri->cri_alg == CRYPTO_MD5_HMAC) { ++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; ++ if (ixp->ixp_ctx.authCtx.authKeyLen > ++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { ++ printk( ++ "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n", ++ cri->cri_klen); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ memcpy(ixp->ixp_ctx.authCtx.key.authKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ } ++ break; ++ ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ ixp->ixp_auth_alg = cri->cri_alg; ++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; ++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN); ++ ixp->ixp_ctx.authCtx.aadLen = 0; ++ /* Only SHA1_HMAC needs a key */ ++ if (cri->cri_alg == CRYPTO_SHA1_HMAC) { ++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; ++ if (ixp->ixp_ctx.authCtx.authKeyLen > ++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { ++ printk( ++ "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n", ++ cri->cri_klen); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ memcpy(ixp->ixp_ctx.authCtx.key.authKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ } ++ break; ++ ++ default: ++ printk("ixp: unknown algo 0x%x\n", cri->cri_alg); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ cri = cri->cri_next; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq); ++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq); ++#else ++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp); ++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp); ++#endif ++ ++ return 0; ++} ++ ++ ++/* ++ * Free a session. ++ */ ++static int ++ixp_freesession(device_t dev, u_int64_t tid) ++{ ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > ixp_sesnum || ixp_sessions == NULL || ++ ixp_sessions[sid] == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return 0; ++ ++ if (ixp_sessions[sid]) { ++ if (ixp_sessions[sid]->ixp_ctx_id != -1) { ++ ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id); ++ ixp_sessions[sid]->ixp_ctx_id = -1; ++ } ++ ++ flush_scheduled_work(); ++ ++ kfree(ixp_sessions[sid]); ++ } ++ ixp_sessions[sid] = NULL; ++ if (ixp_blocked) { ++ ixp_blocked = 0; ++ crypto_unblock(ixp_id, CRYPTO_SYMQ); ++ } ++ return 0; ++} ++ ++ ++/* ++ * callback for when hash processing is complete ++ */ ++ ++static void ++ixp_hash_perform_cb( ++ UINT32 hash_key_id, ++ IX_MBUF *bufp, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_q *q; ++ ++ dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status); ++ ++ if (bufp == NULL) { ++ printk("ixp: NULL buf in %s\n", __FUNCTION__); ++ return; ++ } ++ ++ q = IX_MBUF_PRIV(bufp); ++ if (q == NULL) { ++ printk("ixp: NULL priv in %s\n", __FUNCTION__); ++ return; ++ } ++ ++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ /* On success, need to copy hash back into original client buffer */ ++ memcpy(q->ixp_hash_dest, q->ixp_hash_src, ++ (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ? ++ SHA1_HASH_LEN : MD5_HASH_LEN); ++ } ++ else { ++ printk("ixp: hash perform failed status=%d\n", status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ } ++ ++ /* Free internal buffer used for hashing */ ++ kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf)); ++ ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++/* ++ * setup a request and perform it ++ */ ++static void ++ixp_q_process(struct ixp_q *q) ++{ ++ IxCryptoAccStatus status; ++ struct ixp_data *ixp = q->ixp_q_data; ++ int auth_off = 0; ++ int auth_len = 0; ++ int crypt_off = 0; ++ int crypt_len = 0; ++ int icv_off = 0; ++ char *crypt_func; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, q); ++ ++ if (q->ixp_q_ccrd) { ++ if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ q->ixp_q_iv = q->ixp_q_ccrd->crd_iv; ++ } else { ++ q->ixp_q_iv = q->ixp_q_iv_data; ++ crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf, ++ q->ixp_q_ccrd->crd_inject, ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen, ++ (caddr_t) q->ixp_q_iv); ++ } ++ ++ if (q->ixp_q_acrd) { ++ auth_off = q->ixp_q_acrd->crd_skip; ++ auth_len = q->ixp_q_acrd->crd_len; ++ icv_off = q->ixp_q_acrd->crd_inject; ++ } ++ ++ crypt_off = q->ixp_q_ccrd->crd_skip; ++ crypt_len = q->ixp_q_ccrd->crd_len; ++ } else { /* if (q->ixp_q_acrd) */ ++ auth_off = q->ixp_q_acrd->crd_skip; ++ auth_len = q->ixp_q_acrd->crd_len; ++ icv_off = q->ixp_q_acrd->crd_inject; ++ } ++ ++ if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) { ++ struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ /* ++ * DAVIDM fix this limitation one day by using ++ * a buffer pool and chaining, it is not currently ++ * needed for current user/kernel space acceleration ++ */ ++ printk("ixp: Cannot handle fragmented skb's yet !\n"); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ goto done; ++ } ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = skb->len; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data; ++ } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) { ++ struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf; ++ if (uiop->uio_iovcnt != 1) { ++ /* ++ * DAVIDM fix this limitation one day by using ++ * a buffer pool and chaining, it is not currently ++ * needed for current user/kernel space acceleration ++ */ ++ printk("ixp: Cannot handle more than 1 iovec yet !\n"); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ goto done; ++ } ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base; ++ } else /* contig buffer */ { ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf; ++ } ++ ++ IX_MBUF_PRIV(&q->ixp_q_mbuf) = q; ++ ++ if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) { ++ /* ++ * For SHA1 and MD5 hash, need to create an internal buffer that is big ++ * enough to hold the original data + the appropriate padding for the ++ * hash algorithm. ++ */ ++ UINT8 *tbuf = NULL; ++ ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = ++ ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8; ++ tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC); ++ ++ if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) { ++ printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n", ++ IX_MBUF_MLEN(&q->ixp_q_mbuf)); ++ q->ixp_q_crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len); ++ ++ /* Set location in client buffer to copy hash into */ ++ q->ixp_hash_dest = ++ &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len]; ++ ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf; ++ ++ /* Set location in internal buffer for where hash starts */ ++ q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len]; ++ ++ crypt_func = "ixCryptoAccHashPerform"; ++ status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo, ++ &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len, ++ &ixp->ixp_hash_key_id); ++ } ++ else { ++ crypt_func = "ixCryptoAccAuthCryptPerform"; ++ status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf, ++ NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off, ++ q->ixp_q_iv); ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ return; ++ ++ if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) { ++ q->ixp_q_crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ ++ printk("ixp: %s failed %u\n", crypt_func, status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ ++done: ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++ ++/* ++ * because we cannot process the Q from the Register callback ++ * we do it here on a task Q. ++ */ ++ ++static void ++ixp_process_pending(void *arg) ++{ ++ struct ixp_data *ixp = arg; ++ struct ixp_q *q = NULL; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, arg); ++ ++ if (!ixp) ++ return; ++ ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ ixp_q_process(q); ++ } ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_process_pending_wq(struct work_struct *work) ++{ ++ struct ixp_data *ixp = container_of(work, struct ixp_data, ++ ixp_pending_work); ++ ixp_process_pending(ixp); ++} ++#endif ++ ++/* ++ * callback for when context registration is complete ++ */ ++ ++static void ++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) ++{ ++ int i; ++ struct ixp_data *ixp; ++ struct ixp_q *q; ++ ++ dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status); ++ ++ /* ++ * free any buffer passed in to this routine ++ */ ++ if (bufp) { ++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; ++ kfree(IX_MBUF_MDATA(bufp)); ++ IX_MBUF_MDATA(bufp) = NULL; ++ } ++ ++ for (i = 0; i < ixp_sesnum; i++) { ++ ixp = ixp_sessions[i]; ++ if (ixp && ixp->ixp_ctx_id == ctx_id) ++ break; ++ } ++ if (i >= ixp_sesnum) { ++ printk("ixp: invalid context id %d\n", ctx_id); ++ return; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_WAIT == status) { ++ /* this is normal to free the first of two buffers */ ++ dprintk("ixp: register not finished yet.\n"); ++ return; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { ++ printk("ixp: register failed 0x%x\n", status); ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++ } ++ return; ++ } ++ ++ /* ++ * we are now registered, we cannot start processing the Q here ++ * or we get strange errors with AES (DES/3DES seem to be ok). ++ */ ++ ixp->ixp_registered = 1; ++ schedule_work(&ixp->ixp_pending_work); ++} ++ ++ ++/* ++ * callback for when data processing is complete ++ */ ++ ++static void ++ixp_perform_cb( ++ UINT32 ctx_id, ++ IX_MBUF *sbufp, ++ IX_MBUF *dbufp, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_q *q; ++ ++ dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp, ++ dbufp, status); ++ ++ if (sbufp == NULL) { ++ printk("ixp: NULL sbuf in ixp_perform_cb\n"); ++ return; ++ } ++ ++ q = IX_MBUF_PRIV(sbufp); ++ if (q == NULL) { ++ printk("ixp: NULL priv in ixp_perform_cb\n"); ++ return; ++ } ++ ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ printk("ixp: perform failed status=%d\n", status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ } ++ ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++ ++/* ++ * registration is not callable at IRQ time, so we defer ++ * to a task queue, this routines completes the registration for us ++ * when the task queue runs ++ * ++ * Unfortunately this means we cannot tell OCF that the driver is blocked, ++ * we do that on the next request. ++ */ ++ ++static void ++ixp_registration(void *arg) ++{ ++ struct ixp_data *ixp = arg; ++ struct ixp_q *q = NULL; ++ IX_MBUF *pri = NULL, *sec = NULL; ++ int status = IX_CRYPTO_ACC_STATUS_SUCCESS; ++ ++ if (!ixp) { ++ printk("ixp: ixp_registration with no arg\n"); ++ return; ++ } ++ ++ if (ixp->ixp_ctx_id != -1) { ++ ixCryptoAccCtxUnregister(ixp->ixp_ctx_id); ++ ixp->ixp_ctx_id = -1; ++ } ++ ++ if (list_empty(&ixp->ixp_q)) { ++ printk("ixp: ixp_registration with no Q\n"); ++ return; ++ } ++ ++ /* ++ * setup the primary and secondary buffers ++ */ ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ if (q->ixp_q_acrd) { ++ pri = &ixp->ixp_pri_mbuf; ++ sec = &ixp->ixp_sec_mbuf; ++ IX_MBUF_MLEN(pri) = IX_MBUF_PKT_LEN(pri) = 128; ++ IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ IX_MBUF_MLEN(sec) = IX_MBUF_PKT_LEN(sec) = 128; ++ IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ } ++ ++ /* Only need to register if a crypt op or HMAC op */ ++ if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 || ++ ixp->ixp_auth_alg == CRYPTO_MD5)) { ++ status = ixCryptoAccCtxRegister( ++ &ixp->ixp_ctx, ++ pri, sec, ++ ixp_register_cb, ++ ixp_perform_cb, ++ &ixp->ixp_ctx_id); ++ } ++ else { ++ /* Otherwise we start processing pending q */ ++ schedule_work(&ixp->ixp_pending_work); ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ return; ++ ++ if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) { ++ printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n"); ++ ixp_blocked = 1; ++ /* perhaps we should return EGAIN on queued ops ? */ ++ return; ++ } ++ ++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); ++ ixp->ixp_ctx_id = -1; ++ ++ /* ++ * everything waiting is toasted ++ */ ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++ } ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_registration_wq(struct work_struct *work) ++{ ++ struct ixp_data *ixp = container_of(work, struct ixp_data, ++ ixp_registration_work); ++ ixp_registration(ixp); ++} ++#endif ++ ++/* ++ * Process a request. ++ */ ++static int ++ixp_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct ixp_data *ixp; ++ unsigned int lid; ++ struct ixp_q *q = NULL; ++ int status; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (ixp_blocked) ++ return ERESTART; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ /* ++ * find the session we are using ++ */ ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL || ++ ixp_sessions[lid] == NULL) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ixp = ixp_sessions[lid]; ++ ++ /* ++ * setup a new request ready for queuing ++ */ ++ q = kmem_cache_alloc(qcache, SLAB_ATOMIC); ++ if (q == NULL) { ++ dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__); ++ crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ /* ++ * save some cycles by only zeroing the important bits ++ */ ++ memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf)); ++ q->ixp_q_ccrd = NULL; ++ q->ixp_q_acrd = NULL; ++ q->ixp_q_crp = crp; ++ q->ixp_q_data = ixp; ++ ++ /* ++ * point the cipher and auth descriptors appropriately ++ * check that we have something to do ++ */ ++ if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg) ++ q->ixp_q_ccrd = crp->crp_desc; ++ else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg) ++ q->ixp_q_acrd = crp->crp_desc; ++ else { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ if (crp->crp_desc->crd_next) { ++ if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg) ++ q->ixp_q_ccrd = crp->crp_desc->crd_next; ++ else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg) ++ q->ixp_q_acrd = crp->crp_desc->crd_next; ++ else { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ } ++ ++ /* ++ * If there is a direction change for this context then we mark it as ++ * unregistered and re-register is for the new direction. This is not ++ * a very expensive operation and currently only tends to happen when ++ * user-space application are doing benchmarks ++ * ++ * DM - we should be checking for pending requests before unregistering. ++ */ ++ if (q->ixp_q_ccrd && ixp->ixp_registered && ++ ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) { ++ dprintk("%s - detected direction change on session\n", __FUNCTION__); ++ ixp->ixp_registered = 0; ++ } ++ ++ /* ++ * if we are registered, call straight into the perform code ++ */ ++ if (ixp->ixp_registered) { ++ ixp_q_process(q); ++ return 0; ++ } ++ ++ /* ++ * the only part of the context not set in newsession is the direction ++ * dependent parts ++ */ ++ if (q->ixp_q_ccrd) { ++ ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT); ++ if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) { ++ ixp->ixp_ctx.operation = q->ixp_q_acrd ? ++ IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT; ++ } else { ++ ixp->ixp_ctx.operation = q->ixp_q_acrd ? ++ IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT; ++ } ++ } else { ++ /* q->ixp_q_acrd must be set if we are here */ ++ ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC; ++ } ++ ++ status = list_empty(&ixp->ixp_q); ++ list_add_tail(&q->ixp_q_list, &ixp->ixp_q); ++ if (status) ++ schedule_work(&ixp->ixp_registration_work); ++ return 0; ++ ++done: ++ if (q) ++ kmem_cache_free(qcache, q); ++ crypto_done(crp); ++ return 0; ++} ++ ++ ++#ifdef __ixp46X ++/* ++ * key processing support for the ixp465 ++ */ ++ ++ ++/* ++ * copy a BN (LE) into a buffer (BE) an fill out the op appropriately ++ * assume zeroed and only copy bits that are significant ++ */ ++ ++static int ++ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf) ++{ ++ unsigned char *src = (unsigned char *) p->crp_p; ++ unsigned char *dst; ++ int len, bits = p->crp_nbits; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) { ++ dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__, ++ bits, MAX_IOP_SIZE * sizeof(UINT32) * 8); ++ return -1; ++ } ++ ++ len = (bits + 31) / 32; /* the number UINT32's needed */ ++ ++ dst = (unsigned char *) &buf[len]; ++ dst--; ++ ++ while (bits > 0) { ++ *dst-- = *src++; ++ bits -= 8; ++ } ++ ++#if 0 /* no need to zero remaining bits as it is done during request alloc */ ++ while (dst > (unsigned char *) buf) ++ *dst-- = '\0'; ++#endif ++ ++ op->pData = buf; ++ op->dataLen = len; ++ return 0; ++} ++ ++/* ++ * copy out the result, be as forgiving as we can about small output buffers ++ */ ++ ++static int ++ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf) ++{ ++ unsigned char *dst = (unsigned char *) p->crp_p; ++ unsigned char *src = (unsigned char *) buf; ++ int len, z, bits = p->crp_nbits; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ len = op->dataLen * sizeof(UINT32); ++ ++ /* skip leading zeroes to be small buffer friendly */ ++ z = 0; ++ while (z < len && src[z] == '\0') ++ z++; ++ ++ src += len; ++ src--; ++ len -= z; ++ ++ while (len > 0 && bits > 0) { ++ *dst++ = *src--; ++ len--; ++ bits -= 8; ++ } ++ ++ while (bits > 0) { ++ *dst++ = '\0'; ++ bits -= 8; ++ } ++ ++ if (len > 0) { ++ dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n", ++ __FUNCTION__, len, z, p->crp_nbits / 8); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * the parameter offsets for exp_mod ++ */ ++ ++#define IXP_PARAM_BASE 0 ++#define IXP_PARAM_EXP 1 ++#define IXP_PARAM_MOD 2 ++#define IXP_PARAM_RES 3 ++ ++/* ++ * key processing complete callback, is also used to start processing ++ * by passing a NULL for pResult ++ */ ++ ++static void ++ixp_kperform_cb( ++ IxCryptoAccPkeEauOperation operation, ++ IxCryptoAccPkeEauOpResult *pResult, ++ BOOL carryOrBorrow, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_pkq *q, *tmp; ++ unsigned long flags; ++ ++ dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult, ++ carryOrBorrow, status); ++ ++ /* handle a completed request */ ++ if (pResult) { ++ if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) { ++ q = ixp_pk_cur; ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status); ++ q->pkq_krp->krp_status = ERANGE; /* could do better */ ++ } else { ++ /* copy out the result */ ++ if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES], ++ &q->pkq_result, q->pkq_obuf)) ++ q->pkq_krp->krp_status = ERANGE; ++ } ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ ixp_pk_cur = NULL; ++ } else ++ printk("%s - callback with invalid result pointer\n", __FUNCTION__); ++ } ++ ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ if (ixp_pk_cur || list_empty(&ixp_pkq)) { ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ return; ++ } ++ ++ list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) { ++ ++ list_del(&q->pkq_list); ++ ixp_pk_cur = q; ++ ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ ++ status = ixCryptoAccPkeEauPerform( ++ IX_CRYPTO_ACC_OP_EAU_MOD_EXP, ++ &q->pkq_op, ++ ixp_kperform_cb, ++ &q->pkq_result); ++ ++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__); ++ return; /* callback will return here for callback */ ++ } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) { ++ printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__); ++ } else { ++ printk("%s() - ixCryptoAccPkeEauPerform failed %d\n", ++ __FUNCTION__, status); ++ } ++ q->pkq_krp->krp_status = ERANGE; /* could do better */ ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ } ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++} ++ ++ ++static int ++ixp_kprocess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ struct ixp_pkq *q; ++ int rc = 0; ++ unsigned long flags; ++ ++ dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__, ++ krp->krp_param[IXP_PARAM_BASE].crp_nbits, ++ krp->krp_param[IXP_PARAM_EXP].crp_nbits, ++ krp->krp_param[IXP_PARAM_MOD].crp_nbits, ++ krp->krp_param[IXP_PARAM_RES].crp_nbits); ++ ++ ++ if (krp->krp_op != CRK_MOD_EXP) { ++ krp->krp_status = EOPNOTSUPP; ++ goto err; ++ } ++ ++ q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); ++ if (q == NULL) { ++ krp->krp_status = ENOMEM; ++ goto err; ++ } ++ ++ /* ++ * The PKE engine does not appear to zero the output buffer ++ * appropriately, so we need to do it all here. ++ */ ++ memset(q, 0, sizeof(*q)); ++ ++ q->pkq_krp = krp; ++ INIT_LIST_HEAD(&q->pkq_list); ++ ++ if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M, ++ q->pkq_ibuf0)) ++ rc = 1; ++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP], ++ &q->pkq_op.modExpOpr.e, q->pkq_ibuf1)) ++ rc = 2; ++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD], ++ &q->pkq_op.modExpOpr.N, q->pkq_ibuf2)) ++ rc = 3; ++ ++ if (rc) { ++ kfree(q); ++ krp->krp_status = ERANGE; ++ goto err; ++ } ++ ++ q->pkq_result.pData = q->pkq_obuf; ++ q->pkq_result.dataLen = ++ (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32; ++ ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ list_add_tail(&q->pkq_list, &ixp_pkq); ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ ++ if (!ixp_pk_cur) ++ ixp_kperform_cb(0, NULL, 0, 0); ++ return (0); ++ ++err: ++ crypto_kdone(krp); ++ return (0); ++} ++ ++ ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++/* ++ * We run the random number generator output through SHA so that it ++ * is FIPS compliant. ++ */ ++ ++static volatile int sha_done = 0; ++static unsigned char sha_digest[20]; ++ ++static void ++ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status) ++{ ++ dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status); ++ if (sha_digest != digest) ++ printk("digest error\n"); ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ sha_done = 1; ++ else ++ sha_done = -status; ++} ++ ++static int ++ixp_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ IxCryptoAccStatus status; ++ int i, n, rc; ++ ++ dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords); ++ memset(buf, 0, maxwords * sizeof(*buf)); ++ status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf); ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n", ++ __FUNCTION__, status); ++ return 0; ++ } ++ ++ /* ++ * run the random data through SHA to make it look more random ++ */ ++ ++ n = sizeof(sha_digest); /* process digest bytes at a time */ ++ ++ rc = 0; ++ for (i = 0; i < maxwords; i += n / sizeof(*buf)) { ++ if ((maxwords - i) * sizeof(*buf) < n) ++ n = (maxwords - i) * sizeof(*buf); ++ sha_done = 0; ++ status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1, ++ (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest); ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("ixCryptoAccPkeHashPerform failed %d\n", status); ++ return -EIO; ++ } ++ while (!sha_done) ++ schedule(); ++ if (sha_done < 0) { ++ dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done); ++ return 0; ++ } ++ memcpy(&buf[i], sha_digest, n); ++ rc += n / sizeof(*buf);; ++ } ++ ++ return rc; ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++#endif /* __ixp46X */ ++ ++ ++ ++/* ++ * our driver startup and shutdown routines ++ */ ++ ++static int ++ixp_init(void) ++{ ++ dprintk("%s(%p)\n", __FUNCTION__, ixp_init); ++ ++ if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS) ++ printk("ixCryptoAccInit failed, assuming already initialised!\n"); ++ ++ qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0, ++ SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ if (!qcache) { ++ printk("failed to create Qcache\n"); ++ return -ENOENT; ++ } ++ ++ memset(&ixpdev, 0, sizeof(ixpdev)); ++ softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods); ++ ++ ixp_id = crypto_get_driverid(softc_get_device(&ixpdev), ++ CRYPTOCAP_F_HARDWARE); ++ if (ixp_id < 0) ++ panic("IXP/OCF crypto device cannot initialize!"); ++ ++#define REGISTER(alg) \ ++ crypto_register(ixp_id,alg,0,0) ++ ++ REGISTER(CRYPTO_DES_CBC); ++ REGISTER(CRYPTO_3DES_CBC); ++ REGISTER(CRYPTO_RIJNDAEL128_CBC); ++#ifdef CONFIG_OCF_IXP4XX_SHA1_MD5 ++ REGISTER(CRYPTO_MD5); ++ REGISTER(CRYPTO_SHA1); ++#endif ++ REGISTER(CRYPTO_MD5_HMAC); ++ REGISTER(CRYPTO_SHA1_HMAC); ++#undef REGISTER ++ ++#ifdef __ixp46X ++ spin_lock_init(&ixp_pkq_lock); ++ /* ++ * we do not enable the go fast options here as they can potentially ++ * allow timing based attacks ++ * ++ * http://www.openssl.org/news/secadv_20030219.txt ++ */ ++ ixCryptoAccPkeEauExpConfig(0, 0); ++ crypto_kregister(ixp_id, CRK_MOD_EXP, 0); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ crypto_rregister(ixp_id, ixp_read_random, NULL); ++#endif ++#endif ++ ++ return 0; ++} ++ ++static void ++ixp_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(ixp_id); ++ ixp_id = -1; ++ kmem_cache_destroy(qcache); ++ qcache = NULL; ++} ++ ++module_init(ixp_init); ++module_exit(ixp_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ixp4xx/Makefile linux-2.6.30/crypto/ocf/ixp4xx/Makefile +--- linux-2.6.30.orig/crypto/ocf/ixp4xx/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ixp4xx/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,104 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++# ++# You will need to point this at your Intel ixp425 includes, this portion ++# of the Makefile only really works under SGLinux with the appropriate libs ++# installed. They can be downloaded from http://www.snapgear.org/ ++# ++ifeq ($(CONFIG_CPU_IXP46X),y) ++IXPLATFORM = ixp46X ++else ++ifeq ($(CONFIG_CPU_IXP43X),y) ++IXPLATFORM = ixp43X ++else ++IXPLATFORM = ixp42X ++endif ++endif ++ ++ifdef CONFIG_IXP400_LIB_2_4 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp_osal ++endif ++ifdef CONFIG_IXP400_LIB_2_1 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp_osal ++endif ++ifdef CONFIG_IXP400_LIB_2_0 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp_osal ++endif ++ifdef IX_XSCALE_SW ++ifdef CONFIG_IXP400_LIB_2_4 ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(IX_XSCALE_SW)/src/include \ ++ -I$(OSAL_DIR)/common/include/ \ ++ -I$(OSAL_DIR)/common/include/modules/ \ ++ -I$(OSAL_DIR)/common/include/modules/ddk/ \ ++ -I$(OSAL_DIR)/common/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/common/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ddk/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/include/ \ ++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/os/linux/include/ \ ++ -DENABLE_IOMEM -DENABLE_BUFFERMGT -DENABLE_DDK \ ++ -DUSE_IXP4XX_CRYPTO ++else ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(IX_XSCALE_SW)/src/include \ ++ -I$(OSAL_DIR)/ \ ++ -I$(OSAL_DIR)/os/linux/include/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp425 \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp465 \ ++ -I$(OSAL_DIR)/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/include/ \ ++ -I$(OSAL_DIR)/include/modules/ \ ++ -I$(OSAL_DIR)/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/include/platforms/ \ ++ -I$(OSAL_DIR)/include/platforms/ixp400/ \ ++ -DUSE_IXP4XX_CRYPTO ++endif ++endif ++ifdef CONFIG_IXP400_LIB_1_4 ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/include \ ++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/linux \ ++ -DUSE_IXP4XX_CRYPTO ++endif ++ifndef IXPDIR ++IXPDIR = ixp-version-is-not-supported ++endif ++ ++ifeq ($(CONFIG_CPU_IXP46X),y) ++IXP_CFLAGS += -D__ixp46X ++else ++ifeq ($(CONFIG_CPU_IXP43X),y) ++IXP_CFLAGS += -D__ixp43X ++else ++IXP_CFLAGS += -D__ixp42X ++endif ++endif ++ ++obj-$(CONFIG_OCF_IXP4XX) += ixp4xx.o ++ ++obj ?= . ++EXTRA_CFLAGS += $(IXP_CFLAGS) -I$(obj)/.. -I$(obj)/. ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/Kconfig linux-2.6.30/crypto/ocf/Kconfig +--- linux-2.6.30.orig/crypto/ocf/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Kconfig 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,101 @@ ++menu "OCF Configuration" ++ ++config OCF_OCF ++ tristate "OCF (Open Cryptograhic Framework)" ++ help ++ A linux port of the OpenBSD/FreeBSD crypto framework. ++ ++config OCF_RANDOMHARVEST ++ bool "crypto random --- harvest entropy for /dev/random" ++ depends on OCF_OCF ++ help ++ Includes code to harvest random numbers from devices that support it. ++ ++config OCF_FIPS ++ bool "enable fips RNG checks" ++ depends on OCF_OCF && OCF_RANDOMHARVEST ++ help ++ Run all RNG provided data through a fips check before ++ adding it /dev/random's entropy pool. ++ ++config OCF_CRYPTODEV ++ tristate "cryptodev (user space support)" ++ depends on OCF_OCF ++ help ++ The user space API to access crypto hardware. ++ ++config OCF_CRYPTOSOFT ++ tristate "cryptosoft (software crypto engine)" ++ depends on OCF_OCF ++ help ++ A software driver for the OCF framework that uses ++ the kernel CryptoAPI. ++ ++config OCF_SAFE ++ tristate "safenet (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ A driver for a number of the safenet Excel crypto accelerators. ++ Currently tested and working on the 1141 and 1741. ++ ++config OCF_IXP4XX ++ tristate "IXP4xx (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ XScale IXP4xx crypto accelerator driver. Requires the ++ Intel Access library. ++ ++config OCF_IXP4XX_SHA1_MD5 ++ bool "IXP4xx SHA1 and MD5 Hashing" ++ depends on OCF_IXP4XX ++ help ++ Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing. ++ Note: this is MUCH slower than using cryptosoft (software crypto engine). ++ ++config OCF_HIFN ++ tristate "hifn (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for various HIFN based crypto accelerators. ++ (7951, 7955, 7956, 7751, 7811) ++ ++config OCF_HIFNHIPP ++ tristate "Hifn HIPP (HW packet crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for various HIFN (HIPP) based crypto accelerators ++ (7855) ++ ++config OCF_TALITOS ++ tristate "talitos (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for Freescale's security engine (SEC/talitos). ++ ++config OCF_PASEMI ++ tristate "pasemi (HW crypto engine)" ++ depends on OCF_OCF && PPC_PASEMI ++ help ++ OCF driver for the PA Semi PWRficient DMA Engine ++ ++config OCF_EP80579 ++ tristate "ep80579 (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for the Intel EP80579 Integrated Processor Product Line. ++ ++config OCF_OCFNULL ++ tristate "ocfnull (fake crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for measuring ipsec overheads (does no crypto) ++ ++config OCF_BENCH ++ tristate "ocf-bench (HW crypto in-kernel benchmark)" ++ depends on OCF_OCF ++ help ++ A very simple encryption test for the in-kernel interface ++ of OCF. Also includes code to benchmark the IXP Access library ++ for comparison. ++ ++endmenu +diff -Nur linux-2.6.30.orig/crypto/ocf/Makefile linux-2.6.30/crypto/ocf/Makefile +--- linux-2.6.30.orig/crypto/ocf/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,121 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++OCF_OBJS = crypto.o criov.o ++ ++ifdef CONFIG_OCF_RANDOMHARVEST ++ OCF_OBJS += random.o ++endif ++ ++ifdef CONFIG_OCF_FIPS ++ OCF_OBJS += rndtest.o ++endif ++ ++# Add in autoconf.h to get #defines for CONFIG_xxx ++AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h ++ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H))) ++ EXTRA_CFLAGS += -include $(AUTOCONF_H) ++ export EXTRA_CFLAGS ++endif ++ ++ifndef obj ++ obj ?= . ++ _obj = subdir ++ mod-subdirs := safe hifn ixp4xx talitos ocfnull ++ export-objs += crypto.o criov.o random.o ++ list-multi += ocf.o ++ _slash := ++else ++ _obj = obj ++ _slash := / ++endif ++ ++EXTRA_CFLAGS += -I$(obj)/. ++ ++obj-$(CONFIG_OCF_OCF) += ocf.o ++obj-$(CONFIG_OCF_CRYPTODEV) += cryptodev.o ++obj-$(CONFIG_OCF_CRYPTOSOFT) += cryptosoft.o ++obj-$(CONFIG_OCF_BENCH) += ocf-bench.o ++ ++$(_obj)-$(CONFIG_OCF_SAFE) += safe$(_slash) ++$(_obj)-$(CONFIG_OCF_HIFN) += hifn$(_slash) ++$(_obj)-$(CONFIG_OCF_IXP4XX) += ixp4xx$(_slash) ++$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash) ++$(_obj)-$(CONFIG_OCF_PASEMI) += pasemi$(_slash) ++$(_obj)-$(CONFIG_OCF_EP80579) += ep80579$(_slash) ++$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash) ++ ++ocf-objs := $(OCF_OBJS) ++ ++$(list-multi) dummy1: $(ocf-objs) ++ $(LD) -r -o $@ $(ocf-objs) ++ ++.PHONY: ++clean: ++ rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c ++ rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ ++# ++# release gen targets ++# ++ ++.PHONY: patch ++patch: ++ REL=`date +%Y%m%d`; \ ++ patch=ocf-linux-$$REL.patch; \ ++ patch24=ocf-linux-24-$$REL.patch; \ ++ patch26=ocf-linux-26-$$REL.patch; \ ++ ( \ ++ find . -name Makefile; \ ++ find . -name Config.in; \ ++ find . -name Kconfig; \ ++ find . -name README; \ ++ find . -name '*.[ch]' | grep -v '.mod.c'; \ ++ ) | while read t; do \ ++ diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \ ++ done > $$patch; \ ++ cat patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \ ++ cat patches/linux-2.6.26-ocf.patch $$patch > $$patch26 ++ ++.PHONY: tarball ++tarball: ++ REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \ ++ CURDIR=`pwd`; \ ++ rm -rf /tmp/ocf-linux-$$REL*; \ ++ mkdir -p $$RELDIR/tools; \ ++ cp README* $$RELDIR; \ ++ cp patches/openss*.patch $$RELDIR; \ ++ cp patches/crypto-tools.patch $$RELDIR; \ ++ cp tools/[!C]* $$RELDIR/tools; \ ++ cd ..; \ ++ tar cvf $$RELDIR/ocf-linux.tar \ ++ --exclude=CVS \ ++ --exclude=.* \ ++ --exclude=*.o \ ++ --exclude=*.ko \ ++ --exclude=*.mod.* \ ++ --exclude=README* \ ++ --exclude=ocf-*.patch \ ++ --exclude=ocf/patches/openss*.patch \ ++ --exclude=ocf/patches/crypto-tools.patch \ ++ --exclude=ocf/tools \ ++ ocf; \ ++ gzip -9 $$RELDIR/ocf-linux.tar; \ ++ cd /tmp; \ ++ tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \ ++ gzip -9 ocf-linux-$$REL.tar; \ ++ cd $$CURDIR/../../user; \ ++ rm -rf /tmp/crypto-tools-$$REL*; \ ++ tar cvf /tmp/crypto-tools-$$REL.tar \ ++ --exclude=CVS \ ++ --exclude=.* \ ++ --exclude=*.o \ ++ --exclude=cryptotest \ ++ --exclude=cryptokeytest \ ++ crypto-tools; \ ++ gzip -9 /tmp/crypto-tools-$$REL.tar ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocf-bench.c linux-2.6.30/crypto/ocf/ocf-bench.c +--- linux-2.6.30.orig/crypto/ocf/ocf-bench.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocf-bench.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,436 @@ ++/* ++ * A loadable module that benchmarks the OCF crypto speed from kernel space. ++ * ++ * Copyright (C) 2004-2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK ++#define BENCH_IXP_ACCESS_LIB 1 ++#endif ++#ifdef BENCH_IXP_ACCESS_LIB ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* ++ * support for access lib version 1.4 ++ */ ++#ifndef IX_MBUF_PRIV ++#define IX_MBUF_PRIV(x) ((x)->priv) ++#endif ++ ++/* ++ * the number of simultaneously active requests ++ */ ++static int request_q_len = 20; ++module_param(request_q_len, int, 0); ++MODULE_PARM_DESC(request_q_len, "Number of outstanding requests"); ++/* ++ * how many requests we want to have processed ++ */ ++static int request_num = 1024; ++module_param(request_num, int, 0); ++MODULE_PARM_DESC(request_num, "run for at least this many requests"); ++/* ++ * the size of each request ++ */ ++static int request_size = 1500; ++module_param(request_size, int, 0); ++MODULE_PARM_DESC(request_size, "size of each request"); ++ ++/* ++ * a structure for each request ++ */ ++typedef struct { ++ struct work_struct work; ++#ifdef BENCH_IXP_ACCESS_LIB ++ IX_MBUF mbuf; ++#endif ++ unsigned char *buffer; ++} request_t; ++ ++static request_t *requests; ++ ++static int outstanding; ++static int total; ++ ++/*************************************************************************/ ++/* ++ * OCF benchmark routines ++ */ ++ ++static uint64_t ocf_cryptoid; ++static int ocf_init(void); ++static int ocf_cb(struct cryptop *crp); ++static void ocf_request(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ocf_request_wq(struct work_struct *work); ++#endif ++ ++static int ++ocf_init(void) ++{ ++ int error; ++ struct cryptoini crie, cria; ++ struct cryptodesc crda, crde; ++ ++ memset(&crie, 0, sizeof(crie)); ++ memset(&cria, 0, sizeof(cria)); ++ memset(&crde, 0, sizeof(crde)); ++ memset(&crda, 0, sizeof(crda)); ++ ++ cria.cri_alg = CRYPTO_SHA1_HMAC; ++ cria.cri_klen = 20 * 8; ++ cria.cri_key = "0123456789abcdefghij"; ++ ++ crie.cri_alg = CRYPTO_3DES_CBC; ++ crie.cri_klen = 24 * 8; ++ crie.cri_key = "0123456789abcdefghijklmn"; ++ ++ crie.cri_next = &cria; ++ ++ error = crypto_newsession(&ocf_cryptoid, &crie, 0); ++ if (error) { ++ printk("crypto_newsession failed %d\n", error); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++ocf_cb(struct cryptop *crp) ++{ ++ request_t *r = (request_t *) crp->crp_opaque; ++ ++ if (crp->crp_etype) ++ printk("Error in OCF processing: %d\n", crp->crp_etype); ++ total++; ++ crypto_freereq(crp); ++ crp = NULL; ++ ++ if (total > request_num) { ++ outstanding--; ++ return 0; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&r->work, ocf_request_wq); ++#else ++ INIT_WORK(&r->work, ocf_request, r); ++#endif ++ schedule_work(&r->work); ++ return 0; ++} ++ ++ ++static void ++ocf_request(void *arg) ++{ ++ request_t *r = arg; ++ struct cryptop *crp = crypto_getreq(2); ++ struct cryptodesc *crde, *crda; ++ ++ if (!crp) { ++ outstanding--; ++ return; ++ } ++ ++ crde = crp->crp_desc; ++ crda = crde->crd_next; ++ ++ crda->crd_skip = 0; ++ crda->crd_flags = 0; ++ crda->crd_len = request_size; ++ crda->crd_inject = request_size; ++ crda->crd_alg = CRYPTO_SHA1_HMAC; ++ crda->crd_key = "0123456789abcdefghij"; ++ crda->crd_klen = 20 * 8; ++ ++ crde->crd_skip = 0; ++ crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT; ++ crde->crd_len = request_size; ++ crde->crd_inject = request_size; ++ crde->crd_alg = CRYPTO_3DES_CBC; ++ crde->crd_key = "0123456789abcdefghijklmn"; ++ crde->crd_klen = 24 * 8; ++ ++ crp->crp_ilen = request_size + 64; ++ crp->crp_flags = CRYPTO_F_CBIMM; ++ crp->crp_buf = (caddr_t) r->buffer; ++ crp->crp_callback = ocf_cb; ++ crp->crp_sid = ocf_cryptoid; ++ crp->crp_opaque = (caddr_t) r; ++ crypto_dispatch(crp); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ocf_request_wq(struct work_struct *work) ++{ ++ request_t *r = container_of(work, request_t, work); ++ ocf_request(r); ++} ++#endif ++ ++/*************************************************************************/ ++#ifdef BENCH_IXP_ACCESS_LIB ++/*************************************************************************/ ++/* ++ * CryptoAcc benchmark routines ++ */ ++ ++static IxCryptoAccCtx ixp_ctx; ++static UINT32 ixp_ctx_id; ++static IX_MBUF ixp_pri; ++static IX_MBUF ixp_sec; ++static int ixp_registered = 0; ++ ++static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, ++ IxCryptoAccStatus status); ++static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp, ++ IxCryptoAccStatus status); ++static void ixp_request(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ixp_request_wq(struct work_struct *work); ++#endif ++ ++static int ++ixp_init(void) ++{ ++ IxCryptoAccStatus status; ++ ++ ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; ++ ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp_ctx.cipherCtx.cipherKeyLen = 24; ++ ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24); ++ ++ ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; ++ ixp_ctx.authCtx.authDigestLen = 12; ++ ixp_ctx.authCtx.aadLen = 0; ++ ixp_ctx.authCtx.authKeyLen = 20; ++ memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20); ++ ++ ixp_ctx.useDifferentSrcAndDestMbufs = 0; ++ ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ; ++ ++ IX_MBUF_MLEN(&ixp_pri) = IX_MBUF_PKT_LEN(&ixp_pri) = 128; ++ IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ IX_MBUF_MLEN(&ixp_sec) = IX_MBUF_PKT_LEN(&ixp_sec) = 128; ++ IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ ++ status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec, ++ ixp_register_cb, ixp_perform_cb, &ixp_ctx_id); ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) { ++ while (!ixp_registered) ++ schedule(); ++ return ixp_registered < 0 ? -1 : 0; ++ } ++ ++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); ++ return -1; ++} ++ ++static void ++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) ++{ ++ if (bufp) { ++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; ++ kfree(IX_MBUF_MDATA(bufp)); ++ IX_MBUF_MDATA(bufp) = NULL; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_WAIT == status) ++ return; ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ ixp_registered = 1; ++ else ++ ixp_registered = -1; ++} ++ ++static void ++ixp_perform_cb( ++ UINT32 ctx_id, ++ IX_MBUF *sbufp, ++ IX_MBUF *dbufp, ++ IxCryptoAccStatus status) ++{ ++ request_t *r = NULL; ++ ++ total++; ++ if (total > request_num) { ++ outstanding--; ++ return; ++ } ++ ++ if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) { ++ printk("crappo %p %p\n", sbufp, r); ++ outstanding--; ++ return; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&r->work, ixp_request_wq); ++#else ++ INIT_WORK(&r->work, ixp_request, r); ++#endif ++ schedule_work(&r->work); ++} ++ ++static void ++ixp_request(void *arg) ++{ ++ request_t *r = arg; ++ IxCryptoAccStatus status; ++ ++ memset(&r->mbuf, 0, sizeof(r->mbuf)); ++ IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64; ++ IX_MBUF_MDATA(&r->mbuf) = r->buffer; ++ IX_MBUF_PRIV(&r->mbuf) = r; ++ status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL, ++ 0, request_size, 0, request_size, request_size, r->buffer); ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { ++ printk("status1 = %d\n", status); ++ outstanding--; ++ return; ++ } ++ return; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_request_wq(struct work_struct *work) ++{ ++ request_t *r = container_of(work, request_t, work); ++ ixp_request(r); ++} ++#endif ++ ++/*************************************************************************/ ++#endif /* BENCH_IXP_ACCESS_LIB */ ++/*************************************************************************/ ++ ++int ++ocfbench_init(void) ++{ ++ int i, jstart, jstop; ++ ++ printk("Crypto Speed tests\n"); ++ ++ requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL); ++ if (!requests) { ++ printk("malloc failed\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < request_q_len; i++) { ++ /* +64 for return data */ ++ requests[i].buffer = kmalloc(request_size + 128, GFP_DMA); ++ if (!requests[i].buffer) { ++ printk("malloc failed\n"); ++ return -EINVAL; ++ } ++ memset(requests[i].buffer, '0' + i, request_size + 128); ++ } ++ ++ /* ++ * OCF benchmark ++ */ ++ printk("OCF: testing ...\n"); ++ ocf_init(); ++ total = outstanding = 0; ++ jstart = jiffies; ++ for (i = 0; i < request_q_len; i++) { ++ outstanding++; ++ ocf_request(&requests[i]); ++ } ++ while (outstanding > 0) ++ schedule(); ++ jstop = jiffies; ++ ++ printk("OCF: %d requests of %d bytes in %d jiffies\n", total, request_size, ++ jstop - jstart); ++ ++#ifdef BENCH_IXP_ACCESS_LIB ++ /* ++ * IXP benchmark ++ */ ++ printk("IXP: testing ...\n"); ++ ixp_init(); ++ total = outstanding = 0; ++ jstart = jiffies; ++ for (i = 0; i < request_q_len; i++) { ++ outstanding++; ++ ixp_request(&requests[i]); ++ } ++ while (outstanding > 0) ++ schedule(); ++ jstop = jiffies; ++ ++ printk("IXP: %d requests of %d bytes in %d jiffies\n", total, request_size, ++ jstop - jstart); ++#endif /* BENCH_IXP_ACCESS_LIB */ ++ ++ for (i = 0; i < request_q_len; i++) ++ kfree(requests[i].buffer); ++ kfree(requests); ++ return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */ ++} ++ ++static void __exit ocfbench_exit(void) ++{ ++} ++ ++module_init(ocfbench_init); ++module_exit(ocfbench_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ocf-compat.h linux-2.6.30/crypto/ocf/ocf-compat.h +--- linux-2.6.30.orig/crypto/ocf/ocf-compat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocf-compat.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,270 @@ ++#ifndef _BSD_COMPAT_H_ ++#define _BSD_COMPAT_H_ 1 ++/****************************************************************************/ ++/* ++ * Provide compat routines for older linux kernels and BSD kernels ++ * ++ * Written by David McCullough ++ * Copyright (C) 2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this file ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++/****************************************************************************/ ++#ifdef __KERNEL__ ++/* ++ * fake some BSD driver interface stuff specifically for OCF use ++ */ ++ ++typedef struct ocf_device *device_t; ++ ++typedef struct { ++ int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri); ++ int (*cryptodev_freesession)(device_t dev, u_int64_t tid); ++ int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint); ++ int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint); ++} device_method_t; ++#define DEVMETHOD(id, func) id: func ++ ++struct ocf_device { ++ char name[32]; /* the driver name */ ++ char nameunit[32]; /* the driver name + HW instance */ ++ int unit; ++ device_method_t methods; ++ void *softc; ++}; ++ ++#define CRYPTODEV_NEWSESSION(dev, sid, cri) \ ++ ((*(dev)->methods.cryptodev_newsession)(dev,sid,cri)) ++#define CRYPTODEV_FREESESSION(dev, sid) \ ++ ((*(dev)->methods.cryptodev_freesession)(dev, sid)) ++#define CRYPTODEV_PROCESS(dev, crp, hint) \ ++ ((*(dev)->methods.cryptodev_process)(dev, crp, hint)) ++#define CRYPTODEV_KPROCESS(dev, krp, hint) \ ++ ((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint)) ++ ++#define device_get_name(dev) ((dev)->name) ++#define device_get_nameunit(dev) ((dev)->nameunit) ++#define device_get_unit(dev) ((dev)->unit) ++#define device_get_softc(dev) ((dev)->softc) ++ ++#define softc_device_decl \ ++ struct ocf_device _device; \ ++ device_t ++ ++#define softc_device_init(_sc, _name, _unit, _methods) \ ++ if (1) {\ ++ strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \ ++ snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \ ++ (_sc)->_device.unit = _unit; \ ++ (_sc)->_device.methods = _methods; \ ++ (_sc)->_device.softc = (void *) _sc; \ ++ *(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \ ++ } else ++ ++#define softc_get_device(_sc) (&(_sc)->_device) ++ ++/* ++ * iomem support for 2.4 and 2.6 kernels ++ */ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define ocf_iomem_t unsigned long ++ ++/* ++ * implement simple workqueue like support for older kernels ++ */ ++ ++#include ++ ++#define work_struct tq_struct ++ ++#define INIT_WORK(wp, fp, ap) \ ++ do { \ ++ (wp)->sync = 0; \ ++ (wp)->routine = (fp); \ ++ (wp)->data = (ap); \ ++ } while (0) ++ ++#define schedule_work(wp) \ ++ do { \ ++ queue_task((wp), &tq_immediate); \ ++ mark_bh(IMMEDIATE_BH); \ ++ } while (0) ++ ++#define flush_scheduled_work() run_task_queue(&tq_immediate) ++ ++#else ++#define ocf_iomem_t void __iomem * ++ ++#include ++ ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ++#define files_fdtable(files) (files) ++#endif ++ ++#ifdef MODULE_PARM ++#undef module_param /* just in case */ ++#define module_param(a,b,c) MODULE_PARM(a,"i") ++#endif ++ ++#define bzero(s,l) memset(s,0,l) ++#define bcopy(s,d,l) memcpy(d,s,l) ++#define bcmp(x, y, l) memcmp(x,y,l) ++ ++#define MIN(x,y) ((x) < (y) ? (x) : (y)) ++ ++#define device_printf(dev, a...) ({ \ ++ printk("%s: ", device_get_nameunit(dev)); printk(a); \ ++ }) ++ ++#undef printf ++#define printf(fmt...) printk(fmt) ++ ++#define KASSERT(c,p) if (!(c)) { printk p ; } else ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define ocf_daemonize(str) \ ++ daemonize(); \ ++ spin_lock_irq(¤t->sigmask_lock); \ ++ sigemptyset(¤t->blocked); \ ++ recalc_sigpending(current); \ ++ spin_unlock_irq(¤t->sigmask_lock); \ ++ sprintf(current->comm, str); ++#else ++#define ocf_daemonize(str) daemonize(str); ++#endif ++ ++#define TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q)) ++#define TAILQ_EMPTY(q) list_empty(q) ++#define TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m) ++ ++#define read_random(p,l) get_random_bytes(p,l) ++ ++#define DELAY(x) ((x) > 2000 ? mdelay((x)/1000) : udelay(x)) ++#define strtoul simple_strtoul ++ ++#define pci_get_vendor(dev) ((dev)->vendor) ++#define pci_get_device(dev) ((dev)->device) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define pci_set_consistent_dma_mask(dev, mask) (0) ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ++#define pci_dma_sync_single_for_cpu pci_dma_sync_single ++#endif ++ ++#ifndef DMA_32BIT_MASK ++#define DMA_32BIT_MASK 0x00000000ffffffffULL ++#endif ++ ++#define htole32(x) cpu_to_le32(x) ++#define htobe32(x) cpu_to_be32(x) ++#define htole16(x) cpu_to_le16(x) ++#define htobe16(x) cpu_to_be16(x) ++ ++/* older kernels don't have these */ ++ ++#ifndef IRQ_NONE ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define irqreturn_t void ++#endif ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++# define strlcpy(dest,src,len) \ ++ ({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; }) ++#endif ++ ++#ifndef MAX_ERRNO ++#define MAX_ERRNO 4095 ++#endif ++#ifndef IS_ERR_VALUE ++#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO) ++#endif ++ ++/* ++ * common debug for all ++ */ ++#if 1 ++#define dprintk(a...) do { if (debug) printk(a); } while(0) ++#else ++#define dprintk(a...) ++#endif ++ ++#ifndef SLAB_ATOMIC ++/* Changed in 2.6.20, must use GFP_ATOMIC now */ ++#define SLAB_ATOMIC GFP_ATOMIC ++#endif ++ ++/* ++ * need some additional support for older kernels */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2) ++#define pci_register_driver_compat(driver, rc) \ ++ do { \ ++ if ((rc) > 0) { \ ++ (rc) = 0; \ ++ } else if (rc == 0) { \ ++ (rc) = -ENODEV; \ ++ } else { \ ++ pci_unregister_driver(driver); \ ++ } \ ++ } while (0) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ++#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0) ++#else ++#define pci_register_driver_compat(driver,rc) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ ++#include ++ ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, ++ unsigned int len, unsigned int offset) ++{ ++ sg->page = page; ++ sg->offset = offset; ++ sg->length = len; ++} ++ ++static inline void *sg_virt(struct scatterlist *sg) ++{ ++ return page_address(sg->page) + sg->offset; ++} ++ ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++/****************************************************************************/ ++#endif /* _BSD_COMPAT_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocfnull/Makefile linux-2.6.30/crypto/ocf/ocfnull/Makefile +--- linux-2.6.30.orig/crypto/ocf/ocfnull/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocfnull/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_OCFNULL) += ocfnull.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocfnull/ocfnull.c linux-2.6.30/crypto/ocf/ocfnull/ocfnull.c +--- linux-2.6.30.orig/crypto/ocf/ocfnull/ocfnull.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocfnull/ocfnull.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ * An OCF module for determining the cost of crypto versus the cost of ++ * IPSec processing outside of OCF. This modules gives us the effect of ++ * zero cost encryption, of course you will need to run it at both ends ++ * since it does no crypto at all. ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static int32_t null_id = -1; ++static u_int32_t null_sesnum = 0; ++ ++static int null_process(device_t, struct cryptop *, int); ++static int null_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int null_freesession(device_t, u_int64_t); ++ ++#define debug ocfnull_debug ++int ocfnull_debug = 0; ++module_param(ocfnull_debug, int, 0644); ++MODULE_PARM_DESC(ocfnull_debug, "Enable debug"); ++ ++/* ++ * dummy device structure ++ */ ++ ++static struct { ++ softc_device_decl sc_dev; ++} nulldev; ++ ++static device_method_t null_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, null_newsession), ++ DEVMETHOD(cryptodev_freesession,null_freesession), ++ DEVMETHOD(cryptodev_process, null_process), ++}; ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++null_newsession(device_t arg, u_int32_t *sid, struct cryptoini *cri) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (null_sesnum == 0) ++ null_sesnum++; ++ *sid = null_sesnum++; ++ return 0; ++} ++ ++ ++/* ++ * Free a session. ++ */ ++static int ++null_freesession(device_t arg, u_int64_t tid) ++{ ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > null_sesnum) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return 0; ++ return 0; ++} ++ ++ ++/* ++ * Process a request. ++ */ ++static int ++null_process(device_t arg, struct cryptop *crp, int hint) ++{ ++ unsigned int lid; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ /* ++ * find the session we are using ++ */ ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= null_sesnum || lid == 0) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++done: ++ crypto_done(crp); ++ return 0; ++} ++ ++ ++/* ++ * our driver startup and shutdown routines ++ */ ++ ++static int ++null_init(void) ++{ ++ dprintk("%s(%p)\n", __FUNCTION__, null_init); ++ ++ memset(&nulldev, 0, sizeof(nulldev)); ++ softc_device_init(&nulldev, "ocfnull", 0, null_methods); ++ ++ null_id = crypto_get_driverid(softc_get_device(&nulldev), ++ CRYPTOCAP_F_HARDWARE); ++ if (null_id < 0) ++ panic("ocfnull: crypto device cannot initialize!"); ++ ++#define REGISTER(alg) \ ++ crypto_register(null_id,alg,0,0) ++ REGISTER(CRYPTO_DES_CBC); ++ REGISTER(CRYPTO_3DES_CBC); ++ REGISTER(CRYPTO_RIJNDAEL128_CBC); ++ REGISTER(CRYPTO_MD5); ++ REGISTER(CRYPTO_SHA1); ++ REGISTER(CRYPTO_MD5_HMAC); ++ REGISTER(CRYPTO_SHA1_HMAC); ++#undef REGISTER ++ ++ return 0; ++} ++ ++static void ++null_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(null_id); ++ null_id = -1; ++} ++ ++module_init(null_init); ++module_exit(null_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("ocfnull - claims a lot but does nothing"); +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/Makefile linux-2.6.30/crypto/ocf/pasemi/Makefile +--- linux-2.6.30.orig/crypto/ocf/pasemi/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_PASEMI) += pasemi.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/pasemi.c linux-2.6.30/crypto/ocf/pasemi/pasemi.c +--- linux-2.6.30.orig/crypto/ocf/pasemi/pasemi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/pasemi.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1009 @@ ++/* ++ * Copyright (C) 2007 PA Semi, Inc ++ * ++ * Driver for the PA Semi PWRficient DMA Crypto Engine ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * 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 AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pasemi_fnu.h" ++ ++#define DRV_NAME "pasemi" ++ ++#define TIMER_INTERVAL 1000 ++ ++static void __devexit pasemi_dma_remove(struct pci_dev *pdev); ++static struct pasdma_status volatile * dma_status; ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Enable debug"); ++ ++static void pasemi_desc_start(struct pasemi_desc *desc, u64 hdr) ++{ ++ desc->postop = 0; ++ desc->quad[0] = hdr; ++ desc->quad_cnt = 1; ++ desc->size = 1; ++} ++ ++static void pasemi_desc_build(struct pasemi_desc *desc, u64 val) ++{ ++ desc->quad[desc->quad_cnt++] = val; ++ desc->size = (desc->quad_cnt + 1) / 2; ++} ++ ++static void pasemi_desc_hdr(struct pasemi_desc *desc, u64 hdr) ++{ ++ desc->quad[0] |= hdr; ++} ++ ++static int pasemi_desc_size(struct pasemi_desc *desc) ++{ ++ return desc->size; ++} ++ ++static void pasemi_ring_add_desc( ++ struct pasemi_fnu_txring *ring, ++ struct pasemi_desc *desc, ++ struct cryptop *crp) { ++ int i; ++ int ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); ++ ++ TX_DESC_INFO(ring, ring->next_to_fill).desc_size = desc->size; ++ TX_DESC_INFO(ring, ring->next_to_fill).desc_postop = desc->postop; ++ TX_DESC_INFO(ring, ring->next_to_fill).cf_crp = crp; ++ ++ for (i = 0; i < desc->quad_cnt; i += 2) { ++ ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); ++ ring->desc[ring_index] = desc->quad[i]; ++ ring->desc[ring_index + 1] = desc->quad[i + 1]; ++ ring->next_to_fill++; ++ } ++ ++ if (desc->quad_cnt & 1) ++ ring->desc[ring_index + 1] = 0; ++} ++ ++static void pasemi_ring_incr(struct pasemi_softc *sc, int chan_index, int incr) ++{ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_INCR(sc->base_chan + chan_index), ++ incr); ++} ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++pasemi_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct pasemi_softc *sc = device_get_softc(dev); ++ struct pasemi_session *ses = NULL, **sespp; ++ int sesn, blksz = 0; ++ u64 ccmd = 0; ++ unsigned long flags; ++ struct pasemi_desc init_desc; ++ struct pasemi_fnu_txring *txring; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return -EINVAL; ++ } ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (ALG_IS_SIG(c->cri_alg)) { ++ if (macini) ++ return -EINVAL; ++ macini = c; ++ } else if (ALG_IS_CIPHER(c->cri_alg)) { ++ if (encini) ++ return -EINVAL; ++ encini = c; ++ } else { ++ DPRINTF("UNKNOWN c->cri_alg %d\n", c->cri_alg); ++ return -EINVAL; ++ } ++ } ++ if (encini == NULL && macini == NULL) ++ return -EINVAL; ++ if (encini) { ++ /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return -EINVAL; ++ ccmd = DMA_CALGO_DES; ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) ++ return -EINVAL; ++ ccmd = DMA_CALGO_3DES; ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return -EINVAL; ++ ccmd = DMA_CALGO_AES; ++ break; ++ case CRYPTO_ARC4: ++ if (encini->cri_klen != 128) ++ return -EINVAL; ++ ccmd = DMA_CALGO_ARC; ++ break; ++ default: ++ DPRINTF("UNKNOWN encini->cri_alg %d\n", ++ encini->cri_alg); ++ return -EINVAL; ++ } ++ } ++ ++ if (macini) { ++ switch (macini->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ blksz = 16; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ blksz = 20; ++ break; ++ default: ++ DPRINTF("UNKNOWN macini->cri_alg %d\n", ++ macini->cri_alg); ++ return -EINVAL; ++ } ++ if (((macini->cri_klen + 7) / 8) > blksz) { ++ DPRINTF("key length %d bigger than blksize %d not supported\n", ++ ((macini->cri_klen + 7) / 8), blksz); ++ return -EINVAL; ++ } ++ } ++ ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn] == NULL) { ++ sc->sc_sessions[sesn] = (struct pasemi_session *) ++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); ++ ses = sc->sc_sessions[sesn]; ++ break; ++ } else if (sc->sc_sessions[sesn]->used == 0) { ++ ses = sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sespp = (struct pasemi_session **) ++ kzalloc(sc->sc_nsessions * 2 * ++ sizeof(struct pasemi_session *), GFP_ATOMIC); ++ if (sespp == NULL) ++ return -ENOMEM; ++ memcpy(sespp, sc->sc_sessions, ++ sc->sc_nsessions * sizeof(struct pasemi_session *)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = sespp; ++ sesn = sc->sc_nsessions; ++ ses = sc->sc_sessions[sesn] = (struct pasemi_session *) ++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); ++ if (ses == NULL) ++ return -ENOMEM; ++ sc->sc_nsessions *= 2; ++ } ++ ++ ses->used = 1; ++ ++ ses->dma_addr = pci_map_single(sc->dma_pdev, (void *) ses->civ, ++ sizeof(struct pasemi_session), DMA_TO_DEVICE); ++ ++ /* enter the channel scheduler */ ++ spin_lock_irqsave(&sc->sc_chnlock, flags); ++ ++ /* ARC4 has to be processed by the even channel */ ++ if (encini && (encini->cri_alg == CRYPTO_ARC4)) ++ ses->chan = sc->sc_lastchn & ~1; ++ else ++ ses->chan = sc->sc_lastchn; ++ sc->sc_lastchn = (sc->sc_lastchn + 1) % sc->sc_num_channels; ++ ++ spin_unlock_irqrestore(&sc->sc_chnlock, flags); ++ ++ txring = &sc->tx[ses->chan]; ++ ++ if (encini) { ++ ses->ccmd = ccmd; ++ ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ get_random_bytes(ses->civ, sizeof(ses->civ)); ++ ++ ses->keysz = (encini->cri_klen - 63) / 64; ++ memcpy(ses->key, encini->cri_key, (ses->keysz + 1) * 8); ++ ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(ses->chan, (encini && macini) ? 0x68 : 0x40, DMA_FN_CIV0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR((encini && macini) ? 0x68 : 0x40, ses->dma_addr)); ++ } ++ if (macini) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC || ++ macini->cri_alg == CRYPTO_SHA1_HMAC) ++ memcpy(ses->hkey, macini->cri_key, blksz); ++ else { ++ /* Load initialization constants(RFC 1321, 3174) */ ++ ses->hiv[0] = 0x67452301efcdab89ULL; ++ ses->hiv[1] = 0x98badcfe10325476ULL; ++ ses->hiv[2] = 0xc3d2e1f000000000ULL; ++ } ++ ses->hseq = 0ULL; ++ } ++ ++ spin_lock_irqsave(&txring->fill_lock, flags); ++ ++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc)) - ++ txring->next_to_clean) > TX_RING_SIZE) { ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ return ERESTART; ++ } ++ ++ if (encini) { ++ pasemi_ring_add_desc(txring, &init_desc, NULL); ++ pasemi_ring_incr(sc, ses->chan, ++ pasemi_desc_size(&init_desc)); ++ } ++ ++ txring->sesn = sesn; ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ ++ *sidp = PASEMI_SID(sesn); ++ return 0; ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++pasemi_freesession(device_t dev, u_int64_t tid) ++{ ++ struct pasemi_softc *sc = device_get_softc(dev); ++ int session; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (sc == NULL) ++ return -EINVAL; ++ session = PASEMI_SESSION(sid); ++ if (session >= sc->sc_nsessions || !sc->sc_sessions[session]) ++ return -EINVAL; ++ ++ pci_unmap_single(sc->dma_pdev, ++ sc->sc_sessions[session]->dma_addr, ++ sizeof(struct pasemi_session), DMA_TO_DEVICE); ++ memset(sc->sc_sessions[session], 0, ++ sizeof(struct pasemi_session)); ++ ++ return 0; ++} ++ ++static int ++pasemi_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ ++ int err = 0, ivsize, srclen = 0, reinit = 0, reinit_size = 0, chsel; ++ struct pasemi_softc *sc = device_get_softc(dev); ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ caddr_t ivp; ++ struct pasemi_desc init_desc, work_desc; ++ struct pasemi_session *ses; ++ struct sk_buff *skb; ++ struct uio *uiop; ++ unsigned long flags; ++ struct pasemi_fnu_txring *txring; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) ++ return -EINVAL; ++ ++ crp->crp_etype = 0; ++ if (PASEMI_SESSION(crp->crp_sid) >= sc->sc_nsessions) ++ return -EINVAL; ++ ++ ses = sc->sc_sessions[PASEMI_SESSION(crp->crp_sid)]; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ err = -EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ if (ALG_IS_SIG(crd1->crd_alg)) { ++ maccrd = crd1; ++ if (crd2 == NULL) ++ enccrd = NULL; ++ else if (ALG_IS_CIPHER(crd2->crd_alg) && ++ (crd2->crd_flags & CRD_F_ENCRYPT) == 0) ++ enccrd = crd2; ++ else ++ goto erralg; ++ } else if (ALG_IS_CIPHER(crd1->crd_alg)) { ++ enccrd = crd1; ++ if (crd2 == NULL) ++ maccrd = NULL; ++ else if (ALG_IS_SIG(crd2->crd_alg) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) ++ maccrd = crd2; ++ else ++ goto erralg; ++ } else ++ goto erralg; ++ ++ chsel = ses->chan; ++ ++ txring = &sc->tx[chsel]; ++ ++ if (enccrd && !maccrd) { ++ if (enccrd->crd_alg == CRYPTO_ARC4) ++ reinit = 1; ++ reinit_size = 0x40; ++ srclen = crp->crp_ilen; ++ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I ++ | XCT_FUN_FUN(chsel)); ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_ENC); ++ else ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_DEC); ++ } else if (enccrd && maccrd) { ++ if (enccrd->crd_alg == CRYPTO_ARC4) ++ reinit = 1; ++ reinit_size = 0x68; ++ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ /* Encrypt -> Authenticate */ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_ENC_SIG ++ | XCT_FUN_A | XCT_FUN_FUN(chsel)); ++ srclen = maccrd->crd_skip + maccrd->crd_len; ++ } else { ++ /* Authenticate -> Decrypt */ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG_DEC ++ | XCT_FUN_24BRES | XCT_FUN_FUN(chsel)); ++ pasemi_desc_build(&work_desc, 0); ++ pasemi_desc_build(&work_desc, 0); ++ pasemi_desc_build(&work_desc, 0); ++ work_desc.postop = PASEMI_CHECK_SIG; ++ srclen = crp->crp_ilen; ++ } ++ ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SHL(maccrd->crd_skip / 4)); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CHL(enccrd->crd_skip - maccrd->crd_skip)); ++ } else if (!enccrd && maccrd) { ++ srclen = maccrd->crd_len; ++ ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(chsel, 0x58, DMA_FN_HKEY0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR(0x58, ((struct pasemi_session *)ses->dma_addr)->hkey)); ++ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG ++ | XCT_FUN_A | XCT_FUN_FUN(chsel)); ++ } ++ ++ if (enccrd) { ++ switch (enccrd->crd_alg) { ++ case CRYPTO_3DES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_3DES | ++ XCT_FUN_BCM_CBC); ++ ivsize = sizeof(u64); ++ break; ++ case CRYPTO_DES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_DES | ++ XCT_FUN_BCM_CBC); ++ ivsize = sizeof(u64); ++ break; ++ case CRYPTO_AES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_AES | ++ XCT_FUN_BCM_CBC); ++ ivsize = 2 * sizeof(u64); ++ break; ++ case CRYPTO_ARC4: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_ARC); ++ ivsize = 0; ++ break; ++ default: ++ printk(DRV_NAME ": unimplemented enccrd->crd_alg %d\n", ++ enccrd->crd_alg); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ ivp = (ivsize == sizeof(u64)) ? (caddr_t) &ses->civ[1] : (caddr_t) &ses->civ[0]; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ memcpy(ivp, enccrd->crd_iv, ivsize); ++ /* If IV is not present in the buffer already, it has to be copied there */ ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ivp); ++ } else { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ /* IV is provided expicitly in descriptor */ ++ memcpy(ivp, enccrd->crd_iv, ivsize); ++ else ++ /* IV is provided in the packet */ ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ++ ivp); ++ } ++ } ++ ++ if (maccrd) { ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_MD5 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_SHA1: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_SHA1 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_MD5_HMAC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_MD5 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_SHA1_HMAC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_SHA1 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ default: ++ printk(DRV_NAME ": unimplemented maccrd->crd_alg %d\n", ++ maccrd->crd_alg); ++ err = -EINVAL; ++ goto errout; ++ } ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ /* using SKB buffers */ ++ skb = (struct sk_buff *)crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ printk(DRV_NAME ": skb frags unimplemented\n"); ++ err = -EINVAL; ++ goto errout; ++ } ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(skb->len, pci_map_single( ++ sc->dma_pdev, skb->data, ++ skb->len, DMA_TO_DEVICE))); ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR( ++ srclen, pci_map_single( ++ sc->dma_pdev, skb->data, ++ srclen, DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* using IOV buffers */ ++ uiop = (struct uio *)crp->crp_buf; ++ if (uiop->uio_iovcnt > 1) { ++ printk(DRV_NAME ": iov frags unimplemented\n"); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ /* crp_olen is never set; always use crp_ilen */ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( ++ sc->dma_pdev, ++ uiop->uio_iov->iov_base, ++ crp->crp_ilen, DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR(srclen, pci_map_single( ++ sc->dma_pdev, ++ uiop->uio_iov->iov_base, ++ srclen, DMA_TO_DEVICE))); ++ } else { ++ /* using contig buffers */ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( ++ sc->dma_pdev, ++ crp->crp_buf, ++ crp->crp_ilen, DMA_TO_DEVICE))); ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR(srclen, pci_map_single( ++ sc->dma_pdev, ++ crp->crp_buf, srclen, ++ DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ } ++ ++ spin_lock_irqsave(&txring->fill_lock, flags); ++ ++ if (txring->sesn != PASEMI_SESSION(crp->crp_sid)) { ++ txring->sesn = PASEMI_SESSION(crp->crp_sid); ++ reinit = 1; ++ } ++ ++ if (enccrd) { ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(chsel, reinit ? reinit_size : 0x10, DMA_FN_CIV0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR(reinit ? reinit_size : 0x10, ses->dma_addr)); ++ } ++ ++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc) + ++ pasemi_desc_size(&work_desc)) - ++ txring->next_to_clean) > TX_RING_SIZE) { ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ err = ERESTART; ++ goto errout; ++ } ++ ++ pasemi_ring_add_desc(txring, &init_desc, NULL); ++ pasemi_ring_add_desc(txring, &work_desc, crp); ++ ++ pasemi_ring_incr(sc, chsel, ++ pasemi_desc_size(&init_desc) + ++ pasemi_desc_size(&work_desc)); ++ ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ ++ mod_timer(&txring->crypto_timer, jiffies + TIMER_INTERVAL); ++ ++ return 0; ++ ++erralg: ++ printk(DRV_NAME ": unsupported algorithm or algorithm order alg1 %d alg2 %d\n", ++ crd1->crd_alg, crd2->crd_alg); ++ err = -EINVAL; ++ ++errout: ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } ++ return err; ++} ++ ++static int pasemi_clean_tx(struct pasemi_softc *sc, int chan) ++{ ++ int i, j, ring_idx; ++ struct pasemi_fnu_txring *ring = &sc->tx[chan]; ++ u16 delta_cnt; ++ int flags, loops = 10; ++ int desc_size; ++ struct cryptop *crp; ++ ++ spin_lock_irqsave(&ring->clean_lock, flags); ++ ++ while ((delta_cnt = (dma_status->tx_sta[sc->base_chan + chan] ++ & PAS_STATUS_PCNT_M) - ring->total_pktcnt) ++ && loops--) { ++ ++ for (i = 0; i < delta_cnt; i++) { ++ desc_size = TX_DESC_INFO(ring, ring->next_to_clean).desc_size; ++ crp = TX_DESC_INFO(ring, ring->next_to_clean).cf_crp; ++ if (crp) { ++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); ++ if (TX_DESC_INFO(ring, ring->next_to_clean).desc_postop & PASEMI_CHECK_SIG) { ++ /* Need to make sure signature matched, ++ * if not - return error */ ++ if (!(ring->desc[ring_idx + 1] & (1ULL << 63))) ++ crp->crp_etype = -EINVAL; ++ } ++ crypto_done(TX_DESC_INFO(ring, ++ ring->next_to_clean).cf_crp); ++ TX_DESC_INFO(ring, ring->next_to_clean).cf_crp = NULL; ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx + 1]), ++ PCI_DMA_TODEVICE); ++ ++ ring->desc[ring_idx] = ring->desc[ring_idx + 1] = 0; ++ ++ ring->next_to_clean++; ++ for (j = 1; j < desc_size; j++) { ++ ring_idx = 2 * ++ (ring->next_to_clean & ++ (TX_RING_SIZE-1)); ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx]), ++ PCI_DMA_TODEVICE); ++ if (ring->desc[ring_idx + 1]) ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN( ++ ring->desc[ ++ ring_idx + 1]), ++ PCI_DMA_TODEVICE); ++ ring->desc[ring_idx] = ++ ring->desc[ring_idx + 1] = 0; ++ ring->next_to_clean++; ++ } ++ } else { ++ for (j = 0; j < desc_size; j++) { ++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); ++ ring->desc[ring_idx] = ++ ring->desc[ring_idx + 1] = 0; ++ ring->next_to_clean++; ++ } ++ } ++ } ++ ++ ring->total_pktcnt += delta_cnt; ++ } ++ spin_unlock_irqrestore(&ring->clean_lock, flags); ++ ++ return 0; ++} ++ ++static void sweepup_tx(struct pasemi_softc *sc) ++{ ++ int i; ++ ++ for (i = 0; i < sc->sc_num_channels; i++) ++ pasemi_clean_tx(sc, i); ++} ++ ++static irqreturn_t pasemi_intr(int irq, void *arg, struct pt_regs *regs) ++{ ++ struct pasemi_softc *sc = arg; ++ unsigned int reg; ++ int chan = irq - sc->base_irq; ++ int chan_index = sc->base_chan + chan; ++ u64 stat = dma_status->tx_sta[chan_index]; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (!(stat & PAS_STATUS_CAUSE_M)) ++ return IRQ_NONE; ++ ++ pasemi_clean_tx(sc, chan); ++ ++ stat = dma_status->tx_sta[chan_index]; ++ ++ reg = PAS_IOB_DMA_TXCH_RESET_PINTC | ++ PAS_IOB_DMA_TXCH_RESET_PCNT(sc->tx[chan].total_pktcnt); ++ ++ if (stat & PAS_STATUS_SOFT) ++ reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), reg); ++ ++ ++ return IRQ_HANDLED; ++} ++ ++static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan) ++{ ++ u32 val; ++ int chan_index = chan + sc->base_chan; ++ int ret; ++ struct pasemi_fnu_txring *ring; ++ ++ ring = &sc->tx[chan]; ++ ++ spin_lock_init(&ring->fill_lock); ++ spin_lock_init(&ring->clean_lock); ++ ++ ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) * ++ TX_RING_SIZE, GFP_KERNEL); ++ if (!ring->desc_info) ++ return -ENOMEM; ++ ++ /* Allocate descriptors */ ++ ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev, ++ TX_RING_SIZE * ++ 2 * sizeof(u64), ++ &ring->dma, GFP_KERNEL); ++ if (!ring->desc) ++ return -ENOMEM; ++ ++ memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64)); ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30); ++ ++ ring->total_pktcnt = 0; ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index), ++ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); ++ ++ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); ++ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val); ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index), ++ PAS_DMA_TXCHAN_CFG_TY_FUNC | ++ PAS_DMA_TXCHAN_CFG_TATTR(chan) | ++ PAS_DMA_TXCHAN_CFG_WT(2)); ++ ++ /* enable tx channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ PAS_DMA_TXCHAN_TCMDSTA_EN); ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index), ++ PAS_IOB_DMA_TXCH_CFG_CNTTH(1000)); ++ ++ ring->next_to_fill = 0; ++ ring->next_to_clean = 0; ++ ++ snprintf(ring->irq_name, sizeof(ring->irq_name), ++ "%s%d", "crypto", chan); ++ ++ ring->irq = irq_create_mapping(NULL, sc->base_irq + chan); ++ ret = request_irq(ring->irq, (irq_handler_t) ++ pasemi_intr, IRQF_DISABLED, ring->irq_name, sc); ++ if (ret) { ++ printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n", ++ ring->irq, ret); ++ ring->irq = -1; ++ return ret; ++ } ++ ++ setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc); ++ ++ return 0; ++} ++ ++static device_method_t pasemi_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, pasemi_newsession), ++ DEVMETHOD(cryptodev_freesession, pasemi_freesession), ++ DEVMETHOD(cryptodev_process, pasemi_process), ++}; ++ ++/* Set up the crypto device structure, private data, ++ * and anything else we need before we start */ ++ ++static int __devinit ++pasemi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ struct pasemi_softc *sc; ++ int ret, i; ++ ++ DPRINTF(KERN_ERR "%s()\n", __FUNCTION__); ++ ++ sc = kzalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return -ENOMEM; ++ ++ softc_device_init(sc, DRV_NAME, 1, pasemi_methods); ++ ++ pci_set_drvdata(pdev, sc); ++ ++ spin_lock_init(&sc->sc_chnlock); ++ ++ sc->sc_sessions = (struct pasemi_session **) ++ kzalloc(PASEMI_INITIAL_SESSIONS * ++ sizeof(struct pasemi_session *), GFP_ATOMIC); ++ if (sc->sc_sessions == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ sc->sc_nsessions = PASEMI_INITIAL_SESSIONS; ++ sc->sc_lastchn = 0; ++ sc->base_irq = pdev->irq + 6; ++ sc->base_chan = 6; ++ sc->sc_cid = -1; ++ sc->dma_pdev = pdev; ++ ++ sc->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); ++ if (!sc->iob_pdev) { ++ dev_err(&pdev->dev, "Can't find I/O Bridge\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ /* This is hardcoded and ugly, but we have some firmware versions ++ * who don't provide the register space in the device tree. Luckily ++ * they are at well-known locations so we can just do the math here. ++ */ ++ sc->dma_regs = ++ ioremap(0xe0000000 + (sc->dma_pdev->devfn << 12), 0x2000); ++ sc->iob_regs = ++ ioremap(0xe0000000 + (sc->iob_pdev->devfn << 12), 0x2000); ++ if (!sc->dma_regs || !sc->iob_regs) { ++ dev_err(&pdev->dev, "Can't map registers\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ dma_status = __ioremap(0xfd800000, 0x1000, 0); ++ if (!dma_status) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Can't map dmastatus space\n"); ++ goto out; ++ } ++ ++ sc->tx = (struct pasemi_fnu_txring *) ++ kzalloc(sizeof(struct pasemi_fnu_txring) ++ * 8, GFP_KERNEL); ++ if (!sc->tx) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* Initialize the h/w */ ++ out_le32(sc->dma_regs + PAS_DMA_COM_CFG, ++ (in_le32(sc->dma_regs + PAS_DMA_COM_CFG) | ++ PAS_DMA_COM_CFG_FWF)); ++ out_le32(sc->dma_regs + PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); ++ ++ for (i = 0; i < PASEMI_FNU_CHANNELS; i++) { ++ sc->sc_num_channels++; ++ ret = pasemi_dma_setup_tx_resources(sc, i); ++ if (ret) ++ goto out; ++ } ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc), ++ CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ printk(KERN_ERR DRV_NAME ": could not get crypto driver id\n"); ++ ret = -ENXIO; ++ goto out; ++ } ++ ++ /* register algorithms with the framework */ ++ printk(DRV_NAME ":"); ++ ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ ++ return 0; ++ ++out: ++ pasemi_dma_remove(pdev); ++ return ret; ++} ++ ++#define MAX_RETRIES 5000 ++ ++static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan) ++{ ++ struct pasemi_fnu_txring *ring = &sc->tx[chan]; ++ int chan_index = chan + sc->base_chan; ++ int retries; ++ u32 stat; ++ ++ /* Stop the channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ PAS_DMA_TXCHAN_TCMDSTA_ST); ++ ++ for (retries = 0; retries < MAX_RETRIES; retries++) { ++ stat = in_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index)); ++ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) ++ break; ++ cond_resched(); ++ } ++ ++ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) ++ dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n", ++ chan_index); ++ ++ /* Disable the channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ 0); ++ ++ if (ring->desc_info) ++ kfree((void *) ring->desc_info); ++ if (ring->desc) ++ dma_free_coherent(&sc->dma_pdev->dev, ++ TX_RING_SIZE * ++ 2 * sizeof(u64), ++ (void *) ring->desc, ring->dma); ++ if (ring->irq != -1) ++ free_irq(ring->irq, sc); ++ ++ del_timer(&ring->crypto_timer); ++} ++ ++static void __devexit pasemi_dma_remove(struct pci_dev *pdev) ++{ ++ struct pasemi_softc *sc = pci_get_drvdata(pdev); ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (sc->sc_cid >= 0) { ++ crypto_unregister_all(sc->sc_cid); ++ } ++ ++ if (sc->tx) { ++ for (i = 0; i < sc->sc_num_channels; i++) ++ pasemi_free_tx_resources(sc, i); ++ ++ kfree(sc->tx); ++ } ++ if (sc->sc_sessions) { ++ for (i = 0; i < sc->sc_nsessions; i++) ++ kfree(sc->sc_sessions[i]); ++ kfree(sc->sc_sessions); ++ } ++ if (sc->iob_pdev) ++ pci_dev_put(sc->iob_pdev); ++ if (sc->dma_regs) ++ iounmap(sc->dma_regs); ++ if (sc->iob_regs) ++ iounmap(sc->iob_regs); ++ kfree(sc); ++} ++ ++static struct pci_device_id pasemi_dma_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa007) }, ++}; ++ ++MODULE_DEVICE_TABLE(pci, pasemi_dma_pci_tbl); ++ ++static struct pci_driver pasemi_dma_driver = { ++ .name = "pasemi_dma", ++ .id_table = pasemi_dma_pci_tbl, ++ .probe = pasemi_dma_probe, ++ .remove = __devexit_p(pasemi_dma_remove), ++}; ++ ++static void __exit pasemi_dma_cleanup_module(void) ++{ ++ pci_unregister_driver(&pasemi_dma_driver); ++ __iounmap(dma_status); ++ dma_status = NULL; ++} ++ ++int pasemi_dma_init_module(void) ++{ ++ return pci_register_driver(&pasemi_dma_driver); ++} ++ ++module_init(pasemi_dma_init_module); ++module_exit(pasemi_dma_cleanup_module); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Egor Martovetsky egor@pasemi.com"); ++MODULE_DESCRIPTION("OCF driver for PA Semi PWRficient DMA Crypto Engine"); +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/pasemi_fnu.h linux-2.6.30/crypto/ocf/pasemi/pasemi_fnu.h +--- linux-2.6.30.orig/crypto/ocf/pasemi/pasemi_fnu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/pasemi_fnu.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,410 @@ ++/* ++ * Copyright (C) 2007 PA Semi, Inc ++ * ++ * Driver for the PA Semi PWRficient DMA Crypto Engine, soft state and ++ * hardware register layouts. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * 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 PASEMI_FNU_H ++#define PASEMI_FNU_H ++ ++#include ++ ++#define PASEMI_SESSION(sid) ((sid) & 0xffffffff) ++#define PASEMI_SID(sesn) ((sesn) & 0xffffffff) ++#define DPRINTF(a...) if (debug) { printk(DRV_NAME ": " a); } ++ ++/* Must be a power of two */ ++#define RX_RING_SIZE 512 ++#define TX_RING_SIZE 512 ++#define TX_DESC(ring, num) ((ring)->desc[2 * (num & (TX_RING_SIZE-1))]) ++#define TX_DESC_INFO(ring, num) ((ring)->desc_info[(num) & (TX_RING_SIZE-1)]) ++#define MAX_DESC_SIZE 8 ++#define PASEMI_INITIAL_SESSIONS 10 ++#define PASEMI_FNU_CHANNELS 8 ++ ++/* DMA descriptor */ ++struct pasemi_desc { ++ u64 quad[2*MAX_DESC_SIZE]; ++ int quad_cnt; ++ int size; ++ int postop; ++}; ++ ++/* ++ * Holds per descriptor data ++ */ ++struct pasemi_desc_info { ++ int desc_size; ++ int desc_postop; ++#define PASEMI_CHECK_SIG 0x1 ++ ++ struct cryptop *cf_crp; ++}; ++ ++/* ++ * Holds per channel data ++ */ ++struct pasemi_fnu_txring { ++ volatile u64 *desc; ++ volatile struct ++ pasemi_desc_info *desc_info; ++ dma_addr_t dma; ++ struct timer_list crypto_timer; ++ spinlock_t fill_lock; ++ spinlock_t clean_lock; ++ unsigned int next_to_fill; ++ unsigned int next_to_clean; ++ u16 total_pktcnt; ++ int irq; ++ int sesn; ++ char irq_name[10]; ++}; ++ ++/* ++ * Holds data specific to a single pasemi device. ++ */ ++struct pasemi_softc { ++ softc_device_decl sc_cdev; ++ struct pci_dev *dma_pdev; /* device backpointer */ ++ struct pci_dev *iob_pdev; /* device backpointer */ ++ void __iomem *dma_regs; ++ void __iomem *iob_regs; ++ int base_irq; ++ int base_chan; ++ int32_t sc_cid; /* crypto tag */ ++ int sc_nsessions; ++ struct pasemi_session **sc_sessions; ++ int sc_num_channels;/* number of crypto channels */ ++ ++ /* pointer to the array of txring datastructures, one txring per channel */ ++ struct pasemi_fnu_txring *tx; ++ ++ /* ++ * mutual exclusion for the channel scheduler ++ */ ++ spinlock_t sc_chnlock; ++ /* last channel used, for now use round-robin to allocate channels */ ++ int sc_lastchn; ++}; ++ ++struct pasemi_session { ++ u64 civ[2]; ++ u64 keysz; ++ u64 key[4]; ++ u64 ccmd; ++ u64 hkey[4]; ++ u64 hseq; ++ u64 giv[2]; ++ u64 hiv[4]; ++ ++ int used; ++ dma_addr_t dma_addr; ++ int chan; ++}; ++ ++/* status register layout in IOB region, at 0xfd800000 */ ++struct pasdma_status { ++ u64 rx_sta[64]; ++ u64 tx_sta[20]; ++}; ++ ++#define ALG_IS_CIPHER(alg) ((alg == CRYPTO_DES_CBC) || \ ++ (alg == CRYPTO_3DES_CBC) || \ ++ (alg == CRYPTO_AES_CBC) || \ ++ (alg == CRYPTO_ARC4) || \ ++ (alg == CRYPTO_NULL_CBC)) ++ ++#define ALG_IS_SIG(alg) ((alg == CRYPTO_MD5) || \ ++ (alg == CRYPTO_MD5_HMAC) || \ ++ (alg == CRYPTO_SHA1) || \ ++ (alg == CRYPTO_SHA1_HMAC) || \ ++ (alg == CRYPTO_NULL_HMAC)) ++ ++enum { ++ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ ++ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ ++ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ ++ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ ++ PAS_DMA_COM_CFG = 0x114, /* DMA Configuration Register */ ++}; ++ ++/* All these registers live in the PCI configuration space for the DMA PCI ++ * device. Use the normal PCI config access functions for them. ++ */ ++ ++#define PAS_DMA_COM_CFG_FWF 0x18000000 ++ ++#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ ++#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ ++#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ ++#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ ++ ++#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ ++#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ ++#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ ++#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ ++#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ ++#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ ++#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ ++#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ ++#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ ++#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ ++#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ ++#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002 /* Type = interface */ ++#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ ++#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c ++#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 ++#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ ++ PAS_DMA_TXCHAN_CFG_TATTR_M) ++#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 ++#define PAS_DMA_TXCHAN_CFG_WT_S 6 ++#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ ++ PAS_DMA_TXCHAN_CFG_WT_M) ++#define PAS_DMA_TXCHAN_CFG_LPSQ_FAST 0x00000400 ++#define PAS_DMA_TXCHAN_CFG_LPDQ_FAST 0x00000800 ++#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ ++#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ ++#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ ++#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 ++#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 ++#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ ++ PAS_DMA_TXCHAN_BASEL_BRBL_M) ++#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff ++#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 ++#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ ++ PAS_DMA_TXCHAN_BASEU_BRBH_M) ++/* # of cache lines worth of buffer ring */ ++#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 ++#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ ++#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ ++ PAS_DMA_TXCHAN_BASEU_SIZ_M) ++ ++#define PAS_STATUS_PCNT_M 0x000000000000ffffull ++#define PAS_STATUS_PCNT_S 0 ++#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull ++#define PAS_STATUS_DCNT_S 16 ++#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull ++#define PAS_STATUS_BPCNT_S 32 ++#define PAS_STATUS_CAUSE_M 0xf000000000000000ull ++#define PAS_STATUS_TIMER 0x1000000000000000ull ++#define PAS_STATUS_ERROR 0x2000000000000000ull ++#define PAS_STATUS_SOFT 0x4000000000000000ull ++#define PAS_STATUS_INT 0x8000000000000000ull ++ ++#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ ++ PAS_IOB_DMA_RXCH_CFG_CNTTH_M) ++#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ ++ PAS_IOB_DMA_TXCH_CFG_CNTTH_M) ++#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) ++#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ ++ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) ++#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) ++#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ ++ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) ++#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) ++#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 ++#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 16 ++#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ ++ PAS_IOB_DMA_RXCH_RESET_PCNT_M) ++#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 ++#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 ++#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 ++#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 ++#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 ++#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 ++#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) ++#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 ++#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 16 ++#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ ++ PAS_IOB_DMA_TXCH_RESET_PCNT_M) ++#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 ++#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 ++#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 ++#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 ++#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 ++#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 ++ ++#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ ++ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) ++ ++/* Transmit descriptor fields */ ++#define XCT_MACTX_T 0x8000000000000000ull ++#define XCT_MACTX_ST 0x4000000000000000ull ++#define XCT_MACTX_NORES 0x0000000000000000ull ++#define XCT_MACTX_8BRES 0x1000000000000000ull ++#define XCT_MACTX_24BRES 0x2000000000000000ull ++#define XCT_MACTX_40BRES 0x3000000000000000ull ++#define XCT_MACTX_I 0x0800000000000000ull ++#define XCT_MACTX_O 0x0400000000000000ull ++#define XCT_MACTX_E 0x0200000000000000ull ++#define XCT_MACTX_VLAN_M 0x0180000000000000ull ++#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull ++#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull ++#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull ++#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull ++#define XCT_MACTX_CRC_M 0x0060000000000000ull ++#define XCT_MACTX_CRC_NOP 0x0000000000000000ull ++#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull ++#define XCT_MACTX_CRC_PAD 0x0040000000000000ull ++#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull ++#define XCT_MACTX_SS 0x0010000000000000ull ++#define XCT_MACTX_LLEN_M 0x00007fff00000000ull ++#define XCT_MACTX_LLEN_S 32ull ++#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ ++ XCT_MACTX_LLEN_M) ++#define XCT_MACTX_IPH_M 0x00000000f8000000ull ++#define XCT_MACTX_IPH_S 27ull ++#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ ++ XCT_MACTX_IPH_M) ++#define XCT_MACTX_IPO_M 0x0000000007c00000ull ++#define XCT_MACTX_IPO_S 22ull ++#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ ++ XCT_MACTX_IPO_M) ++#define XCT_MACTX_CSUM_M 0x0000000000000060ull ++#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull ++#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull ++#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull ++#define XCT_MACTX_V6 0x0000000000000010ull ++#define XCT_MACTX_C 0x0000000000000004ull ++#define XCT_MACTX_AL2 0x0000000000000002ull ++ ++#define XCT_PTR_T 0x8000000000000000ull ++#define XCT_PTR_LEN_M 0x7ffff00000000000ull ++#define XCT_PTR_LEN_S 44 ++#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ ++ XCT_PTR_LEN_M) ++#define XCT_PTR_ADDR_M 0x00000fffffffffffull ++#define XCT_PTR_ADDR_S 0 ++#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ ++ XCT_PTR_ADDR_M) ++ ++/* Function descriptor fields */ ++#define XCT_FUN_T 0x8000000000000000ull ++#define XCT_FUN_ST 0x4000000000000000ull ++#define XCT_FUN_NORES 0x0000000000000000ull ++#define XCT_FUN_8BRES 0x1000000000000000ull ++#define XCT_FUN_24BRES 0x2000000000000000ull ++#define XCT_FUN_40BRES 0x3000000000000000ull ++#define XCT_FUN_I 0x0800000000000000ull ++#define XCT_FUN_O 0x0400000000000000ull ++#define XCT_FUN_E 0x0200000000000000ull ++#define XCT_FUN_FUN_S 54 ++#define XCT_FUN_FUN_M 0x01c0000000000000ull ++#define XCT_FUN_FUN(num) ((((long)(num)) << XCT_FUN_FUN_S) & \ ++ XCT_FUN_FUN_M) ++#define XCT_FUN_CRM_NOP 0x0000000000000000ull ++#define XCT_FUN_CRM_SIG 0x0008000000000000ull ++#define XCT_FUN_CRM_ENC 0x0010000000000000ull ++#define XCT_FUN_CRM_DEC 0x0018000000000000ull ++#define XCT_FUN_CRM_SIG_ENC 0x0020000000000000ull ++#define XCT_FUN_CRM_ENC_SIG 0x0028000000000000ull ++#define XCT_FUN_CRM_SIG_DEC 0x0030000000000000ull ++#define XCT_FUN_CRM_DEC_SIG 0x0038000000000000ull ++#define XCT_FUN_LLEN_M 0x0007ffff00000000ull ++#define XCT_FUN_LLEN_S 32ULL ++#define XCT_FUN_LLEN(x) ((((long)(x)) << XCT_FUN_LLEN_S) & \ ++ XCT_FUN_LLEN_M) ++#define XCT_FUN_SHL_M 0x00000000f8000000ull ++#define XCT_FUN_SHL_S 27ull ++#define XCT_FUN_SHL(x) ((((long)(x)) << XCT_FUN_SHL_S) & \ ++ XCT_FUN_SHL_M) ++#define XCT_FUN_CHL_M 0x0000000007c00000ull ++#define XCT_FUN_CHL_S 22ull ++#define XCT_FUN_CHL(x) ((((long)(x)) << XCT_FUN_CHL_S) & \ ++ XCT_FUN_CHL_M) ++#define XCT_FUN_HSZ_M 0x00000000003c0000ull ++#define XCT_FUN_HSZ_S 18ull ++#define XCT_FUN_HSZ(x) ((((long)(x)) << XCT_FUN_HSZ_S) & \ ++ XCT_FUN_HSZ_M) ++#define XCT_FUN_ALG_DES 0x0000000000000000ull ++#define XCT_FUN_ALG_3DES 0x0000000000008000ull ++#define XCT_FUN_ALG_AES 0x0000000000010000ull ++#define XCT_FUN_ALG_ARC 0x0000000000018000ull ++#define XCT_FUN_ALG_KASUMI 0x0000000000020000ull ++#define XCT_FUN_BCM_ECB 0x0000000000000000ull ++#define XCT_FUN_BCM_CBC 0x0000000000001000ull ++#define XCT_FUN_BCM_CFB 0x0000000000002000ull ++#define XCT_FUN_BCM_OFB 0x0000000000003000ull ++#define XCT_FUN_BCM_CNT 0x0000000000003800ull ++#define XCT_FUN_BCM_KAS_F8 0x0000000000002800ull ++#define XCT_FUN_BCM_KAS_F9 0x0000000000001800ull ++#define XCT_FUN_BCP_NO_PAD 0x0000000000000000ull ++#define XCT_FUN_BCP_ZRO 0x0000000000000200ull ++#define XCT_FUN_BCP_PL 0x0000000000000400ull ++#define XCT_FUN_BCP_INCR 0x0000000000000600ull ++#define XCT_FUN_SIG_MD5 (0ull << 4) ++#define XCT_FUN_SIG_SHA1 (2ull << 4) ++#define XCT_FUN_SIG_HMAC_MD5 (8ull << 4) ++#define XCT_FUN_SIG_HMAC_SHA1 (10ull << 4) ++#define XCT_FUN_A 0x0000000000000008ull ++#define XCT_FUN_C 0x0000000000000004ull ++#define XCT_FUN_AL2 0x0000000000000002ull ++#define XCT_FUN_SE 0x0000000000000001ull ++ ++#define XCT_FUN_SRC_PTR(len, addr) (XCT_PTR_LEN(len) | XCT_PTR_ADDR(addr)) ++#define XCT_FUN_DST_PTR(len, addr) (XCT_FUN_SRC_PTR(len, addr) | \ ++ 0x8000000000000000ull) ++ ++#define XCT_CTRL_HDR_FUN_NUM_M 0x01c0000000000000ull ++#define XCT_CTRL_HDR_FUN_NUM_S 54 ++#define XCT_CTRL_HDR_LEN_M 0x0007ffff00000000ull ++#define XCT_CTRL_HDR_LEN_S 32 ++#define XCT_CTRL_HDR_REG_M 0x00000000000000ffull ++#define XCT_CTRL_HDR_REG_S 0 ++ ++#define XCT_CTRL_HDR(funcN,len,reg) (0x9400000000000000ull | \ ++ ((((long)(funcN)) << XCT_CTRL_HDR_FUN_NUM_S) \ ++ & XCT_CTRL_HDR_FUN_NUM_M) | \ ++ ((((long)(len)) << \ ++ XCT_CTRL_HDR_LEN_S) & XCT_CTRL_HDR_LEN_M) | \ ++ ((((long)(reg)) << \ ++ XCT_CTRL_HDR_REG_S) & XCT_CTRL_HDR_REG_M)) ++ ++/* Function config command options */ ++#define DMA_CALGO_DES 0x00 ++#define DMA_CALGO_3DES 0x01 ++#define DMA_CALGO_AES 0x02 ++#define DMA_CALGO_ARC 0x03 ++ ++#define DMA_FN_CIV0 0x02 ++#define DMA_FN_CIV1 0x03 ++#define DMA_FN_HKEY0 0x0a ++ ++#define XCT_PTR_ADDR_LEN(ptr) ((ptr) & XCT_PTR_ADDR_M), \ ++ (((ptr) & XCT_PTR_LEN_M) >> XCT_PTR_LEN_S) ++ ++#endif /* PASEMI_FNU_H */ +diff -Nur linux-2.6.30.orig/crypto/ocf/random.c linux-2.6.30/crypto/ocf/random.c +--- linux-2.6.30.orig/crypto/ocf/random.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/random.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,317 @@ ++/* ++ * A system independant way of adding entropy to the kernels pool ++ * this way the drivers can focus on the real work and we can take ++ * care of pushing it to the appropriate place in the kernel. ++ * ++ * This should be fast and callable from timers/interrupts ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_OCF_FIPS ++#include "rndtest.h" ++#endif ++ ++#ifndef HAS_RANDOM_INPUT_WAIT ++#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches" ++#endif ++ ++/* ++ * a hack to access the debug levels from the crypto driver ++ */ ++extern int crypto_debug; ++#define debug crypto_debug ++ ++/* ++ * a list of all registered random providers ++ */ ++static LIST_HEAD(random_ops); ++static int started = 0; ++static int initted = 0; ++ ++struct random_op { ++ struct list_head random_list; ++ u_int32_t driverid; ++ int (*read_random)(void *arg, u_int32_t *buf, int len); ++ void *arg; ++}; ++ ++static int random_proc(void *arg); ++ ++static pid_t randomproc = (pid_t) -1; ++static spinlock_t random_lock; ++ ++/* ++ * just init the spin locks ++ */ ++static int ++crypto_random_init(void) ++{ ++ spin_lock_init(&random_lock); ++ initted = 1; ++ return(0); ++} ++ ++/* ++ * Add the given random reader to our list (if not present) ++ * and start the thread (if not already started) ++ * ++ * we have to assume that driver id is ok for now ++ */ ++int ++crypto_rregister( ++ u_int32_t driverid, ++ int (*read_random)(void *arg, u_int32_t *buf, int len), ++ void *arg) ++{ ++ unsigned long flags; ++ int ret = 0; ++ struct random_op *rops, *tmp; ++ ++ dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__, ++ __FUNCTION__, driverid, read_random, arg); ++ ++ if (!initted) ++ crypto_random_init(); ++ ++#if 0 ++ struct cryptocap *cap; ++ ++ cap = crypto_checkdriver(driverid); ++ if (!cap) ++ return EINVAL; ++#endif ++ ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ if (rops->driverid == driverid && rops->read_random == read_random) ++ return EEXIST; ++ } ++ ++ rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL); ++ if (!rops) ++ return ENOMEM; ++ ++ rops->driverid = driverid; ++ rops->read_random = read_random; ++ rops->arg = arg; ++ ++ spin_lock_irqsave(&random_lock, flags); ++ list_add_tail(&rops->random_list, &random_ops); ++ if (!started) { ++ randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (randomproc < 0) { ++ ret = randomproc; ++ printk("crypto: crypto_rregister cannot start random thread; " ++ "error %d", ret); ++ } else ++ started = 1; ++ } ++ spin_unlock_irqrestore(&random_lock, flags); ++ ++ return ret; ++} ++EXPORT_SYMBOL(crypto_rregister); ++ ++int ++crypto_runregister_all(u_int32_t driverid) ++{ ++ struct random_op *rops, *tmp; ++ unsigned long flags; ++ ++ dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid); ++ ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ if (rops->driverid == driverid) { ++ list_del(&rops->random_list); ++ kfree(rops); ++ } ++ } ++ ++ spin_lock_irqsave(&random_lock, flags); ++ if (list_empty(&random_ops) && started) ++ kill_pid(randomproc, SIGKILL, 1); ++ spin_unlock_irqrestore(&random_lock, flags); ++ return(0); ++} ++EXPORT_SYMBOL(crypto_runregister_all); ++ ++/* ++ * while we can add entropy to random.c continue to read random data from ++ * the drivers and push it to random. ++ */ ++static int ++random_proc(void *arg) ++{ ++ int n; ++ int wantcnt; ++ int bufcnt = 0; ++ int retval = 0; ++ int *buf = NULL; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ daemonize(); ++ spin_lock_irq(¤t->sigmask_lock); ++ sigemptyset(¤t->blocked); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ sprintf(current->comm, "ocf-random"); ++#else ++ daemonize("ocf-random"); ++ allow_signal(SIGKILL); ++#endif ++ ++ (void) get_fs(); ++ set_fs(get_ds()); ++ ++#ifdef CONFIG_OCF_FIPS ++#define NUM_INT (RNDTEST_NBYTES/sizeof(int)) ++#else ++#define NUM_INT 32 ++#endif ++ ++ /* ++ * some devices can transferr their RNG data direct into memory, ++ * so make sure it is device friendly ++ */ ++ buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA); ++ if (NULL == buf) { ++ printk("crypto: RNG could not allocate memory\n"); ++ retval = -ENOMEM; ++ goto bad_alloc; ++ } ++ ++ wantcnt = NUM_INT; /* start by adding some entropy */ ++ ++ /* ++ * its possible due to errors or driver removal that we no longer ++ * have anything to do, if so exit or we will consume all the CPU ++ * doing nothing ++ */ ++ while (!list_empty(&random_ops)) { ++ struct random_op *rops, *tmp; ++ ++#ifdef CONFIG_OCF_FIPS ++ if (wantcnt) ++ wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */ ++#endif ++ ++ /* see if we can get enough entropy to make the world ++ * a better place. ++ */ ++ while (bufcnt < wantcnt && bufcnt < NUM_INT) { ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ ++ n = (*rops->read_random)(rops->arg, &buf[bufcnt], ++ NUM_INT - bufcnt); ++ ++ /* on failure remove the random number generator */ ++ if (n == -1) { ++ list_del(&rops->random_list); ++ printk("crypto: RNG (driverid=0x%x) failed, disabling\n", ++ rops->driverid); ++ kfree(rops); ++ } else if (n > 0) ++ bufcnt += n; ++ } ++ /* give up CPU for a bit, just in case as this is a loop */ ++ schedule(); ++ } ++ ++ ++#ifdef CONFIG_OCF_FIPS ++ if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) { ++ dprintk("crypto: buffer had fips errors, discarding\n"); ++ bufcnt = 0; ++ } ++#endif ++ ++ /* ++ * if we have a certified buffer, we can send some data ++ * to /dev/random and move along ++ */ ++ if (bufcnt > 0) { ++ /* add what we have */ ++ random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8); ++ bufcnt = 0; ++ } ++ ++ /* give up CPU for a bit so we don't hog while filling */ ++ schedule(); ++ ++ /* wait for needing more */ ++ wantcnt = random_input_wait(); ++ ++ if (wantcnt <= 0) ++ wantcnt = 0; /* try to get some info again */ ++ else ++ /* round up to one word or we can loop forever */ ++ wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8); ++ if (wantcnt > NUM_INT) { ++ wantcnt = NUM_INT; ++ } ++ ++ if (signal_pending(current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ } ++ ++ kfree(buf); ++ ++bad_alloc: ++ spin_lock_irq(&random_lock); ++ randomproc = (pid_t) -1; ++ started = 0; ++ spin_unlock_irq(&random_lock); ++ ++ return retval; ++} ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/README linux-2.6.30/crypto/ocf/README +--- linux-2.6.30.orig/crypto/ocf/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/README 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,167 @@ ++README - ocf-linux-20071215 ++--------------------------- ++ ++This README provides instructions for getting ocf-linux compiled and ++operating in a generic linux environment. For other information you ++might like to visit the home page for this project: ++ ++ http://ocf-linux.sourceforge.net/ ++ ++Adding OCF to linux ++------------------- ++ ++ Not much in this file for now, just some notes. I usually build ++ the ocf support as modules but it can be built into the kernel as ++ well. To use it: ++ ++ * mknod /dev/crypto c 10 70 ++ ++ * to add OCF to your kernel source, you have two options. Apply ++ the kernel specific patch: ++ ++ cd linux-2.4*; gunzip < ocf-linux-24-XXXXXXXX.patch.gz | patch -p1 ++ cd linux-2.6*; gunzip < ocf-linux-26-XXXXXXXX.patch.gz | patch -p1 ++ ++ if you do one of the above, then you can proceed to the next step, ++ or you can do the above process by hand with using the patches against ++ linux-2.4.35 and 2.6.23 to include the ocf code under crypto/ocf. ++ Here's how to add it: ++ ++ for 2.4.35 (and later) ++ ++ cd linux-2.4.35/crypto ++ tar xvzf ocf-linux.tar.gz ++ cd .. ++ patch -p1 < crypto/ocf/patches/linux-2.4.35-ocf.patch ++ ++ for 2.6.23 (and later), find the kernel patch specific (or nearest) ++ to your kernel versions and then: ++ ++ cd linux-2.6.NN/crypto ++ tar xvzf ocf-linux.tar.gz ++ cd .. ++ patch -p1 < crypto/ocf/patches/linux-2.6.NN-ocf.patch ++ ++ It should be easy to take this patch and apply it to other more ++ recent versions of the kernels. The same patches should also work ++ relatively easily on kernels as old as 2.6.11 and 2.4.18. ++ ++ * under 2.4 if you are on a non-x86 platform, you may need to: ++ ++ cp linux-2.X.x/include/asm-i386/kmap_types.h linux-2.X.x/include/asm-YYY ++ ++ so that you can build the kernel crypto support needed for the cryptosoft ++ driver. ++ ++ * For simplicity you should enable all the crypto support in your kernel ++ except for the test driver. Likewise for the OCF options. Do not ++ enable OCF crypto drivers for HW that you do not have (for example ++ ixp4xx will not compile on non-Xscale systems). ++ ++ * make sure that cryptodev.h (from ocf-linux.tar.gz) is installed as ++ crypto/cryptodev.h in an include directory that is used for building ++ applications for your platform. For example on a host system that ++ might be: ++ ++ /usr/include/crypto/cryptodev.h ++ ++ * patch your openssl-0.9.8i code with the openssl-0.9.8i.patch. ++ (NOTE: there is no longer a need to patch ssh). The patch is against: ++ openssl-0_9_8e ++ ++ If you need a patch for an older version of openssl, you should look ++ to older OCF releases. This patch is unlikely to work on older ++ openssl versions. ++ ++ openssl-0.9.8i.patch ++ - enables --with-cryptodev for non BSD systems ++ - adds -cpu option to openssl speed for calculating CPU load ++ under linux ++ - fixes null pointer in openssl speed multi thread output. ++ - fixes test keys to work with linux crypto's more stringent ++ key checking. ++ - adds MD5/SHA acceleration (Ronen Shitrit), only enabled ++ with the --with-cryptodev-digests option ++ - fixes bug in engine code caching. ++ ++ * build crypto-tools-XXXXXXXX.tar.gz if you want to try some of the BSD ++ tools for testing OCF (ie., cryptotest). ++ ++How to load the OCF drivers ++--------------------------- ++ ++ First insert the base modules: ++ ++ insmod ocf ++ insmod cryptodev ++ ++ You can then install the software OCF driver with: ++ ++ insmod cryptosoft ++ ++ and one or more of the OCF HW drivers with: ++ ++ insmod safe ++ insmod hifn7751 ++ insmod ixp4xx ++ ... ++ ++ all the drivers take a debug option to enable verbose debug so that ++ you can see what is going on. For debug you load them as: ++ ++ insmod ocf crypto_debug=1 ++ insmod cryptodev cryptodev_debug=1 ++ insmod cryptosoft swcr_debug=1 ++ ++ You may load more than one OCF crypto driver but then there is no guarantee ++ as to which will be used. ++ ++ You can also enable debug at run time on 2.6 systems with the following: ++ ++ echo 1 > /sys/module/ocf/parameters/crypto_debug ++ echo 1 > /sys/module/cryptodev/parameters/cryptodev_debug ++ echo 1 > /sys/module/cryptosoft/parameters/swcr_debug ++ echo 1 > /sys/module/hifn7751/parameters/hifn_debug ++ echo 1 > /sys/module/safe/parameters/safe_debug ++ echo 1 > /sys/module/ixp4xx/parameters/ixp_debug ++ ... ++ ++Testing the OCF support ++----------------------- ++ ++ run "cryptotest", it should do a short test for a couple of ++ des packets. If it does everything is working. ++ ++ If this works, then ssh will use the driver when invoked as: ++ ++ ssh -c 3des username@host ++ ++ to see for sure that it is operating, enable debug as defined above. ++ ++ To get a better idea of performance run: ++ ++ cryptotest 100 4096 ++ ++ There are more options to cryptotest, see the help. ++ ++ It is also possible to use openssl to test the speed of the crypto ++ drivers. ++ ++ openssl speed -evp des -engine cryptodev -elapsed ++ openssl speed -evp des3 -engine cryptodev -elapsed ++ openssl speed -evp aes128 -engine cryptodev -elapsed ++ ++ and multiple threads (10) with: ++ ++ openssl speed -evp des -engine cryptodev -elapsed -multi 10 ++ openssl speed -evp des3 -engine cryptodev -elapsed -multi 10 ++ openssl speed -evp aes128 -engine cryptodev -elapsed -multi 10 ++ ++ for public key testing you can try: ++ ++ cryptokeytest ++ openssl speed -engine cryptodev rsa -elapsed ++ openssl speed -engine cryptodev dsa -elapsed ++ ++David McCullough ++david_mccullough@securecomputing.com +diff -Nur linux-2.6.30.orig/crypto/ocf/rndtest.c linux-2.6.30/crypto/ocf/rndtest.c +--- linux-2.6.30.orig/crypto/ocf/rndtest.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/rndtest.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,300 @@ ++/* $OpenBSD$ */ ++ ++/* ++ * OCF/Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Jason L. Wright ++ * 4. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rndtest.h" ++ ++static struct rndtest_stats rndstats; ++ ++static void rndtest_test(struct rndtest_state *); ++ ++/* The tests themselves */ ++static int rndtest_monobit(struct rndtest_state *); ++static int rndtest_runs(struct rndtest_state *); ++static int rndtest_longruns(struct rndtest_state *); ++static int rndtest_chi_4(struct rndtest_state *); ++ ++static int rndtest_runs_check(struct rndtest_state *, int, int *); ++static void rndtest_runs_record(struct rndtest_state *, int, int *); ++ ++static const struct rndtest_testfunc { ++ int (*test)(struct rndtest_state *); ++} rndtest_funcs[] = { ++ { rndtest_monobit }, ++ { rndtest_runs }, ++ { rndtest_chi_4 }, ++ { rndtest_longruns }, ++}; ++ ++#define RNDTEST_NTESTS (sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0])) ++ ++static void ++rndtest_test(struct rndtest_state *rsp) ++{ ++ int i, rv = 0; ++ ++ rndstats.rst_tests++; ++ for (i = 0; i < RNDTEST_NTESTS; i++) ++ rv |= (*rndtest_funcs[i].test)(rsp); ++ rsp->rs_discard = (rv != 0); ++} ++ ++ ++extern int crypto_debug; ++#define rndtest_verbose 2 ++#define rndtest_report(rsp, failure, fmt, a...) \ ++ { if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; } ++ ++#define RNDTEST_MONOBIT_MINONES 9725 ++#define RNDTEST_MONOBIT_MAXONES 10275 ++ ++static int ++rndtest_monobit(struct rndtest_state *rsp) ++{ ++ int i, ones = 0, j; ++ u_int8_t r; ++ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ r = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, r <<= 1) ++ if (r & 0x80) ++ ones++; ++ } ++ if (ones > RNDTEST_MONOBIT_MINONES && ++ ones < RNDTEST_MONOBIT_MAXONES) { ++ if (rndtest_verbose > 1) ++ rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)", ++ RNDTEST_MONOBIT_MINONES, ones, ++ RNDTEST_MONOBIT_MAXONES); ++ return (0); ++ } else { ++ if (rndtest_verbose) ++ rndtest_report(rsp, 1, ++ "monobit failed (%d ones)", ones); ++ rndstats.rst_monobit++; ++ return (-1); ++ } ++} ++ ++#define RNDTEST_RUNS_NINTERVAL 6 ++ ++static const struct rndtest_runs_tabs { ++ u_int16_t min, max; ++} rndtest_runs_tab[] = { ++ { 2343, 2657 }, ++ { 1135, 1365 }, ++ { 542, 708 }, ++ { 251, 373 }, ++ { 111, 201 }, ++ { 111, 201 }, ++}; ++ ++static int ++rndtest_runs(struct rndtest_state *rsp) ++{ ++ int i, j, ones, zeros, rv = 0; ++ int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL]; ++ u_int8_t c; ++ ++ bzero(onei, sizeof(onei)); ++ bzero(zeroi, sizeof(zeroi)); ++ ones = zeros = 0; ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ c = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, c <<= 1) { ++ if (c & 0x80) { ++ ones++; ++ rndtest_runs_record(rsp, zeros, zeroi); ++ zeros = 0; ++ } else { ++ zeros++; ++ rndtest_runs_record(rsp, ones, onei); ++ ones = 0; ++ } ++ } ++ } ++ rndtest_runs_record(rsp, ones, onei); ++ rndtest_runs_record(rsp, zeros, zeroi); ++ ++ rv |= rndtest_runs_check(rsp, 0, zeroi); ++ rv |= rndtest_runs_check(rsp, 1, onei); ++ ++ if (rv) ++ rndstats.rst_runs++; ++ ++ return (rv); ++} ++ ++static void ++rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv) ++{ ++ if (len == 0) ++ return; ++ if (len > RNDTEST_RUNS_NINTERVAL) ++ len = RNDTEST_RUNS_NINTERVAL; ++ len -= 1; ++ intrv[len]++; ++} ++ ++static int ++rndtest_runs_check(struct rndtest_state *rsp, int val, int *src) ++{ ++ int i, rv = 0; ++ ++ for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) { ++ if (src[i] < rndtest_runs_tab[i].min || ++ src[i] > rndtest_runs_tab[i].max) { ++ rndtest_report(rsp, 1, ++ "%s interval %d failed (%d, %d-%d)", ++ val ? "ones" : "zeros", ++ i + 1, src[i], rndtest_runs_tab[i].min, ++ rndtest_runs_tab[i].max); ++ rv = -1; ++ } else { ++ rndtest_report(rsp, 0, ++ "runs pass %s interval %d (%d < %d < %d)", ++ val ? "ones" : "zeros", ++ i + 1, rndtest_runs_tab[i].min, src[i], ++ rndtest_runs_tab[i].max); ++ } ++ } ++ return (rv); ++} ++ ++static int ++rndtest_longruns(struct rndtest_state *rsp) ++{ ++ int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0; ++ u_int8_t c; ++ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ c = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, c <<= 1) { ++ if (c & 0x80) { ++ zeros = 0; ++ ones++; ++ if (ones > maxones) ++ maxones = ones; ++ } else { ++ ones = 0; ++ zeros++; ++ if (zeros > maxzeros) ++ maxzeros = zeros; ++ } ++ } ++ } ++ ++ if (maxones < 26 && maxzeros < 26) { ++ rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)", ++ maxones, maxzeros); ++ return (0); ++ } else { ++ rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)", ++ maxones, maxzeros); ++ rndstats.rst_longruns++; ++ return (-1); ++ } ++} ++ ++/* ++ * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2, ++ * but it is really the chi^2 test over 4 bits (the poker test as described ++ * by Knuth vol 2 is something different, and I take him as authoritative ++ * on nomenclature over NIST). ++ */ ++#define RNDTEST_CHI4_K 16 ++#define RNDTEST_CHI4_K_MASK (RNDTEST_CHI4_K - 1) ++ ++/* ++ * The unnormalized values are used so that we don't have to worry about ++ * fractional precision. The "real" value is found by: ++ * (V - 1562500) * (16 / 5000) = Vn (where V is the unnormalized value) ++ */ ++#define RNDTEST_CHI4_VMIN 1563181 /* 2.1792 */ ++#define RNDTEST_CHI4_VMAX 1576929 /* 46.1728 */ ++ ++static int ++rndtest_chi_4(struct rndtest_state *rsp) ++{ ++ unsigned int freq[RNDTEST_CHI4_K], i, sum; ++ ++ for (i = 0; i < RNDTEST_CHI4_K; i++) ++ freq[i] = 0; ++ ++ /* Get number of occurances of each 4 bit pattern */ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++; ++ freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++; ++ } ++ ++ for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++) ++ sum += freq[i] * freq[i]; ++ ++ if (sum >= 1563181 && sum <= 1576929) { ++ rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum); ++ return (0); ++ } else { ++ rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum); ++ rndstats.rst_chi++; ++ return (-1); ++ } ++} ++ ++int ++rndtest_buf(unsigned char *buf) ++{ ++ struct rndtest_state rsp; ++ ++ memset(&rsp, 0, sizeof(rsp)); ++ rsp.rs_buf = buf; ++ rndtest_test(&rsp); ++ return(rsp.rs_discard); ++} ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/rndtest.h linux-2.6.30/crypto/ocf/rndtest.h +--- linux-2.6.30.orig/crypto/ocf/rndtest.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/rndtest.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* $FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $ */ ++/* $OpenBSD$ */ ++ ++/* ++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Jason L. Wright ++ * 4. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/* Some of the tests depend on these values */ ++#define RNDTEST_NBYTES 2500 ++#define RNDTEST_NBITS (8 * RNDTEST_NBYTES) ++ ++struct rndtest_state { ++ int rs_discard; /* discard/accept random data */ ++ u_int8_t *rs_buf; ++}; ++ ++struct rndtest_stats { ++ u_int32_t rst_discard; /* number of bytes discarded */ ++ u_int32_t rst_tests; /* number of test runs */ ++ u_int32_t rst_monobit; /* monobit test failures */ ++ u_int32_t rst_runs; /* 0/1 runs failures */ ++ u_int32_t rst_longruns; /* longruns failures */ ++ u_int32_t rst_chi; /* chi^2 failures */ ++}; ++ ++extern int rndtest_buf(unsigned char *buf); +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/Makefile linux-2.6.30/crypto/ocf/safe/Makefile +--- linux-2.6.30.orig/crypto/ocf/safe/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_SAFE) += safe.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/md5.c linux-2.6.30/crypto/ocf/safe/md5.c +--- linux-2.6.30.orig/crypto/ocf/safe/md5.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/md5.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,308 @@ ++/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/crypto/md5.c,v 1.9 2004/01/27 19:49:19 des Exp $"); ++ ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) ++ ++#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) ++#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) ++#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) ++#define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) ++ ++#define ROUND1(a, b, c, d, k, s, i) { \ ++ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND2(a, b, c, d, k, s, i) { \ ++ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND3(a, b, c, d, k, s, i) { \ ++ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND4(a, b, c, d, k, s, i) { \ ++ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define Sa 7 ++#define Sb 12 ++#define Sc 17 ++#define Sd 22 ++ ++#define Se 5 ++#define Sf 9 ++#define Sg 14 ++#define Sh 20 ++ ++#define Si 4 ++#define Sj 11 ++#define Sk 16 ++#define Sl 23 ++ ++#define Sm 6 ++#define Sn 10 ++#define So 15 ++#define Sp 21 ++ ++#define MD5_A0 0x67452301 ++#define MD5_B0 0xefcdab89 ++#define MD5_C0 0x98badcfe ++#define MD5_D0 0x10325476 ++ ++/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ ++static const u_int32_t T[65] = { ++ 0, ++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, ++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, ++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, ++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, ++ ++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, ++ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, ++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, ++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, ++ ++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, ++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, ++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, ++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, ++ ++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, ++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, ++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, ++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, ++}; ++ ++static const u_int8_t md5_paddat[MD5_BUFLEN] = { ++ 0x80, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++static void md5_calc(u_int8_t *, md5_ctxt *); ++ ++void md5_init(ctxt) ++ md5_ctxt *ctxt; ++{ ++ ctxt->md5_n = 0; ++ ctxt->md5_i = 0; ++ ctxt->md5_sta = MD5_A0; ++ ctxt->md5_stb = MD5_B0; ++ ctxt->md5_stc = MD5_C0; ++ ctxt->md5_std = MD5_D0; ++ bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); ++} ++ ++void md5_loop(ctxt, input, len) ++ md5_ctxt *ctxt; ++ u_int8_t *input; ++ u_int len; /* number of bytes */ ++{ ++ u_int gap, i; ++ ++ ctxt->md5_n += len * 8; /* byte to bit */ ++ gap = MD5_BUFLEN - ctxt->md5_i; ++ ++ if (len >= gap) { ++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap); ++ md5_calc(ctxt->md5_buf, ctxt); ++ ++ for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { ++ md5_calc((u_int8_t *)(input + i), ctxt); ++ } ++ ++ ctxt->md5_i = len - i; ++ bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); ++ } else { ++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ len); ++ ctxt->md5_i += len; ++ } ++} ++ ++void md5_pad(ctxt) ++ md5_ctxt *ctxt; ++{ ++ u_int gap; ++ ++ /* Don't count up padding. Keep md5_n. */ ++ gap = MD5_BUFLEN - ctxt->md5_i; ++ if (gap > 8) { ++ bcopy(md5_paddat, ++ (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap - sizeof(ctxt->md5_n)); ++ } else { ++ /* including gap == 8 */ ++ bcopy(md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap); ++ md5_calc(ctxt->md5_buf, ctxt); ++ bcopy((md5_paddat + gap), ++ (void *)ctxt->md5_buf, ++ MD5_BUFLEN - sizeof(ctxt->md5_n)); ++ } ++ ++ /* 8 byte word */ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ ctxt->md5_buf[56] = ctxt->md5_n8[7]; ++ ctxt->md5_buf[57] = ctxt->md5_n8[6]; ++ ctxt->md5_buf[58] = ctxt->md5_n8[5]; ++ ctxt->md5_buf[59] = ctxt->md5_n8[4]; ++ ctxt->md5_buf[60] = ctxt->md5_n8[3]; ++ ctxt->md5_buf[61] = ctxt->md5_n8[2]; ++ ctxt->md5_buf[62] = ctxt->md5_n8[1]; ++ ctxt->md5_buf[63] = ctxt->md5_n8[0]; ++#endif ++ ++ md5_calc(ctxt->md5_buf, ctxt); ++} ++ ++void md5_result(digest, ctxt) ++ u_int8_t *digest; ++ md5_ctxt *ctxt; ++{ ++ /* 4 byte words */ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ bcopy(&ctxt->md5_st8[0], digest, 16); ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; ++ digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; ++ digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; ++ digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; ++ digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; ++ digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; ++ digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; ++ digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; ++#endif ++} ++ ++static void md5_calc(b64, ctxt) ++ u_int8_t *b64; ++ md5_ctxt *ctxt; ++{ ++ u_int32_t A = ctxt->md5_sta; ++ u_int32_t B = ctxt->md5_stb; ++ u_int32_t C = ctxt->md5_stc; ++ u_int32_t D = ctxt->md5_std; ++#if BYTE_ORDER == LITTLE_ENDIAN ++ u_int32_t *X = (u_int32_t *)b64; ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ /* 4 byte words */ ++ /* what a brute force but fast! */ ++ u_int32_t X[16]; ++ u_int8_t *y = (u_int8_t *)X; ++ y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; ++ y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; ++ y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; ++ y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; ++ y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; ++ y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; ++ y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; ++ y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; ++ y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; ++ y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; ++ y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; ++ y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; ++ y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; ++ y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; ++ y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; ++ y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; ++#endif ++ ++ ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); ++ ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); ++ ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); ++ ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); ++ ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); ++ ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); ++ ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); ++ ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); ++ ++ ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); ++ ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); ++ ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); ++ ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); ++ ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); ++ ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); ++ ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); ++ ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); ++ ++ ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); ++ ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); ++ ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); ++ ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); ++ ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); ++ ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); ++ ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); ++ ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); ++ ++ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); ++ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); ++ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); ++ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); ++ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); ++ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); ++ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); ++ ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); ++ ++ ctxt->md5_sta += A; ++ ctxt->md5_stb += B; ++ ctxt->md5_stc += C; ++ ctxt->md5_std += D; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/md5.h linux-2.6.30/crypto/ocf/safe/md5.h +--- linux-2.6.30.orig/crypto/ocf/safe/md5.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/md5.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* $FreeBSD: src/sys/crypto/md5.h,v 1.4 2002/03/20 05:13:50 alfred Exp $ */ ++/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ ++ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#ifndef _NETINET6_MD5_H_ ++#define _NETINET6_MD5_H_ ++ ++#define MD5_BUFLEN 64 ++ ++typedef struct { ++ union { ++ u_int32_t md5_state32[4]; ++ u_int8_t md5_state8[16]; ++ } md5_st; ++ ++#define md5_sta md5_st.md5_state32[0] ++#define md5_stb md5_st.md5_state32[1] ++#define md5_stc md5_st.md5_state32[2] ++#define md5_std md5_st.md5_state32[3] ++#define md5_st8 md5_st.md5_state8 ++ ++ union { ++ u_int64_t md5_count64; ++ u_int8_t md5_count8[8]; ++ } md5_count; ++#define md5_n md5_count.md5_count64 ++#define md5_n8 md5_count.md5_count8 ++ ++ u_int md5_i; ++ u_int8_t md5_buf[MD5_BUFLEN]; ++} md5_ctxt; ++ ++extern void md5_init(md5_ctxt *); ++extern void md5_loop(md5_ctxt *, u_int8_t *, u_int); ++extern void md5_pad(md5_ctxt *); ++extern void md5_result(u_int8_t *, md5_ctxt *); ++ ++/* compatibility */ ++#define MD5_CTX md5_ctxt ++#define MD5Init(x) md5_init((x)) ++#define MD5Update(x, y, z) md5_loop((x), (y), (z)) ++#define MD5Final(x, y) \ ++do { \ ++ md5_pad((y)); \ ++ md5_result((x), (y)); \ ++} while (0) ++ ++#endif /* ! _NETINET6_MD5_H_*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safe.c linux-2.6.30/crypto/ocf/safe/safe.c +--- linux-2.6.30.orig/crypto/ocf/safe/safe.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safe.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,2288 @@ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++__FBSDID("$FreeBSD: src/sys/dev/safe/safe.c,v 1.18 2007/03/21 03:42:50 sam Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * SafeNet SafeXcel-1141 hardware crypto accelerator ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DPRINTF(a) do { \ ++ if (debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "safe"); \ ++ printk a; \ ++ } \ ++ } while (0) ++#else ++#define DPRINTF(a) ++#endif ++ ++/* ++ * until we find a cleaner way, include the BSD md5/sha1 code ++ * here ++ */ ++#define HMAC_HACK 1 ++#ifdef HMAC_HACK ++#define LITTLE_ENDIAN 1234 ++#define BIG_ENDIAN 4321 ++#ifdef __LITTLE_ENDIAN ++#define BYTE_ORDER LITTLE_ENDIAN ++#endif ++#ifdef __BIG_ENDIAN ++#define BYTE_ORDER BIG_ENDIAN ++#endif ++#include ++#include ++#include ++#include ++ ++u_int8_t hmac_ipad_buffer[64] = { ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 ++}; ++ ++u_int8_t hmac_opad_buffer[64] = { ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C ++}; ++#endif /* HMAC_HACK */ ++ ++/* add proc entry for this */ ++struct safe_stats safestats; ++ ++#define debug safe_debug ++int safe_debug = 0; ++module_param(safe_debug, int, 0644); ++MODULE_PARM_DESC(safe_debug, "Enable debug"); ++ ++static void safe_callback(struct safe_softc *, struct safe_ringentry *); ++static void safe_feed(struct safe_softc *, struct safe_ringentry *); ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++static void safe_rng_init(struct safe_softc *); ++int safe_rngbufsize = 8; /* 32 bytes each read */ ++module_param(safe_rngbufsize, int, 0644); ++MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)"); ++int safe_rngmaxalarm = 8; /* max alarms before reset */ ++module_param(safe_rngmaxalarm, int, 0644); ++MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset"); ++#endif /* SAFE_NO_RNG */ ++ ++static void safe_totalreset(struct safe_softc *sc); ++static int safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op); ++static int safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op); ++static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re); ++static int safe_kprocess(device_t dev, struct cryptkop *krp, int hint); ++static int safe_kstart(struct safe_softc *sc); ++static int safe_ksigbits(struct safe_softc *sc, struct crparam *cr); ++static void safe_kfeed(struct safe_softc *sc); ++static void safe_kpoll(unsigned long arg); ++static void safe_kload_reg(struct safe_softc *sc, u_int32_t off, ++ u_int32_t len, struct crparam *n); ++ ++static int safe_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int safe_freesession(device_t, u_int64_t); ++static int safe_process(device_t, struct cryptop *, int); ++ ++static device_method_t safe_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, safe_newsession), ++ DEVMETHOD(cryptodev_freesession,safe_freesession), ++ DEVMETHOD(cryptodev_process, safe_process), ++ DEVMETHOD(cryptodev_kprocess, safe_kprocess), ++}; ++ ++#define READ_REG(sc,r) readl((sc)->sc_base_addr + (r)) ++#define WRITE_REG(sc,r,val) writel((val), (sc)->sc_base_addr + (r)) ++ ++#define SAFE_MAX_CHIPS 8 ++static struct safe_softc *safe_chip_idx[SAFE_MAX_CHIPS]; ++ ++/* ++ * split our buffers up into safe DMAable byte fragments to avoid lockup ++ * bug in 1141 HW on rev 1.0. ++ */ ++ ++static int ++pci_map_linear( ++ struct safe_softc *sc, ++ struct safe_operand *buf, ++ void *addr, ++ int len) ++{ ++ dma_addr_t tmp; ++ int chunk, tlen = len; ++ ++ tmp = pci_map_single(sc->sc_pcidev, addr, len, PCI_DMA_BIDIRECTIONAL); ++ ++ buf->mapsize += len; ++ while (len > 0) { ++ chunk = (len > sc->sc_max_dsize) ? sc->sc_max_dsize : len; ++ buf->segs[buf->nsegs].ds_addr = tmp; ++ buf->segs[buf->nsegs].ds_len = chunk; ++ buf->segs[buf->nsegs].ds_tlen = tlen; ++ buf->nsegs++; ++ tmp += chunk; ++ len -= chunk; ++ tlen = 0; ++ } ++ return 0; ++} ++ ++/* ++ * map in a given uio buffer (great on some arches :-) ++ */ ++ ++static int ++pci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int n; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ buf->mapsize = 0; ++ buf->nsegs = 0; ++ ++ for (n = 0; n < uio->uio_iovcnt; n++) { ++ pci_map_linear(sc, buf, iov->iov_base, iov->iov_len); ++ iov++; ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given sk_buff ++ */ ++ ++static int ++pci_map_skb(struct safe_softc *sc,struct safe_operand *buf,struct sk_buff *skb) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ buf->mapsize = 0; ++ buf->nsegs = 0; ++ ++ pci_map_linear(sc, buf, skb->data, skb_headlen(skb)); ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ pci_map_linear(sc, buf, ++ page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ skb_shinfo(skb)->frags[i].size); ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++ ++#if 0 /* not needed at this time */ ++static void ++pci_sync_operand(struct safe_softc *sc, struct safe_operand *buf) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ for (i = 0; i < buf->nsegs; i++) ++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++} ++#endif ++ ++static void ++pci_unmap_operand(struct safe_softc *sc, struct safe_operand *buf) ++{ ++ int i; ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ for (i = 0; i < buf->nsegs; i++) { ++ if (buf->segs[i].ds_tlen) { ++ DPRINTF(("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); ++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_tlen, PCI_DMA_BIDIRECTIONAL); ++ DPRINTF(("%s - unmap %d 0x%x %d done\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); ++ } ++ buf->segs[i].ds_addr = 0; ++ buf->segs[i].ds_len = 0; ++ buf->segs[i].ds_tlen = 0; ++ } ++ buf->nsegs = 0; ++ buf->mapsize = 0; ++ buf->map = 0; ++} ++ ++ ++/* ++ * SafeXcel Interrupt routine ++ */ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++safe_intr(int irq, void *arg) ++#else ++safe_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct safe_softc *sc = arg; ++ int stat; ++ unsigned long flags; ++ ++ stat = READ_REG(sc, SAFE_HM_STAT); ++ ++ DPRINTF(("%s(stat=0x%x)\n", __FUNCTION__, stat)); ++ ++ if (stat == 0) /* shared irq, not for us */ ++ return IRQ_NONE; ++ ++ WRITE_REG(sc, SAFE_HI_CLR, stat); /* IACK */ ++ ++ if ((stat & SAFE_INT_PE_DDONE)) { ++ /* ++ * Descriptor(s) done; scan the ring and ++ * process completed operations. ++ */ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ while (sc->sc_back != sc->sc_front) { ++ struct safe_ringentry *re = sc->sc_back; ++ ++#ifdef SAFE_DEBUG ++ if (debug) { ++ safe_dump_ringstate(sc, __func__); ++ safe_dump_request(sc, __func__, re); ++ } ++#endif ++ /* ++ * safe_process marks ring entries that were allocated ++ * but not used with a csr of zero. This insures the ++ * ring front pointer never needs to be set backwards ++ * in the event that an entry is allocated but not used ++ * because of a setup error. ++ */ ++ DPRINTF(("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr)); ++ if (re->re_desc.d_csr != 0) { ++ if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) { ++ DPRINTF(("%s !CSR_IS_DONE\n", __FUNCTION__)); ++ break; ++ } ++ if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) { ++ DPRINTF(("%s !LEN_IS_DONE\n", __FUNCTION__)); ++ break; ++ } ++ sc->sc_nqchip--; ++ safe_callback(sc, re); ++ } ++ if (++(sc->sc_back) == sc->sc_ringtop) ++ sc->sc_back = sc->sc_ring; ++ } ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ } ++ ++ /* ++ * Check to see if we got any DMA Error ++ */ ++ if (stat & SAFE_INT_PE_ERROR) { ++ printk("%s: dmaerr dmastat %08x\n", device_get_nameunit(sc->sc_dev), ++ (int)READ_REG(sc, SAFE_PE_DMASTAT)); ++ safestats.st_dmaerr++; ++ safe_totalreset(sc); ++#if 0 ++ safe_feed(sc); ++#endif ++ } ++ ++ if (sc->sc_needwakeup) { /* XXX check high watermark */ ++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); ++ DPRINTF(("%s: wakeup crypto %x\n", __func__, ++ sc->sc_needwakeup)); ++ sc->sc_needwakeup &= ~wakeup; ++ crypto_unblock(sc->sc_cid, wakeup); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * safe_feed() - post a request to chip ++ */ ++static void ++safe_feed(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++#ifdef SAFE_DEBUG ++ if (debug) { ++ safe_dump_ringstate(sc, __func__); ++ safe_dump_request(sc, __func__, re); ++ } ++#endif ++ sc->sc_nqchip++; ++ if (sc->sc_nqchip > safestats.st_maxqchip) ++ safestats.st_maxqchip = sc->sc_nqchip; ++ /* poke h/w to check descriptor ring, any value can be written */ ++ WRITE_REG(sc, SAFE_HI_RD_DESCR, 0); ++} ++ ++#define N(a) (sizeof(a) / sizeof (a[0])) ++static void ++safe_setup_enckey(struct safe_session *ses, caddr_t key) ++{ ++ int i; ++ ++ bcopy(key, ses->ses_key, ses->ses_klen / 8); ++ ++ /* PE is little-endian, insure proper byte order */ ++ for (i = 0; i < N(ses->ses_key); i++) ++ ses->ses_key[i] = htole32(ses->ses_key[i]); ++} ++ ++static void ++safe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen) ++{ ++#ifdef HMAC_HACK ++ MD5_CTX md5ctx; ++ SHA1_CTX sha1ctx; ++ int i; ++ ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= HMAC_IPAD_VAL; ++ ++ if (algo == CRYPTO_MD5_HMAC) { ++ MD5Init(&md5ctx); ++ MD5Update(&md5ctx, key, klen); ++ MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen); ++ bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8)); ++ } else { ++ SHA1Init(&sha1ctx); ++ SHA1Update(&sha1ctx, key, klen); ++ SHA1Update(&sha1ctx, hmac_ipad_buffer, ++ SHA1_HMAC_BLOCK_LEN - klen); ++ bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32)); ++ } ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); ++ ++ if (algo == CRYPTO_MD5_HMAC) { ++ MD5Init(&md5ctx); ++ MD5Update(&md5ctx, key, klen); ++ MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen); ++ bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8)); ++ } else { ++ SHA1Init(&sha1ctx); ++ SHA1Update(&sha1ctx, key, klen); ++ SHA1Update(&sha1ctx, hmac_opad_buffer, ++ SHA1_HMAC_BLOCK_LEN - klen); ++ bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32)); ++ } ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= HMAC_OPAD_VAL; ++ ++#if 0 ++ /* ++ * this code prevents SHA working on a BE host, ++ * so it is obviously wrong. I think the byte ++ * swap setup we do with the chip fixes this for us ++ */ ++ ++ /* PE is little-endian, insure proper byte order */ ++ for (i = 0; i < N(ses->ses_hminner); i++) { ++ ses->ses_hminner[i] = htole32(ses->ses_hminner[i]); ++ ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]); ++ } ++#endif ++#else /* HMAC_HACK */ ++ printk("safe: md5/sha not implemented\n"); ++#endif /* HMAC_HACK */ ++} ++#undef N ++ ++/* ++ * Allocate a new 'session' and return an encoded session id. 'sidp' ++ * contains our registration id, and should contain an encoded session ++ * id on successful allocation. ++ */ ++static int ++safe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct safe_session *ses = NULL; ++ int sesn; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sidp == NULL || cri == NULL || sc == NULL) ++ return (EINVAL); ++ ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (c->cri_alg == CRYPTO_MD5_HMAC || ++ c->cri_alg == CRYPTO_SHA1_HMAC || ++ c->cri_alg == CRYPTO_NULL_HMAC) { ++ if (macini) ++ return (EINVAL); ++ macini = c; ++ } else if (c->cri_alg == CRYPTO_DES_CBC || ++ c->cri_alg == CRYPTO_3DES_CBC || ++ c->cri_alg == CRYPTO_AES_CBC || ++ c->cri_alg == CRYPTO_NULL_CBC) { ++ if (encini) ++ return (EINVAL); ++ encini = c; ++ } else ++ return (EINVAL); ++ } ++ if (encini == NULL && macini == NULL) ++ return (EINVAL); ++ if (encini) { /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return (EINVAL); ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) ++ return (EINVAL); ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return (EINVAL); ++ break; ++ } ++ } ++ ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct safe_session *) ++ kmalloc(sizeof(struct safe_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return (ENOMEM); ++ memset(ses, 0, sizeof(struct safe_session)); ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn].ses_used == 0) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sesn = sc->sc_nsessions; ++ ses = (struct safe_session *) ++ kmalloc((sesn + 1) * sizeof(struct safe_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return (ENOMEM); ++ memset(ses, 0, (sesn + 1) * sizeof(struct safe_session)); ++ bcopy(sc->sc_sessions, ses, sesn * ++ sizeof(struct safe_session)); ++ bzero(sc->sc_sessions, sesn * ++ sizeof(struct safe_session)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ ++ bzero(ses, sizeof(struct safe_session)); ++ ses->ses_used = 1; ++ ++ if (encini) { ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ read_random(ses->ses_iv, sizeof(ses->ses_iv)); ++ ++ ses->ses_klen = encini->cri_klen; ++ if (encini->cri_key != NULL) ++ safe_setup_enckey(ses, encini->cri_key); ++ } ++ ++ if (macini) { ++ ses->ses_mlen = macini->cri_mlen; ++ if (ses->ses_mlen == 0) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC) ++ ses->ses_mlen = MD5_HASH_LEN; ++ else ++ ses->ses_mlen = SHA1_HASH_LEN; ++ } ++ ++ if (macini->cri_key != NULL) { ++ safe_setup_mackey(ses, macini->cri_alg, macini->cri_key, ++ macini->cri_klen / 8); ++ } ++ } ++ ++ *sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn); ++ return (0); ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++safe_freesession(device_t dev, u_int64_t tid) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ int session, ret; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc == NULL) ++ return (EINVAL); ++ ++ session = SAFE_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session])); ++ ret = 0; ++ } else ++ ret = EINVAL; ++ return (ret); ++} ++ ++ ++static int ++safe_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ int err = 0, i, nicealign, uniform; ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ int bypass, oplen, ivsize; ++ caddr_t iv; ++ int16_t coffset; ++ struct safe_session *ses; ++ struct safe_ringentry *re; ++ struct safe_sarec *sa; ++ struct safe_pdesc *pd; ++ u_int32_t cmd0, cmd1, staterec; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { ++ safestats.st_invalid++; ++ return (EINVAL); ++ } ++ if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) { ++ safestats.st_badsession++; ++ return (EINVAL); ++ } ++ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) { ++ safestats.st_ringfull++; ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ return (ERESTART); ++ } ++ re = sc->sc_front; ++ ++ staterec = re->re_sa.sa_staterec; /* save */ ++ /* NB: zero everything but the PE descriptor */ ++ bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc)); ++ re->re_sa.sa_staterec = staterec; /* restore */ ++ ++ re->re_crp = crp; ++ re->re_sesn = SAFE_SESSION(crp->crp_sid); ++ ++ re->re_src.nsegs = 0; ++ re->re_dst.nsegs = 0; ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ re->re_src_skb = (struct sk_buff *)crp->crp_buf; ++ re->re_dst_skb = (struct sk_buff *)crp->crp_buf; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ re->re_src_io = (struct uio *)crp->crp_buf; ++ re->re_dst_io = (struct uio *)crp->crp_buf; ++ } else { ++ safestats.st_badflags++; ++ err = EINVAL; ++ goto errout; /* XXX we don't handle contiguous blocks! */ ++ } ++ ++ sa = &re->re_sa; ++ ses = &sc->sc_sessions[re->re_sesn]; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ safestats.st_nodesc++; ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ cmd0 = SAFE_SA_CMD0_BASIC; /* basic group operation */ ++ cmd1 = 0; ++ if (crd2 == NULL) { ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_NULL_HMAC) { ++ maccrd = crd1; ++ enccrd = NULL; ++ cmd0 |= SAFE_SA_CMD0_OP_HASH; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_NULL_CBC) { ++ maccrd = NULL; ++ enccrd = crd1; ++ cmd0 |= SAFE_SA_CMD0_OP_CRYPT; ++ } else { ++ safestats.st_badalg++; ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_NULL_HMAC) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_NULL_CBC) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_NULL_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_NULL_HMAC) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ safestats.st_badalg++; ++ err = EINVAL; ++ goto errout; ++ } ++ cmd0 |= SAFE_SA_CMD0_OP_BOTH; ++ } ++ ++ if (enccrd) { ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) ++ safe_setup_enckey(ses, enccrd->crd_key); ++ ++ if (enccrd->crd_alg == CRYPTO_DES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_DES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (enccrd->crd_alg == CRYPTO_3DES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_3DES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (enccrd->crd_alg == CRYPTO_AES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_AES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ if (ses->ses_klen == 128) ++ cmd1 |= SAFE_SA_CMD1_AES128; ++ else if (ses->ses_klen == 192) ++ cmd1 |= SAFE_SA_CMD1_AES192; ++ else ++ cmd1 |= SAFE_SA_CMD1_AES256; ++ ivsize = 4*sizeof(u_int32_t); ++ } else { ++ cmd0 |= SAFE_SA_CMD0_CRYPT_NULL; ++ ivsize = 0; ++ } ++ ++ /* ++ * Setup encrypt/decrypt state. When using basic ops ++ * we can't use an inline IV because hash/crypt offset ++ * must be from the end of the IV to the start of the ++ * crypt data and this leaves out the preceding header ++ * from the hash calculation. Instead we place the IV ++ * in the state record and set the hash/crypt offset to ++ * copy both the header+IV. ++ */ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ cmd0 |= SAFE_SA_CMD0_OUTBOUND; ++ ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ iv = enccrd->crd_iv; ++ else ++ iv = (caddr_t) ses->ses_iv; ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ bcopy(iv, re->re_sastate.sa_saved_iv, ivsize); ++ /* make iv LE */ ++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) ++ re->re_sastate.sa_saved_iv[i] = ++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]); ++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV; ++ re->re_flags |= SAFE_QFLAGS_COPYOUTIV; ++ } else { ++ cmd0 |= SAFE_SA_CMD0_INBOUND; ++ ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ bcopy(enccrd->crd_iv, ++ re->re_sastate.sa_saved_iv, ivsize); ++ } else { ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ++ (caddr_t)re->re_sastate.sa_saved_iv); ++ } ++ /* make iv LE */ ++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) ++ re->re_sastate.sa_saved_iv[i] = ++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]); ++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE; ++ } ++ /* ++ * For basic encryption use the zero pad algorithm. ++ * This pads results to an 8-byte boundary and ++ * suppresses padding verification for inbound (i.e. ++ * decrypt) operations. ++ * ++ * NB: Not sure if the 8-byte pad boundary is a problem. ++ */ ++ cmd0 |= SAFE_SA_CMD0_PAD_ZERO; ++ ++ /* XXX assert key bufs have the same size */ ++ bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key)); ++ } ++ ++ if (maccrd) { ++ if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ safe_setup_mackey(ses, maccrd->crd_alg, ++ maccrd->crd_key, maccrd->crd_klen / 8); ++ } ++ ++ if (maccrd->crd_alg == CRYPTO_MD5_HMAC) { ++ cmd0 |= SAFE_SA_CMD0_MD5; ++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ ++ } else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) { ++ cmd0 |= SAFE_SA_CMD0_SHA1; ++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ ++ } else { ++ cmd0 |= SAFE_SA_CMD0_HASH_NULL; ++ } ++ /* ++ * Digest data is loaded from the SA and the hash ++ * result is saved to the state block where we ++ * retrieve it for return to the caller. ++ */ ++ /* XXX assert digest bufs have the same size */ ++ bcopy(ses->ses_hminner, sa->sa_indigest, ++ sizeof(sa->sa_indigest)); ++ bcopy(ses->ses_hmouter, sa->sa_outdigest, ++ sizeof(sa->sa_outdigest)); ++ ++ cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH; ++ re->re_flags |= SAFE_QFLAGS_COPYOUTICV; ++ } ++ ++ if (enccrd && maccrd) { ++ /* ++ * The offset from hash data to the start of ++ * crypt data is the difference in the skips. ++ */ ++ bypass = maccrd->crd_skip; ++ coffset = enccrd->crd_skip - maccrd->crd_skip; ++ if (coffset < 0) { ++ DPRINTF(("%s: hash does not precede crypt; " ++ "mac skip %u enc skip %u\n", ++ __func__, maccrd->crd_skip, enccrd->crd_skip)); ++ safestats.st_skipmismatch++; ++ err = EINVAL; ++ goto errout; ++ } ++ oplen = enccrd->crd_skip + enccrd->crd_len; ++ if (maccrd->crd_skip + maccrd->crd_len != oplen) { ++ DPRINTF(("%s: hash amount %u != crypt amount %u\n", ++ __func__, maccrd->crd_skip + maccrd->crd_len, ++ oplen)); ++ safestats.st_lenmismatch++; ++ err = EINVAL; ++ goto errout; ++ } ++#ifdef SAFE_DEBUG ++ if (debug) { ++ printf("mac: skip %d, len %d, inject %d\n", ++ maccrd->crd_skip, maccrd->crd_len, ++ maccrd->crd_inject); ++ printf("enc: skip %d, len %d, inject %d\n", ++ enccrd->crd_skip, enccrd->crd_len, ++ enccrd->crd_inject); ++ printf("bypass %d coffset %d oplen %d\n", ++ bypass, coffset, oplen); ++ } ++#endif ++ if (coffset & 3) { /* offset must be 32-bit aligned */ ++ DPRINTF(("%s: coffset %u misaligned\n", ++ __func__, coffset)); ++ safestats.st_coffmisaligned++; ++ err = EINVAL; ++ goto errout; ++ } ++ coffset >>= 2; ++ if (coffset > 255) { /* offset must be <256 dwords */ ++ DPRINTF(("%s: coffset %u too big\n", ++ __func__, coffset)); ++ safestats.st_cofftoobig++; ++ err = EINVAL; ++ goto errout; ++ } ++ /* ++ * Tell the hardware to copy the header to the output. ++ * The header is defined as the data from the end of ++ * the bypass to the start of data to be encrypted. ++ * Typically this is the inline IV. Note that you need ++ * to do this even if src+dst are the same; it appears ++ * that w/o this bit the crypted data is written ++ * immediately after the bypass data. ++ */ ++ cmd1 |= SAFE_SA_CMD1_HDRCOPY; ++ /* ++ * Disable IP header mutable bit handling. This is ++ * needed to get correct HMAC calculations. ++ */ ++ cmd1 |= SAFE_SA_CMD1_MUTABLE; ++ } else { ++ if (enccrd) { ++ bypass = enccrd->crd_skip; ++ oplen = bypass + enccrd->crd_len; ++ } else { ++ bypass = maccrd->crd_skip; ++ oplen = bypass + maccrd->crd_len; ++ } ++ coffset = 0; ++ } ++ /* XXX verify multiple of 4 when using s/g */ ++ if (bypass > 96) { /* bypass offset must be <= 96 bytes */ ++ DPRINTF(("%s: bypass %u too big\n", __func__, bypass)); ++ safestats.st_bypasstoobig++; ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &re->re_src, re->re_src_skb)) { ++ safestats.st_noload++; ++ err = ENOMEM; ++ goto errout; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &re->re_src, re->re_src_io)) { ++ safestats.st_noload++; ++ err = ENOMEM; ++ goto errout; ++ } ++ } ++ nicealign = safe_dmamap_aligned(sc, &re->re_src); ++ uniform = safe_dmamap_uniform(sc, &re->re_src); ++ ++ DPRINTF(("src nicealign %u uniform %u nsegs %u\n", ++ nicealign, uniform, re->re_src.nsegs)); ++ if (re->re_src.nsegs > 1) { ++ re->re_desc.d_src = sc->sc_spalloc.dma_paddr + ++ ((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring); ++ for (i = 0; i < re->re_src_nsegs; i++) { ++ /* NB: no need to check if there's space */ ++ pd = sc->sc_spfree; ++ if (++(sc->sc_spfree) == sc->sc_springtop) ++ sc->sc_spfree = sc->sc_spring; ++ ++ KASSERT((pd->pd_flags&3) == 0 || ++ (pd->pd_flags&3) == SAFE_PD_DONE, ++ ("bogus source particle descriptor; flags %x", ++ pd->pd_flags)); ++ pd->pd_addr = re->re_src_segs[i].ds_addr; ++ pd->pd_size = re->re_src_segs[i].ds_len; ++ pd->pd_flags = SAFE_PD_READY; ++ } ++ cmd0 |= SAFE_SA_CMD0_IGATHER; ++ } else { ++ /* ++ * No need for gather, reference the operand directly. ++ */ ++ re->re_desc.d_src = re->re_src_segs[0].ds_addr; ++ } ++ ++ if (enccrd == NULL && maccrd != NULL) { ++ /* ++ * Hash op; no destination needed. ++ */ ++ } else { ++ if (crp->crp_flags & (CRYPTO_F_IOV|CRYPTO_F_SKBUF)) { ++ if (!nicealign) { ++ safestats.st_iovmisaligned++; ++ err = EINVAL; ++ goto errout; ++ } ++ if (uniform != 1) { ++ device_printf(sc->sc_dev, "!uniform source\n"); ++ if (!uniform) { ++ /* ++ * There's no way to handle the DMA ++ * requirements with this uio. We ++ * could create a separate DMA area for ++ * the result and then copy it back, ++ * but for now we just bail and return ++ * an error. Note that uio requests ++ * > SAFE_MAX_DSIZE are handled because ++ * the DMA map and segment list for the ++ * destination wil result in a ++ * destination particle list that does ++ * the necessary scatter DMA. ++ */ ++ safestats.st_iovnotuniform++; ++ err = EINVAL; ++ goto errout; ++ } ++ } else ++ re->re_dst = re->re_src; ++ } else { ++ safestats.st_badflags++; ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (re->re_dst.nsegs > 1) { ++ re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr + ++ ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring); ++ for (i = 0; i < re->re_dst_nsegs; i++) { ++ pd = sc->sc_dpfree; ++ KASSERT((pd->pd_flags&3) == 0 || ++ (pd->pd_flags&3) == SAFE_PD_DONE, ++ ("bogus dest particle descriptor; flags %x", ++ pd->pd_flags)); ++ if (++(sc->sc_dpfree) == sc->sc_dpringtop) ++ sc->sc_dpfree = sc->sc_dpring; ++ pd->pd_addr = re->re_dst_segs[i].ds_addr; ++ pd->pd_flags = SAFE_PD_READY; ++ } ++ cmd0 |= SAFE_SA_CMD0_OSCATTER; ++ } else { ++ /* ++ * No need for scatter, reference the operand directly. ++ */ ++ re->re_desc.d_dst = re->re_dst_segs[0].ds_addr; ++ } ++ } ++ ++ /* ++ * All done with setup; fillin the SA command words ++ * and the packet engine descriptor. The operation ++ * is now ready for submission to the hardware. ++ */ ++ sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI; ++ sa->sa_cmd1 = cmd1 ++ | (coffset << SAFE_SA_CMD1_OFFSET_S) ++ | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */ ++ | SAFE_SA_CMD1_SRPCI ++ ; ++ /* ++ * NB: the order of writes is important here. In case the ++ * chip is scanning the ring because of an outstanding request ++ * it might nab this one too. In that case we need to make ++ * sure the setup is complete before we write the length ++ * field of the descriptor as it signals the descriptor is ++ * ready for processing. ++ */ ++ re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI; ++ if (maccrd) ++ re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL; ++ wmb(); ++ re->re_desc.d_len = oplen ++ | SAFE_PE_LEN_READY ++ | (bypass << SAFE_PE_LEN_BYPASS_S) ++ ; ++ ++ safestats.st_ipackets++; ++ safestats.st_ibytes += oplen; ++ ++ if (++(sc->sc_front) == sc->sc_ringtop) ++ sc->sc_front = sc->sc_ring; ++ ++ /* XXX honor batching */ ++ safe_feed(sc, re); ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ return (0); ++ ++errout: ++ if (re->re_src.map != re->re_dst.map) ++ pci_unmap_operand(sc, &re->re_dst); ++ if (re->re_src.map) ++ pci_unmap_operand(sc, &re->re_src); ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } else { ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ } ++ return (err); ++} ++ ++static void ++safe_callback(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ struct cryptop *crp = (struct cryptop *)re->re_crp; ++ struct cryptodesc *crd; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safestats.st_opackets++; ++ safestats.st_obytes += re->re_dst.mapsize; ++ ++ if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) { ++ device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n", ++ re->re_desc.d_csr, ++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1); ++ safestats.st_peoperr++; ++ crp->crp_etype = EIO; /* something more meaningful? */ ++ } ++ ++ if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map) ++ pci_unmap_operand(sc, &re->re_dst); ++ pci_unmap_operand(sc, &re->re_src); ++ ++ /* ++ * If result was written to a differet mbuf chain, swap ++ * it in as the return value and reclaim the original. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_SKBUF) && re->re_src_skb != re->re_dst_skb) { ++ device_printf(sc->sc_dev, "no CRYPTO_F_SKBUF swapping support\n"); ++ /* kfree_skb(skb) */ ++ /* crp->crp_buf = (caddr_t)re->re_dst_skb */ ++ return; ++ } ++ ++ if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) { ++ /* copy out IV for future use */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ int i; ++ int ivsize; ++ ++ if (crd->crd_alg == CRYPTO_DES_CBC || ++ crd->crd_alg == CRYPTO_3DES_CBC) { ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (crd->crd_alg == CRYPTO_AES_CBC) { ++ ivsize = 4*sizeof(u_int32_t); ++ } else ++ continue; ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_skip + crd->crd_len - ivsize, ivsize, ++ (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv); ++ for (i = 0; ++ i < ivsize/sizeof(sc->sc_sessions[re->re_sesn].ses_iv[0]); ++ i++) ++ sc->sc_sessions[re->re_sesn].ses_iv[i] = ++ cpu_to_le32(sc->sc_sessions[re->re_sesn].ses_iv[i]); ++ break; ++ } ++ } ++ ++ if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) { ++ /* copy out ICV result */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ if (!(crd->crd_alg == CRYPTO_MD5_HMAC || ++ crd->crd_alg == CRYPTO_SHA1_HMAC || ++ crd->crd_alg == CRYPTO_NULL_HMAC)) ++ continue; ++ if (crd->crd_alg == CRYPTO_SHA1_HMAC) { ++ /* ++ * SHA-1 ICV's are byte-swapped; fix 'em up ++ * before copy them to their destination. ++ */ ++ re->re_sastate.sa_saved_indigest[0] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[0]); ++ re->re_sastate.sa_saved_indigest[1] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[1]); ++ re->re_sastate.sa_saved_indigest[2] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[2]); ++ } else { ++ re->re_sastate.sa_saved_indigest[0] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[0]); ++ re->re_sastate.sa_saved_indigest[1] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[1]); ++ re->re_sastate.sa_saved_indigest[2] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[2]); ++ } ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ++ sc->sc_sessions[re->re_sesn].ses_mlen, ++ (caddr_t)re->re_sastate.sa_saved_indigest); ++ break; ++ } ++ } ++ crypto_done(crp); ++} ++ ++ ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++#define SAFE_RNG_MAXWAIT 1000 ++ ++static void ++safe_rng_init(struct safe_softc *sc) ++{ ++ u_int32_t w, v; ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, 0); ++ /* use default value according to the manual */ ++ WRITE_REG(sc, SAFE_RNG_CNFG, 0x834); /* magic from SafeNet */ ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ /* ++ * There is a bug in rev 1.0 of the 1140 that when the RNG ++ * is brought out of reset the ready status flag does not ++ * work until the RNG has finished its internal initialization. ++ * ++ * So in order to determine the device is through its ++ * initialization we must read the data register, using the ++ * status reg in the read in case it is initialized. Then read ++ * the data register until it changes from the first read. ++ * Once it changes read the data register until it changes ++ * again. At this time the RNG is considered initialized. ++ * This could take between 750ms - 1000ms in time. ++ */ ++ i = 0; ++ w = READ_REG(sc, SAFE_RNG_OUT); ++ do { ++ v = READ_REG(sc, SAFE_RNG_OUT); ++ if (v != w) { ++ w = v; ++ break; ++ } ++ DELAY(10); ++ } while (++i < SAFE_RNG_MAXWAIT); ++ ++ /* Wait Until data changes again */ ++ i = 0; ++ do { ++ v = READ_REG(sc, SAFE_RNG_OUT); ++ if (v != w) ++ break; ++ DELAY(10); ++ } while (++i < SAFE_RNG_MAXWAIT); ++} ++ ++static __inline void ++safe_rng_disable_short_cycle(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, ++ READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN); ++} ++ ++static __inline void ++safe_rng_enable_short_cycle(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, ++ READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN); ++} ++ ++static __inline u_int32_t ++safe_rng_read(struct safe_softc *sc) ++{ ++ int i; ++ ++ i = 0; ++ while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT) ++ ; ++ return READ_REG(sc, SAFE_RNG_OUT); ++} ++ ++static int ++safe_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ struct safe_softc *sc = (struct safe_softc *) arg; ++ int i, rc; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safestats.st_rng++; ++ /* ++ * Fetch the next block of data. ++ */ ++ if (maxwords > safe_rngbufsize) ++ maxwords = safe_rngbufsize; ++ if (maxwords > SAFE_RNG_MAXBUFSIZ) ++ maxwords = SAFE_RNG_MAXBUFSIZ; ++retry: ++ /* read as much as we can */ ++ for (rc = 0; rc < maxwords; rc++) { ++ if (READ_REG(sc, SAFE_RNG_STAT) != 0) ++ break; ++ buf[rc] = READ_REG(sc, SAFE_RNG_OUT); ++ } ++ if (rc == 0) ++ return 0; ++ /* ++ * Check the comparator alarm count and reset the h/w if ++ * it exceeds our threshold. This guards against the ++ * hardware oscillators resonating with external signals. ++ */ ++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) { ++ u_int32_t freq_inc, w; ++ ++ DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__, ++ (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm)); ++ safestats.st_rngalarm++; ++ safe_rng_enable_short_cycle(sc); ++ freq_inc = 18; ++ for (i = 0; i < 64; i++) { ++ w = READ_REG(sc, SAFE_RNG_CNFG); ++ freq_inc = ((w + freq_inc) & 0x3fL); ++ w = ((w & ~0x3fL) | freq_inc); ++ WRITE_REG(sc, SAFE_RNG_CNFG, w); ++ ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ (void) safe_rng_read(sc); ++ DELAY(25); ++ ++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) { ++ safe_rng_disable_short_cycle(sc); ++ goto retry; ++ } ++ freq_inc = 1; ++ } ++ safe_rng_disable_short_cycle(sc); ++ } else ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ return(rc); ++} ++#endif /* defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) */ ++ ++ ++/* ++ * Resets the board. Values in the regesters are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++safe_reset_board(struct safe_softc *sc) ++{ ++ u_int32_t v; ++ /* ++ * Reset the device. The manual says no delay ++ * is needed between marking and clearing reset. ++ */ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ v = READ_REG(sc, SAFE_PE_DMACFG) &~ ++ (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET | ++ SAFE_PE_DMACFG_SGRESET); ++ WRITE_REG(sc, SAFE_PE_DMACFG, v ++ | SAFE_PE_DMACFG_PERESET ++ | SAFE_PE_DMACFG_PDRRESET ++ | SAFE_PE_DMACFG_SGRESET); ++ WRITE_REG(sc, SAFE_PE_DMACFG, v); ++} ++ ++/* ++ * Initialize registers we need to touch only once. ++ */ ++static void ++safe_init_board(struct safe_softc *sc) ++{ ++ u_int32_t v, dwords; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ v = READ_REG(sc, SAFE_PE_DMACFG); ++ v &=~ ( SAFE_PE_DMACFG_PEMODE ++ | SAFE_PE_DMACFG_FSENA /* failsafe enable */ ++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ ++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ ++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ ++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ ++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ ++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ ++ ); ++ v |= SAFE_PE_DMACFG_FSENA /* failsafe enable */ ++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ ++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ ++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ ++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ ++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ ++#if 0 ++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ ++#endif ++ ; ++ WRITE_REG(sc, SAFE_PE_DMACFG, v); ++ ++#ifdef __BIG_ENDIAN ++ /* tell the safenet that we are 4321 and not 1234 */ ++ WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b); ++#endif ++ ++ if (sc->sc_chiprev == SAFE_REV(1,0)) { ++ /* ++ * Avoid large PCI DMA transfers. Rev 1.0 has a bug where ++ * "target mode transfers" done while the chip is DMA'ing ++ * >1020 bytes cause the hardware to lockup. To avoid this ++ * we reduce the max PCI transfer size and use small source ++ * particle descriptors (<= 256 bytes). ++ */ ++ WRITE_REG(sc, SAFE_DMA_CFG, 256); ++ device_printf(sc->sc_dev, ++ "Reduce max DMA size to %u words for rev %u.%u WAR\n", ++ (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff), ++ (unsigned) SAFE_REV_MAJ(sc->sc_chiprev), ++ (unsigned) SAFE_REV_MIN(sc->sc_chiprev)); ++ sc->sc_max_dsize = 256; ++ } else { ++ sc->sc_max_dsize = SAFE_MAX_DSIZE; ++ } ++ ++ /* NB: operands+results are overlaid */ ++ WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr); ++ /* ++ * Configure ring entry size and number of items in the ring. ++ */ ++ KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0, ++ ("PE ring entry not 32-bit aligned!")); ++ dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t); ++ WRITE_REG(sc, SAFE_PE_RINGCFG, ++ (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE); ++ WRITE_REG(sc, SAFE_PE_RINGPOLL, 0); /* disable polling */ ++ ++ WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_PARTSIZE, ++ (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART); ++ /* ++ * NB: destination particles are fixed size. We use ++ * an mbuf cluster and require all results go to ++ * clusters or smaller. ++ */ ++ WRITE_REG(sc, SAFE_PE_PARTCFG, sc->sc_max_dsize); ++ ++ /* it's now safe to enable PE mode, do it */ ++ WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE); ++ ++ /* ++ * Configure hardware to use level-triggered interrupts and ++ * to interrupt after each descriptor is processed. ++ */ ++ WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL); ++ WRITE_REG(sc, SAFE_HI_CLR, 0xffffffff); ++ WRITE_REG(sc, SAFE_HI_DESC_CNT, 1); ++ WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR); ++} ++ ++ ++/* ++ * Clean up after a chip crash. ++ * It is assumed that the caller in splimp() ++ */ ++static void ++safe_cleanchip(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc->sc_nqchip != 0) { ++ struct safe_ringentry *re = sc->sc_back; ++ ++ while (re != sc->sc_front) { ++ if (re->re_desc.d_csr != 0) ++ safe_free_entry(sc, re); ++ if (++re == sc->sc_ringtop) ++ re = sc->sc_ring; ++ } ++ sc->sc_back = re; ++ sc->sc_nqchip = 0; ++ } ++} ++ ++/* ++ * free a safe_q ++ * It is assumed that the caller is within splimp(). ++ */ ++static int ++safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ struct cryptop *crp; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ /* ++ * Free header MCR ++ */ ++ if ((re->re_dst_skb != NULL) && (re->re_src_skb != re->re_dst_skb)) ++#ifdef NOTYET ++ m_freem(re->re_dst_m); ++#else ++ printk("%s,%d: SKB not supported\n", __FILE__, __LINE__); ++#endif ++ ++ crp = (struct cryptop *)re->re_crp; ++ ++ re->re_desc.d_csr = 0; ++ ++ crp->crp_etype = EFAULT; ++ crypto_done(crp); ++ return(0); ++} ++ ++/* ++ * Routine to reset the chip and clean up. ++ * It is assumed that the caller is in splimp() ++ */ ++static void ++safe_totalreset(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safe_reset_board(sc); ++ safe_init_board(sc); ++ safe_cleanchip(sc); ++} ++ ++/* ++ * Is the operand suitable aligned for direct DMA. Each ++ * segment must be aligned on a 32-bit boundary and all ++ * but the last segment must be a multiple of 4 bytes. ++ */ ++static int ++safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ for (i = 0; i < op->nsegs; i++) { ++ if (op->segs[i].ds_addr & 3) ++ return (0); ++ if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3)) ++ return (0); ++ } ++ return (1); ++} ++ ++/* ++ * Is the operand suitable for direct DMA as the destination ++ * of an operation. The hardware requires that each ``particle'' ++ * but the last in an operation result have the same size. We ++ * fix that size at SAFE_MAX_DSIZE bytes. This routine returns ++ * 0 if some segment is not a multiple of of this size, 1 if all ++ * segments are exactly this size, or 2 if segments are at worst ++ * a multple of this size. ++ */ ++static int ++safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op) ++{ ++ int result = 1; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (op->nsegs > 0) { ++ int i; ++ ++ for (i = 0; i < op->nsegs-1; i++) { ++ if (op->segs[i].ds_len % sc->sc_max_dsize) ++ return (0); ++ if (op->segs[i].ds_len != sc->sc_max_dsize) ++ result = 2; ++ } ++ } ++ return (result); ++} ++ ++static int ++safe_kprocess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ struct safe_pkq *q; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc == NULL) { ++ krp->krp_status = EINVAL; ++ goto err; ++ } ++ ++ if (krp->krp_op != CRK_MOD_EXP) { ++ krp->krp_status = EOPNOTSUPP; ++ goto err; ++ } ++ ++ q = (struct safe_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); ++ if (q == NULL) { ++ krp->krp_status = ENOMEM; ++ goto err; ++ } ++ memset(q, 0, sizeof(*q)); ++ q->pkq_krp = krp; ++ INIT_LIST_HEAD(&q->pkq_list); ++ ++ spin_lock_irqsave(&sc->sc_pkmtx, flags); ++ list_add_tail(&q->pkq_list, &sc->sc_pkq); ++ safe_kfeed(sc); ++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags); ++ return (0); ++ ++err: ++ crypto_kdone(krp); ++ return (0); ++} ++ ++#define SAFE_CRK_PARAM_BASE 0 ++#define SAFE_CRK_PARAM_EXP 1 ++#define SAFE_CRK_PARAM_MOD 2 ++ ++static int ++safe_kstart(struct safe_softc *sc) ++{ ++ struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp; ++ int exp_bits, mod_bits, base_bits; ++ u_int32_t op, a_off, b_off, c_off, d_off; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (krp->krp_iparams < 3 || krp->krp_oparams != 1) { ++ krp->krp_status = EINVAL; ++ return (1); ++ } ++ ++ base_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_BASE]); ++ if (base_bits > 2048) ++ goto too_big; ++ if (base_bits <= 0) /* 5. base not zero */ ++ goto too_small; ++ ++ exp_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_EXP]); ++ if (exp_bits > 2048) ++ goto too_big; ++ if (exp_bits <= 0) /* 1. exponent word length > 0 */ ++ goto too_small; /* 4. exponent not zero */ ++ ++ mod_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_MOD]); ++ if (mod_bits > 2048) ++ goto too_big; ++ if (mod_bits <= 32) /* 2. modulus word length > 1 */ ++ goto too_small; /* 8. MSW of modulus != zero */ ++ if (mod_bits < exp_bits) /* 3 modulus len >= exponent len */ ++ goto too_small; ++ if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0) ++ goto bad_domain; /* 6. modulus is odd */ ++ if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits) ++ goto too_small; /* make sure result will fit */ ++ ++ /* 7. modulus > base */ ++ if (mod_bits < base_bits) ++ goto too_small; ++ if (mod_bits == base_bits) { ++ u_int8_t *basep, *modp; ++ int i; ++ ++ basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p + ++ ((base_bits + 7) / 8) - 1; ++ modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p + ++ ((mod_bits + 7) / 8) - 1; ++ ++ for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) { ++ if (*modp < *basep) ++ goto too_small; ++ if (*modp > *basep) ++ break; ++ } ++ } ++ ++ /* And on the 9th step, he rested. */ ++ ++ WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32); ++ WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32); ++ if (mod_bits > 1024) { ++ op = SAFE_PK_FUNC_EXP4; ++ a_off = 0x000; ++ b_off = 0x100; ++ c_off = 0x200; ++ d_off = 0x300; ++ } else { ++ op = SAFE_PK_FUNC_EXP16; ++ a_off = 0x000; ++ b_off = 0x080; ++ c_off = 0x100; ++ d_off = 0x180; ++ } ++ sc->sc_pk_reslen = b_off - a_off; ++ sc->sc_pk_resoff = d_off; ++ ++ /* A is exponent, B is modulus, C is base, D is result */ ++ safe_kload_reg(sc, a_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_EXP]); ++ WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2); ++ safe_kload_reg(sc, b_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_MOD]); ++ WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2); ++ safe_kload_reg(sc, c_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_BASE]); ++ WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2); ++ WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2); ++ ++ WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN); ++ ++ return (0); ++ ++too_big: ++ krp->krp_status = E2BIG; ++ return (1); ++too_small: ++ krp->krp_status = ERANGE; ++ return (1); ++bad_domain: ++ krp->krp_status = EDOM; ++ return (1); ++} ++ ++static int ++safe_ksigbits(struct safe_softc *sc, struct crparam *cr) ++{ ++ u_int plen = (cr->crp_nbits + 7) / 8; ++ int i, sig = plen * 8; ++ u_int8_t c, *p = cr->crp_p; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ for (i = plen - 1; i >= 0; i--) { ++ c = p[i]; ++ if (c != 0) { ++ while ((c & 0x80) == 0) { ++ sig--; ++ c <<= 1; ++ } ++ break; ++ } ++ sig -= 8; ++ } ++ return (sig); ++} ++ ++static void ++safe_kfeed(struct safe_softc *sc) ++{ ++ struct safe_pkq *q, *tmp; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (list_empty(&sc->sc_pkq) && sc->sc_pkq_cur == NULL) ++ return; ++ if (sc->sc_pkq_cur != NULL) ++ return; ++ list_for_each_entry_safe(q, tmp, &sc->sc_pkq, pkq_list) { ++ sc->sc_pkq_cur = q; ++ list_del(&q->pkq_list); ++ if (safe_kstart(sc) != 0) { ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ sc->sc_pkq_cur = NULL; ++ } else { ++ /* op started, start polling */ ++ mod_timer(&sc->sc_pkto, jiffies + 1); ++ break; ++ } ++ } ++} ++ ++static void ++safe_kpoll(unsigned long arg) ++{ ++ struct safe_softc *sc = NULL; ++ struct safe_pkq *q; ++ struct crparam *res; ++ int i; ++ u_int32_t buf[64]; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (arg >= SAFE_MAX_CHIPS) ++ return; ++ sc = safe_chip_idx[arg]; ++ if (!sc) { ++ DPRINTF(("%s() - bad callback\n", __FUNCTION__)); ++ return; ++ } ++ ++ spin_lock_irqsave(&sc->sc_pkmtx, flags); ++ if (sc->sc_pkq_cur == NULL) ++ goto out; ++ if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) { ++ /* still running, check back later */ ++ mod_timer(&sc->sc_pkto, jiffies + 1); ++ goto out; ++ } ++ ++ q = sc->sc_pkq_cur; ++ res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams]; ++ bzero(buf, sizeof(buf)); ++ bzero(res->crp_p, (res->crp_nbits + 7) / 8); ++ for (i = 0; i < sc->sc_pk_reslen >> 2; i++) ++ buf[i] = le32_to_cpu(READ_REG(sc, SAFE_PK_RAM_START + ++ sc->sc_pk_resoff + (i << 2))); ++ bcopy(buf, res->crp_p, (res->crp_nbits + 7) / 8); ++ /* ++ * reduce the bits that need copying if possible ++ */ ++ res->crp_nbits = min(res->crp_nbits,sc->sc_pk_reslen * 8); ++ res->crp_nbits = safe_ksigbits(sc, res); ++ ++ for (i = SAFE_PK_RAM_START; i < SAFE_PK_RAM_END; i += 4) ++ WRITE_REG(sc, i, 0); ++ ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ sc->sc_pkq_cur = NULL; ++ ++ safe_kfeed(sc); ++out: ++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags); ++} ++ ++static void ++safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len, ++ struct crparam *n) ++{ ++ u_int32_t buf[64], i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ bzero(buf, sizeof(buf)); ++ bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8); ++ ++ for (i = 0; i < len >> 2; i++) ++ WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2), ++ cpu_to_le32(buf[i])); ++} ++ ++#ifdef SAFE_DEBUG ++static void ++safe_dump_dmastatus(struct safe_softc *sc, const char *tag) ++{ ++ printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n" ++ , tag ++ , READ_REG(sc, SAFE_DMA_ENDIAN) ++ , READ_REG(sc, SAFE_DMA_SRCADDR) ++ , READ_REG(sc, SAFE_DMA_DSTADDR) ++ , READ_REG(sc, SAFE_DMA_STAT) ++ ); ++} ++ ++static void ++safe_dump_intrstate(struct safe_softc *sc, const char *tag) ++{ ++ printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n" ++ , tag ++ , READ_REG(sc, SAFE_HI_CFG) ++ , READ_REG(sc, SAFE_HI_MASK) ++ , READ_REG(sc, SAFE_HI_DESC_CNT) ++ , READ_REG(sc, SAFE_HU_STAT) ++ , READ_REG(sc, SAFE_HM_STAT) ++ ); ++} ++ ++static void ++safe_dump_ringstate(struct safe_softc *sc, const char *tag) ++{ ++ u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT); ++ ++ /* NB: assume caller has lock on ring */ ++ printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n", ++ tag, ++ estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S), ++ (unsigned long)(sc->sc_back - sc->sc_ring), ++ (unsigned long)(sc->sc_front - sc->sc_ring)); ++} ++ ++static void ++safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re) ++{ ++ int ix, nsegs; ++ ++ ix = re - sc->sc_ring; ++ printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n" ++ , tag ++ , re, ix ++ , re->re_desc.d_csr ++ , re->re_desc.d_src ++ , re->re_desc.d_dst ++ , re->re_desc.d_sa ++ , re->re_desc.d_len ++ ); ++ if (re->re_src.nsegs > 1) { ++ ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) / ++ sizeof(struct safe_pdesc); ++ for (nsegs = re->re_src.nsegs; nsegs; nsegs--) { ++ printf(" spd[%u] %p: %p size %u flags %x" ++ , ix, &sc->sc_spring[ix] ++ , (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr ++ , sc->sc_spring[ix].pd_size ++ , sc->sc_spring[ix].pd_flags ++ ); ++ if (sc->sc_spring[ix].pd_size == 0) ++ printf(" (zero!)"); ++ printf("\n"); ++ if (++ix == SAFE_TOTAL_SPART) ++ ix = 0; ++ } ++ } ++ if (re->re_dst.nsegs > 1) { ++ ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) / ++ sizeof(struct safe_pdesc); ++ for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) { ++ printf(" dpd[%u] %p: %p flags %x\n" ++ , ix, &sc->sc_dpring[ix] ++ , (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr ++ , sc->sc_dpring[ix].pd_flags ++ ); ++ if (++ix == SAFE_TOTAL_DPART) ++ ix = 0; ++ } ++ } ++ printf("sa: cmd0 %08x cmd1 %08x staterec %x\n", ++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec); ++ printf("sa: key %x %x %x %x %x %x %x %x\n" ++ , re->re_sa.sa_key[0] ++ , re->re_sa.sa_key[1] ++ , re->re_sa.sa_key[2] ++ , re->re_sa.sa_key[3] ++ , re->re_sa.sa_key[4] ++ , re->re_sa.sa_key[5] ++ , re->re_sa.sa_key[6] ++ , re->re_sa.sa_key[7] ++ ); ++ printf("sa: indigest %x %x %x %x %x\n" ++ , re->re_sa.sa_indigest[0] ++ , re->re_sa.sa_indigest[1] ++ , re->re_sa.sa_indigest[2] ++ , re->re_sa.sa_indigest[3] ++ , re->re_sa.sa_indigest[4] ++ ); ++ printf("sa: outdigest %x %x %x %x %x\n" ++ , re->re_sa.sa_outdigest[0] ++ , re->re_sa.sa_outdigest[1] ++ , re->re_sa.sa_outdigest[2] ++ , re->re_sa.sa_outdigest[3] ++ , re->re_sa.sa_outdigest[4] ++ ); ++ printf("sr: iv %x %x %x %x\n" ++ , re->re_sastate.sa_saved_iv[0] ++ , re->re_sastate.sa_saved_iv[1] ++ , re->re_sastate.sa_saved_iv[2] ++ , re->re_sastate.sa_saved_iv[3] ++ ); ++ printf("sr: hashbc %u indigest %x %x %x %x %x\n" ++ , re->re_sastate.sa_saved_hashbc ++ , re->re_sastate.sa_saved_indigest[0] ++ , re->re_sastate.sa_saved_indigest[1] ++ , re->re_sastate.sa_saved_indigest[2] ++ , re->re_sastate.sa_saved_indigest[3] ++ , re->re_sastate.sa_saved_indigest[4] ++ ); ++} ++ ++static void ++safe_dump_ring(struct safe_softc *sc, const char *tag) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ printf("\nSafeNet Ring State:\n"); ++ safe_dump_intrstate(sc, tag); ++ safe_dump_dmastatus(sc, tag); ++ safe_dump_ringstate(sc, tag); ++ if (sc->sc_nqchip) { ++ struct safe_ringentry *re = sc->sc_back; ++ do { ++ safe_dump_request(sc, tag, re); ++ if (++re == sc->sc_ringtop) ++ re = sc->sc_ring; ++ } while (re != sc->sc_front); ++ } ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++} ++#endif /* SAFE_DEBUG */ ++ ++ ++static int safe_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct safe_softc *sc = NULL; ++ u32 mem_start, mem_len, cmd; ++ int i, rc, devinfo; ++ dma_addr_t raddr; ++ static int num_chips = 0; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("safe: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ if (pci_set_mwi(dev)) { ++ printk("safe: pci_set_mwi failed!"); ++ return(-ENODEV); ++ } ++ ++ sc = (struct safe_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "safe", num_chips, safe_methods); ++ ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_pcidev = dev; ++ if (num_chips < SAFE_MAX_CHIPS) { ++ safe_chip_idx[device_get_unit(sc->sc_dev)] = sc; ++ num_chips++; ++ } ++ ++ INIT_LIST_HEAD(&sc->sc_pkq); ++ spin_lock_init(&sc->sc_pkmtx); ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ /* we read its hardware registers as memory */ ++ mem_start = pci_resource_start(sc->sc_pcidev, 0); ++ mem_len = pci_resource_len(sc->sc_pcidev, 0); ++ ++ sc->sc_base_addr = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_base_addr) { ++ device_printf(sc->sc_dev, "failed to ioremap 0x%x-0x%x\n", ++ mem_start, mem_start + mem_len - 1); ++ goto out; ++ } ++ ++ /* fix up the bus size */ ++ if (pci_set_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); ++ goto out; ++ } ++ if (pci_set_consistent_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable consistent DMA configuration, aborting.\n"); ++ goto out; ++ } ++ ++ pci_set_master(sc->sc_pcidev); ++ ++ pci_read_config_dword(sc->sc_pcidev, PCI_COMMAND, &cmd); ++ ++ if (!(cmd & PCI_COMMAND_MEMORY)) { ++ device_printf(sc->sc_dev, "failed to enable memory mapping\n"); ++ goto out; ++ } ++ ++ if (!(cmd & PCI_COMMAND_MASTER)) { ++ device_printf(sc->sc_dev, "failed to enable bus mastering\n"); ++ goto out; ++ } ++ ++ rc = request_irq(dev->irq, safe_intr, IRQF_SHARED, "safe", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "failed to hook irq %d\n", sc->sc_irq); ++ goto out; ++ } ++ sc->sc_irq = dev->irq; ++ ++ sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) & ++ (SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN); ++ ++ /* ++ * Allocate packet engine descriptors. ++ */ ++ sc->sc_ringalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ &sc->sc_ringalloc.dma_paddr); ++ if (!sc->sc_ringalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate PE descriptor ring\n"); ++ goto out; ++ } ++ ++ /* ++ * Hookup the static portion of all our data structures. ++ */ ++ sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr; ++ sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE; ++ sc->sc_front = sc->sc_ring; ++ sc->sc_back = sc->sc_ring; ++ raddr = sc->sc_ringalloc.dma_paddr; ++ bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry)); ++ for (i = 0; i < SAFE_MAX_NQUEUE; i++) { ++ struct safe_ringentry *re = &sc->sc_ring[i]; ++ ++ re->re_desc.d_sa = raddr + ++ offsetof(struct safe_ringentry, re_sa); ++ re->re_sa.sa_staterec = raddr + ++ offsetof(struct safe_ringentry, re_sastate); ++ ++ raddr += sizeof (struct safe_ringentry); ++ } ++ spin_lock_init(&sc->sc_ringmtx); ++ ++ /* ++ * Allocate scatter and gather particle descriptors. ++ */ ++ sc->sc_spalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_SPART * sizeof (struct safe_pdesc), ++ &sc->sc_spalloc.dma_paddr); ++ if (!sc->sc_spalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate source particle descriptor ring\n"); ++ goto out; ++ } ++ sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr; ++ sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART; ++ sc->sc_spfree = sc->sc_spring; ++ bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc)); ++ ++ sc->sc_dpalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ &sc->sc_dpalloc.dma_paddr); ++ if (!sc->sc_dpalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate destination particle descriptor ring\n"); ++ goto out; ++ } ++ sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr; ++ sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART; ++ sc->sc_dpfree = sc->sc_dpring; ++ bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc)); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto out; ++ } ++ ++ printf("%s:", device_get_nameunit(sc->sc_dev)); ++ ++ devinfo = READ_REG(sc, SAFE_DEVINFO); ++ if (devinfo & SAFE_DEVINFO_RNG) { ++ sc->sc_flags |= SAFE_FLAGS_RNG; ++ printf(" rng"); ++ } ++ if (devinfo & SAFE_DEVINFO_PKEY) { ++ printf(" key"); ++ sc->sc_flags |= SAFE_FLAGS_KEY; ++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0); ++#if 0 ++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0); ++#endif ++ init_timer(&sc->sc_pkto); ++ sc->sc_pkto.function = safe_kpoll; ++ sc->sc_pkto.data = (unsigned long) device_get_unit(sc->sc_dev); ++ } ++ if (devinfo & SAFE_DEVINFO_DES) { ++ printf(" des/3des"); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_AES) { ++ printf(" aes"); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_MD5) { ++ printf(" md5"); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_SHA1) { ++ printf(" sha1"); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ } ++ printf(" null"); ++ crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0); ++ /* XXX other supported algorithms */ ++ printf("\n"); ++ ++ safe_reset_board(sc); /* reset h/w */ ++ safe_init_board(sc); /* init h/w */ ++ ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++ if (sc->sc_flags & SAFE_FLAGS_RNG) { ++ safe_rng_init(sc); ++ crypto_rregister(sc->sc_cid, safe_read_random, sc); ++ } ++#endif /* SAFE_NO_RNG */ ++ ++ return (0); ++ ++out: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_ringalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); ++ if (sc->sc_spalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); ++ if (sc->sc_dpalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); ++ kfree(sc); ++ return(-ENODEV); ++} ++ ++static void safe_remove(struct pci_dev *dev) ++{ ++ struct safe_softc *sc = pci_get_drvdata(dev); ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ /* XXX wait/abort active ops */ ++ ++ WRITE_REG(sc, SAFE_HI_MASK, 0); /* disable interrupts */ ++ ++ del_timer_sync(&sc->sc_pkto); ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ safe_cleanchip(sc); ++ ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_ringalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); ++ if (sc->sc_spalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); ++ if (sc->sc_dpalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); ++ sc->sc_irq = -1; ++ sc->sc_ringalloc.dma_vaddr = NULL; ++ sc->sc_spalloc.dma_vaddr = NULL; ++ sc->sc_dpalloc.dma_vaddr = NULL; ++} ++ ++static struct pci_device_id safe_pci_tbl[] = { ++ { PCI_VENDOR_SAFENET, PCI_PRODUCT_SAFEXCEL, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(pci, safe_pci_tbl); ++ ++static struct pci_driver safe_driver = { ++ .name = "safe", ++ .id_table = safe_pci_tbl, ++ .probe = safe_probe, ++ .remove = safe_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init safe_init (void) ++{ ++ struct safe_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF(("%s(%p)\n", __FUNCTION__, safe_init)); ++ ++ rc = pci_register_driver(&safe_driver); ++ pci_register_driver_compat(&safe_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit safe_exit (void) ++{ ++ pci_unregister_driver(&safe_driver); ++} ++ ++module_init(safe_init); ++module_exit(safe_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF driver for safenet PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safereg.h linux-2.6.30/crypto/ocf/safe/safereg.h +--- linux-2.6.30.orig/crypto/ocf/safe/safereg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safereg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,421 @@ ++/*- ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * $FreeBSD: src/sys/dev/safe/safereg.h,v 1.1 2003/07/21 21:46:07 sam Exp $ ++ */ ++#ifndef _SAFE_SAFEREG_H_ ++#define _SAFE_SAFEREG_H_ ++ ++/* ++ * Register definitions for SafeNet SafeXcel-1141 crypto device. ++ * Definitions from revision 1.3 (Nov 6 2002) of the User's Manual. ++ */ ++ ++#define BS_BAR 0x10 /* DMA base address register */ ++#define BS_TRDY_TIMEOUT 0x40 /* TRDY timeout */ ++#define BS_RETRY_TIMEOUT 0x41 /* DMA retry timeout */ ++ ++#define PCI_VENDOR_SAFENET 0x16ae /* SafeNet, Inc. */ ++ ++/* SafeNet */ ++#define PCI_PRODUCT_SAFEXCEL 0x1141 /* 1141 */ ++ ++#define SAFE_PE_CSR 0x0000 /* Packet Enginge Ctrl/Status */ ++#define SAFE_PE_SRC 0x0004 /* Packet Engine Source */ ++#define SAFE_PE_DST 0x0008 /* Packet Engine Destination */ ++#define SAFE_PE_SA 0x000c /* Packet Engine SA */ ++#define SAFE_PE_LEN 0x0010 /* Packet Engine Length */ ++#define SAFE_PE_DMACFG 0x0040 /* Packet Engine DMA Configuration */ ++#define SAFE_PE_DMASTAT 0x0044 /* Packet Engine DMA Status */ ++#define SAFE_PE_PDRBASE 0x0048 /* Packet Engine Descriptor Ring Base */ ++#define SAFE_PE_RDRBASE 0x004c /* Packet Engine Result Ring Base */ ++#define SAFE_PE_RINGCFG 0x0050 /* Packet Engine Ring Configuration */ ++#define SAFE_PE_RINGPOLL 0x0054 /* Packet Engine Ring Poll */ ++#define SAFE_PE_IRNGSTAT 0x0058 /* Packet Engine Internal Ring Status */ ++#define SAFE_PE_ERNGSTAT 0x005c /* Packet Engine External Ring Status */ ++#define SAFE_PE_IOTHRESH 0x0060 /* Packet Engine I/O Threshold */ ++#define SAFE_PE_GRNGBASE 0x0064 /* Packet Engine Gather Ring Base */ ++#define SAFE_PE_SRNGBASE 0x0068 /* Packet Engine Scatter Ring Base */ ++#define SAFE_PE_PARTSIZE 0x006c /* Packet Engine Particlar Ring Size */ ++#define SAFE_PE_PARTCFG 0x0070 /* Packet Engine Particle Ring Config */ ++#define SAFE_CRYPTO_CTRL 0x0080 /* Crypto Control */ ++#define SAFE_DEVID 0x0084 /* Device ID */ ++#define SAFE_DEVINFO 0x0088 /* Device Info */ ++#define SAFE_HU_STAT 0x00a0 /* Host Unmasked Status */ ++#define SAFE_HM_STAT 0x00a4 /* Host Masked Status (read-only) */ ++#define SAFE_HI_CLR 0x00a4 /* Host Clear Interrupt (write-only) */ ++#define SAFE_HI_MASK 0x00a8 /* Host Mask Control */ ++#define SAFE_HI_CFG 0x00ac /* Interrupt Configuration */ ++#define SAFE_HI_RD_DESCR 0x00b4 /* Force Descriptor Read */ ++#define SAFE_HI_DESC_CNT 0x00b8 /* Host Descriptor Done Count */ ++#define SAFE_DMA_ENDIAN 0x00c0 /* Master Endian Status */ ++#define SAFE_DMA_SRCADDR 0x00c4 /* DMA Source Address Status */ ++#define SAFE_DMA_DSTADDR 0x00c8 /* DMA Destination Address Status */ ++#define SAFE_DMA_STAT 0x00cc /* DMA Current Status */ ++#define SAFE_DMA_CFG 0x00d4 /* DMA Configuration/Status */ ++#define SAFE_ENDIAN 0x00e0 /* Endian Configuration */ ++#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */ ++#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */ ++#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */ ++#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */ ++#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */ ++#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */ ++#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */ ++#define SAFE_PK_FUNC 0x081c /* Public Key Function */ ++#define SAFE_PK_RAM_START 0x1000 /* Public Key RAM start address */ ++#define SAFE_PK_RAM_END 0x1fff /* Public Key RAM end address */ ++ ++#define SAFE_RNG_OUT 0x0100 /* RNG Output */ ++#define SAFE_RNG_STAT 0x0104 /* RNG Status */ ++#define SAFE_RNG_CTRL 0x0108 /* RNG Control */ ++#define SAFE_RNG_A 0x010c /* RNG A */ ++#define SAFE_RNG_B 0x0110 /* RNG B */ ++#define SAFE_RNG_X_LO 0x0114 /* RNG X [31:0] */ ++#define SAFE_RNG_X_MID 0x0118 /* RNG X [63:32] */ ++#define SAFE_RNG_X_HI 0x011c /* RNG X [80:64] */ ++#define SAFE_RNG_X_CNTR 0x0120 /* RNG Counter */ ++#define SAFE_RNG_ALM_CNT 0x0124 /* RNG Alarm Count */ ++#define SAFE_RNG_CNFG 0x0128 /* RNG Configuration */ ++#define SAFE_RNG_LFSR1_LO 0x012c /* RNG LFSR1 [31:0] */ ++#define SAFE_RNG_LFSR1_HI 0x0130 /* RNG LFSR1 [47:32] */ ++#define SAFE_RNG_LFSR2_LO 0x0134 /* RNG LFSR1 [31:0] */ ++#define SAFE_RNG_LFSR2_HI 0x0138 /* RNG LFSR1 [47:32] */ ++ ++#define SAFE_PE_CSR_READY 0x00000001 /* ready for processing */ ++#define SAFE_PE_CSR_DONE 0x00000002 /* h/w completed processing */ ++#define SAFE_PE_CSR_LOADSA 0x00000004 /* load SA digests */ ++#define SAFE_PE_CSR_HASHFINAL 0x00000010 /* do hash pad & write result */ ++#define SAFE_PE_CSR_SABUSID 0x000000c0 /* bus id for SA */ ++#define SAFE_PE_CSR_SAPCI 0x00000040 /* PCI bus id for SA */ ++#define SAFE_PE_CSR_NXTHDR 0x0000ff00 /* next hdr value for IPsec */ ++#define SAFE_PE_CSR_FPAD 0x0000ff00 /* fixed pad for basic ops */ ++#define SAFE_PE_CSR_STATUS 0x00ff0000 /* operation result status */ ++#define SAFE_PE_CSR_AUTH_FAIL 0x00010000 /* ICV mismatch (inbound) */ ++#define SAFE_PE_CSR_PAD_FAIL 0x00020000 /* pad verify fail (inbound) */ ++#define SAFE_PE_CSR_SEQ_FAIL 0x00040000 /* sequence number (inbound) */ ++#define SAFE_PE_CSR_XERROR 0x00080000 /* extended error follows */ ++#define SAFE_PE_CSR_XECODE 0x00f00000 /* extended error code */ ++#define SAFE_PE_CSR_XECODE_S 20 ++#define SAFE_PE_CSR_XECODE_BADCMD 0 /* invalid command */ ++#define SAFE_PE_CSR_XECODE_BADALG 1 /* invalid algorithm */ ++#define SAFE_PE_CSR_XECODE_ALGDIS 2 /* algorithm disabled */ ++#define SAFE_PE_CSR_XECODE_ZEROLEN 3 /* zero packet length */ ++#define SAFE_PE_CSR_XECODE_DMAERR 4 /* bus DMA error */ ++#define SAFE_PE_CSR_XECODE_PIPEABORT 5 /* secondary bus DMA error */ ++#define SAFE_PE_CSR_XECODE_BADSPI 6 /* IPsec SPI mismatch */ ++#define SAFE_PE_CSR_XECODE_TIMEOUT 10 /* failsafe timeout */ ++#define SAFE_PE_CSR_PAD 0xff000000 /* ESP padding control/status */ ++#define SAFE_PE_CSR_PAD_MIN 0x00000000 /* minimum IPsec padding */ ++#define SAFE_PE_CSR_PAD_16 0x08000000 /* pad to 16-byte boundary */ ++#define SAFE_PE_CSR_PAD_32 0x10000000 /* pad to 32-byte boundary */ ++#define SAFE_PE_CSR_PAD_64 0x20000000 /* pad to 64-byte boundary */ ++#define SAFE_PE_CSR_PAD_128 0x40000000 /* pad to 128-byte boundary */ ++#define SAFE_PE_CSR_PAD_256 0x80000000 /* pad to 256-byte boundary */ ++ ++/* ++ * Check the CSR to see if the PE has returned ownership to ++ * the host. Note that before processing a descriptor this ++ * must be done followed by a check of the SAFE_PE_LEN register ++ * status bits to avoid premature processing of a descriptor ++ * on its way back to the host. ++ */ ++#define SAFE_PE_CSR_IS_DONE(_csr) \ ++ (((_csr) & (SAFE_PE_CSR_READY | SAFE_PE_CSR_DONE)) == SAFE_PE_CSR_DONE) ++ ++#define SAFE_PE_LEN_LENGTH 0x000fffff /* total length (bytes) */ ++#define SAFE_PE_LEN_READY 0x00400000 /* ready for processing */ ++#define SAFE_PE_LEN_DONE 0x00800000 /* h/w completed processing */ ++#define SAFE_PE_LEN_BYPASS 0xff000000 /* bypass offset (bytes) */ ++#define SAFE_PE_LEN_BYPASS_S 24 ++ ++#define SAFE_PE_LEN_IS_DONE(_len) \ ++ (((_len) & (SAFE_PE_LEN_READY | SAFE_PE_LEN_DONE)) == SAFE_PE_LEN_DONE) ++ ++/* NB: these apply to HU_STAT, HM_STAT, HI_CLR, and HI_MASK */ ++#define SAFE_INT_PE_CDONE 0x00000002 /* PE context done */ ++#define SAFE_INT_PE_DDONE 0x00000008 /* PE descriptor done */ ++#define SAFE_INT_PE_ERROR 0x00000010 /* PE error */ ++#define SAFE_INT_PE_ODONE 0x00000020 /* PE operation done */ ++ ++#define SAFE_HI_CFG_PULSE 0x00000001 /* use pulse interrupt */ ++#define SAFE_HI_CFG_LEVEL 0x00000000 /* use level interrupt */ ++#define SAFE_HI_CFG_AUTOCLR 0x00000002 /* auto-clear pulse interrupt */ ++ ++#define SAFE_ENDIAN_PASS 0x000000e4 /* straight pass-thru */ ++#define SAFE_ENDIAN_SWAB 0x0000001b /* swap bytes in 32-bit word */ ++ ++#define SAFE_PE_DMACFG_PERESET 0x00000001 /* reset packet engine */ ++#define SAFE_PE_DMACFG_PDRRESET 0x00000002 /* reset PDR counters/ptrs */ ++#define SAFE_PE_DMACFG_SGRESET 0x00000004 /* reset scatter/gather cache */ ++#define SAFE_PE_DMACFG_FSENA 0x00000008 /* enable failsafe reset */ ++#define SAFE_PE_DMACFG_PEMODE 0x00000100 /* packet engine mode */ ++#define SAFE_PE_DMACFG_SAPREC 0x00000200 /* SA precedes packet */ ++#define SAFE_PE_DMACFG_PKFOLL 0x00000400 /* packet follows descriptor */ ++#define SAFE_PE_DMACFG_GPRBID 0x00003000 /* gather particle ring busid */ ++#define SAFE_PE_DMACFG_GPRPCI 0x00001000 /* PCI gather particle ring */ ++#define SAFE_PE_DMACFG_SPRBID 0x0000c000 /* scatter part. ring busid */ ++#define SAFE_PE_DMACFG_SPRPCI 0x00004000 /* PCI scatter part. ring */ ++#define SAFE_PE_DMACFG_ESDESC 0x00010000 /* endian swap descriptors */ ++#define SAFE_PE_DMACFG_ESSA 0x00020000 /* endian swap SA data */ ++#define SAFE_PE_DMACFG_ESPACKET 0x00040000 /* endian swap packet data */ ++#define SAFE_PE_DMACFG_ESPDESC 0x00080000 /* endian swap particle desc. */ ++#define SAFE_PE_DMACFG_NOPDRUP 0x00100000 /* supp. PDR ownership update */ ++#define SAFE_PD_EDMACFG_PCIMODE 0x01000000 /* PCI target mode */ ++ ++#define SAFE_PE_DMASTAT_PEIDONE 0x00000001 /* PE core input done */ ++#define SAFE_PE_DMASTAT_PEODONE 0x00000002 /* PE core output done */ ++#define SAFE_PE_DMASTAT_ENCDONE 0x00000004 /* encryption done */ ++#define SAFE_PE_DMASTAT_IHDONE 0x00000008 /* inner hash done */ ++#define SAFE_PE_DMASTAT_OHDONE 0x00000010 /* outer hash (HMAC) done */ ++#define SAFE_PE_DMASTAT_PADFLT 0x00000020 /* crypto pad fault */ ++#define SAFE_PE_DMASTAT_ICVFLT 0x00000040 /* ICV fault */ ++#define SAFE_PE_DMASTAT_SPIMIS 0x00000080 /* SPI mismatch */ ++#define SAFE_PE_DMASTAT_CRYPTO 0x00000100 /* crypto engine timeout */ ++#define SAFE_PE_DMASTAT_CQACT 0x00000200 /* command queue active */ ++#define SAFE_PE_DMASTAT_IRACT 0x00000400 /* input request active */ ++#define SAFE_PE_DMASTAT_ORACT 0x00000800 /* output request active */ ++#define SAFE_PE_DMASTAT_PEISIZE 0x003ff000 /* PE input size:32-bit words */ ++#define SAFE_PE_DMASTAT_PEOSIZE 0xffc00000 /* PE out. size:32-bit words */ ++ ++#define SAFE_PE_RINGCFG_SIZE 0x000003ff /* ring size (descriptors) */ ++#define SAFE_PE_RINGCFG_OFFSET 0xffff0000 /* offset btw desc's (dwords) */ ++#define SAFE_PE_RINGCFG_OFFSET_S 16 ++ ++#define SAFE_PE_RINGPOLL_POLL 0x00000fff /* polling frequency/divisor */ ++#define SAFE_PE_RINGPOLL_RETRY 0x03ff0000 /* polling frequency/divisor */ ++#define SAFE_PE_RINGPOLL_CONT 0x80000000 /* continuously poll */ ++ ++#define SAFE_PE_IRNGSTAT_CQAVAIL 0x00000001 /* command queue available */ ++ ++#define SAFE_PE_ERNGSTAT_NEXT 0x03ff0000 /* index of next packet desc. */ ++#define SAFE_PE_ERNGSTAT_NEXT_S 16 ++ ++#define SAFE_PE_IOTHRESH_INPUT 0x000003ff /* input threshold (dwords) */ ++#define SAFE_PE_IOTHRESH_OUTPUT 0x03ff0000 /* output threshold (dwords) */ ++ ++#define SAFE_PE_PARTCFG_SIZE 0x0000ffff /* scatter particle size */ ++#define SAFE_PE_PARTCFG_GBURST 0x00030000 /* gather particle burst */ ++#define SAFE_PE_PARTCFG_GBURST_2 0x00000000 ++#define SAFE_PE_PARTCFG_GBURST_4 0x00010000 ++#define SAFE_PE_PARTCFG_GBURST_8 0x00020000 ++#define SAFE_PE_PARTCFG_GBURST_16 0x00030000 ++#define SAFE_PE_PARTCFG_SBURST 0x000c0000 /* scatter particle burst */ ++#define SAFE_PE_PARTCFG_SBURST_2 0x00000000 ++#define SAFE_PE_PARTCFG_SBURST_4 0x00040000 ++#define SAFE_PE_PARTCFG_SBURST_8 0x00080000 ++#define SAFE_PE_PARTCFG_SBURST_16 0x000c0000 ++ ++#define SAFE_PE_PARTSIZE_SCAT 0xffff0000 /* scatter particle ring size */ ++#define SAFE_PE_PARTSIZE_GATH 0x0000ffff /* gather particle ring size */ ++ ++#define SAFE_CRYPTO_CTRL_3DES 0x00000001 /* enable 3DES support */ ++#define SAFE_CRYPTO_CTRL_PKEY 0x00010000 /* enable public key support */ ++#define SAFE_CRYPTO_CTRL_RNG 0x00020000 /* enable RNG support */ ++ ++#define SAFE_DEVINFO_REV_MIN 0x0000000f /* minor rev for chip */ ++#define SAFE_DEVINFO_REV_MAJ 0x000000f0 /* major rev for chip */ ++#define SAFE_DEVINFO_REV_MAJ_S 4 ++#define SAFE_DEVINFO_DES 0x00000100 /* DES/3DES support present */ ++#define SAFE_DEVINFO_ARC4 0x00000200 /* ARC4 support present */ ++#define SAFE_DEVINFO_AES 0x00000400 /* AES support present */ ++#define SAFE_DEVINFO_MD5 0x00001000 /* MD5 support present */ ++#define SAFE_DEVINFO_SHA1 0x00002000 /* SHA-1 support present */ ++#define SAFE_DEVINFO_RIPEMD 0x00004000 /* RIPEMD support present */ ++#define SAFE_DEVINFO_DEFLATE 0x00010000 /* Deflate support present */ ++#define SAFE_DEVINFO_SARAM 0x00100000 /* on-chip SA RAM present */ ++#define SAFE_DEVINFO_EMIBUS 0x00200000 /* EMI bus present */ ++#define SAFE_DEVINFO_PKEY 0x00400000 /* public key support present */ ++#define SAFE_DEVINFO_RNG 0x00800000 /* RNG present */ ++ ++#define SAFE_REV(_maj, _min) (((_maj) << SAFE_DEVINFO_REV_MAJ_S) | (_min)) ++#define SAFE_REV_MAJ(_chiprev) \ ++ (((_chiprev) & SAFE_DEVINFO_REV_MAJ) >> SAFE_DEVINFO_REV_MAJ_S) ++#define SAFE_REV_MIN(_chiprev) ((_chiprev) & SAFE_DEVINFO_REV_MIN) ++ ++#define SAFE_PK_FUNC_MULT 0x00000001 /* Multiply function */ ++#define SAFE_PK_FUNC_SQUARE 0x00000004 /* Square function */ ++#define SAFE_PK_FUNC_ADD 0x00000010 /* Add function */ ++#define SAFE_PK_FUNC_SUB 0x00000020 /* Subtract function */ ++#define SAFE_PK_FUNC_LSHIFT 0x00000040 /* Left-shift function */ ++#define SAFE_PK_FUNC_RSHIFT 0x00000080 /* Right-shift function */ ++#define SAFE_PK_FUNC_DIV 0x00000100 /* Divide function */ ++#define SAFE_PK_FUNC_CMP 0x00000400 /* Compare function */ ++#define SAFE_PK_FUNC_COPY 0x00000800 /* Copy function */ ++#define SAFE_PK_FUNC_EXP16 0x00002000 /* Exponentiate (4-bit ACT) */ ++#define SAFE_PK_FUNC_EXP4 0x00004000 /* Exponentiate (2-bit ACT) */ ++#define SAFE_PK_FUNC_RUN 0x00008000 /* start/status */ ++ ++#define SAFE_RNG_STAT_BUSY 0x00000001 /* busy, data not valid */ ++ ++#define SAFE_RNG_CTRL_PRE_LFSR 0x00000001 /* enable output pre-LFSR */ ++#define SAFE_RNG_CTRL_TST_MODE 0x00000002 /* enable test mode */ ++#define SAFE_RNG_CTRL_TST_RUN 0x00000004 /* start test state machine */ ++#define SAFE_RNG_CTRL_ENA_RING1 0x00000008 /* test entropy oscillator #1 */ ++#define SAFE_RNG_CTRL_ENA_RING2 0x00000010 /* test entropy oscillator #2 */ ++#define SAFE_RNG_CTRL_DIS_ALARM 0x00000020 /* disable RNG alarm reports */ ++#define SAFE_RNG_CTRL_TST_CLOCK 0x00000040 /* enable test clock */ ++#define SAFE_RNG_CTRL_SHORTEN 0x00000080 /* shorten state timers */ ++#define SAFE_RNG_CTRL_TST_ALARM 0x00000100 /* simulate alarm state */ ++#define SAFE_RNG_CTRL_RST_LFSR 0x00000200 /* reset LFSR */ ++ ++/* ++ * Packet engine descriptor. Note that d_csr is a copy of the ++ * SAFE_PE_CSR register and all definitions apply, and d_len ++ * is a copy of the SAFE_PE_LEN register and all definitions apply. ++ * d_src and d_len may point directly to contiguous data or to a ++ * list of ``particle descriptors'' when using scatter/gather i/o. ++ */ ++struct safe_desc { ++ u_int32_t d_csr; /* per-packet control/status */ ++ u_int32_t d_src; /* source address */ ++ u_int32_t d_dst; /* destination address */ ++ u_int32_t d_sa; /* SA address */ ++ u_int32_t d_len; /* length, bypass, status */ ++}; ++ ++/* ++ * Scatter/Gather particle descriptor. ++ * ++ * NB: scatter descriptors do not specify a size; this is fixed ++ * by the setting of the SAFE_PE_PARTCFG register. ++ */ ++struct safe_pdesc { ++ u_int32_t pd_addr; /* particle address */ ++#ifdef __BIG_ENDIAN ++ u_int16_t pd_flags; /* control word */ ++ u_int16_t pd_size; /* particle size (bytes) */ ++#else ++ u_int16_t pd_flags; /* control word */ ++ u_int16_t pd_size; /* particle size (bytes) */ ++#endif ++}; ++ ++#define SAFE_PD_READY 0x0001 /* ready for processing */ ++#define SAFE_PD_DONE 0x0002 /* h/w completed processing */ ++ ++/* ++ * Security Association (SA) Record (Rev 1). One of these is ++ * required for each operation processed by the packet engine. ++ */ ++struct safe_sarec { ++ u_int32_t sa_cmd0; ++ u_int32_t sa_cmd1; ++ u_int32_t sa_resv0; ++ u_int32_t sa_resv1; ++ u_int32_t sa_key[8]; /* DES/3DES/AES key */ ++ u_int32_t sa_indigest[5]; /* inner digest */ ++ u_int32_t sa_outdigest[5]; /* outer digest */ ++ u_int32_t sa_spi; /* SPI */ ++ u_int32_t sa_seqnum; /* sequence number */ ++ u_int32_t sa_seqmask[2]; /* sequence number mask */ ++ u_int32_t sa_resv2; ++ u_int32_t sa_staterec; /* address of state record */ ++ u_int32_t sa_resv3[2]; ++ u_int32_t sa_samgmt0; /* SA management field 0 */ ++ u_int32_t sa_samgmt1; /* SA management field 0 */ ++}; ++ ++#define SAFE_SA_CMD0_OP 0x00000007 /* operation code */ ++#define SAFE_SA_CMD0_OP_CRYPT 0x00000000 /* encrypt/decrypt (basic) */ ++#define SAFE_SA_CMD0_OP_BOTH 0x00000001 /* encrypt-hash/hash-decrypto */ ++#define SAFE_SA_CMD0_OP_HASH 0x00000003 /* hash (outbound-only) */ ++#define SAFE_SA_CMD0_OP_ESP 0x00000000 /* ESP in/out (proto) */ ++#define SAFE_SA_CMD0_OP_AH 0x00000001 /* AH in/out (proto) */ ++#define SAFE_SA_CMD0_INBOUND 0x00000008 /* inbound operation */ ++#define SAFE_SA_CMD0_OUTBOUND 0x00000000 /* outbound operation */ ++#define SAFE_SA_CMD0_GROUP 0x00000030 /* operation group */ ++#define SAFE_SA_CMD0_BASIC 0x00000000 /* basic operation */ ++#define SAFE_SA_CMD0_PROTO 0x00000010 /* protocol/packet operation */ ++#define SAFE_SA_CMD0_BUNDLE 0x00000020 /* bundled operation (resvd) */ ++#define SAFE_SA_CMD0_PAD 0x000000c0 /* crypto pad method */ ++#define SAFE_SA_CMD0_PAD_IPSEC 0x00000000 /* IPsec padding */ ++#define SAFE_SA_CMD0_PAD_PKCS7 0x00000040 /* PKCS#7 padding */ ++#define SAFE_SA_CMD0_PAD_CONS 0x00000080 /* constant padding */ ++#define SAFE_SA_CMD0_PAD_ZERO 0x000000c0 /* zero padding */ ++#define SAFE_SA_CMD0_CRYPT_ALG 0x00000f00 /* symmetric crypto algorithm */ ++#define SAFE_SA_CMD0_DES 0x00000000 /* DES crypto algorithm */ ++#define SAFE_SA_CMD0_3DES 0x00000100 /* 3DES crypto algorithm */ ++#define SAFE_SA_CMD0_AES 0x00000300 /* AES crypto algorithm */ ++#define SAFE_SA_CMD0_CRYPT_NULL 0x00000f00 /* null crypto algorithm */ ++#define SAFE_SA_CMD0_HASH_ALG 0x0000f000 /* hash algorithm */ ++#define SAFE_SA_CMD0_MD5 0x00000000 /* MD5 hash algorithm */ ++#define SAFE_SA_CMD0_SHA1 0x00001000 /* SHA-1 hash algorithm */ ++#define SAFE_SA_CMD0_HASH_NULL 0x0000f000 /* null hash algorithm */ ++#define SAFE_SA_CMD0_HDR_PROC 0x00080000 /* header processing */ ++#define SAFE_SA_CMD0_IBUSID 0x00300000 /* input bus id */ ++#define SAFE_SA_CMD0_IPCI 0x00100000 /* PCI input bus id */ ++#define SAFE_SA_CMD0_OBUSID 0x00c00000 /* output bus id */ ++#define SAFE_SA_CMD0_OPCI 0x00400000 /* PCI output bus id */ ++#define SAFE_SA_CMD0_IVLD 0x03000000 /* IV loading */ ++#define SAFE_SA_CMD0_IVLD_NONE 0x00000000 /* IV no load (reuse) */ ++#define SAFE_SA_CMD0_IVLD_IBUF 0x01000000 /* IV load from input buffer */ ++#define SAFE_SA_CMD0_IVLD_STATE 0x02000000 /* IV load from state */ ++#define SAFE_SA_CMD0_HSLD 0x0c000000 /* hash state loading */ ++#define SAFE_SA_CMD0_HSLD_SA 0x00000000 /* hash state load from SA */ ++#define SAFE_SA_CMD0_HSLD_STATE 0x08000000 /* hash state load from state */ ++#define SAFE_SA_CMD0_HSLD_NONE 0x0c000000 /* hash state no load */ ++#define SAFE_SA_CMD0_SAVEIV 0x10000000 /* save IV */ ++#define SAFE_SA_CMD0_SAVEHASH 0x20000000 /* save hash state */ ++#define SAFE_SA_CMD0_IGATHER 0x40000000 /* input gather */ ++#define SAFE_SA_CMD0_OSCATTER 0x80000000 /* output scatter */ ++ ++#define SAFE_SA_CMD1_HDRCOPY 0x00000002 /* copy header to output */ ++#define SAFE_SA_CMD1_PAYCOPY 0x00000004 /* copy payload to output */ ++#define SAFE_SA_CMD1_PADCOPY 0x00000008 /* copy pad to output */ ++#define SAFE_SA_CMD1_IPV4 0x00000000 /* IPv4 protocol */ ++#define SAFE_SA_CMD1_IPV6 0x00000010 /* IPv6 protocol */ ++#define SAFE_SA_CMD1_MUTABLE 0x00000020 /* mutable bit processing */ ++#define SAFE_SA_CMD1_SRBUSID 0x000000c0 /* state record bus id */ ++#define SAFE_SA_CMD1_SRPCI 0x00000040 /* state record from PCI */ ++#define SAFE_SA_CMD1_CRMODE 0x00000300 /* crypto mode */ ++#define SAFE_SA_CMD1_ECB 0x00000000 /* ECB crypto mode */ ++#define SAFE_SA_CMD1_CBC 0x00000100 /* CBC crypto mode */ ++#define SAFE_SA_CMD1_OFB 0x00000200 /* OFB crypto mode */ ++#define SAFE_SA_CMD1_CFB 0x00000300 /* CFB crypto mode */ ++#define SAFE_SA_CMD1_CRFEEDBACK 0x00000c00 /* crypto feedback mode */ ++#define SAFE_SA_CMD1_64BIT 0x00000000 /* 64-bit crypto feedback */ ++#define SAFE_SA_CMD1_8BIT 0x00000400 /* 8-bit crypto feedback */ ++#define SAFE_SA_CMD1_1BIT 0x00000800 /* 1-bit crypto feedback */ ++#define SAFE_SA_CMD1_128BIT 0x00000c00 /* 128-bit crypto feedback */ ++#define SAFE_SA_CMD1_OPTIONS 0x00001000 /* HMAC/options mutable bit */ ++#define SAFE_SA_CMD1_HMAC SAFE_SA_CMD1_OPTIONS ++#define SAFE_SA_CMD1_SAREV1 0x00008000 /* SA Revision 1 */ ++#define SAFE_SA_CMD1_OFFSET 0x00ff0000 /* hash/crypto offset(dwords) */ ++#define SAFE_SA_CMD1_OFFSET_S 16 ++#define SAFE_SA_CMD1_AESKEYLEN 0x0f000000 /* AES key length */ ++#define SAFE_SA_CMD1_AES128 0x02000000 /* 128-bit AES key */ ++#define SAFE_SA_CMD1_AES192 0x03000000 /* 192-bit AES key */ ++#define SAFE_SA_CMD1_AES256 0x04000000 /* 256-bit AES key */ ++ ++/* ++ * Security Associate State Record (Rev 1). ++ */ ++struct safe_sastate { ++ u_int32_t sa_saved_iv[4]; /* saved IV (DES/3DES/AES) */ ++ u_int32_t sa_saved_hashbc; /* saved hash byte count */ ++ u_int32_t sa_saved_indigest[5]; /* saved inner digest */ ++}; ++#endif /* _SAFE_SAFEREG_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safevar.h linux-2.6.30/crypto/ocf/safe/safevar.h +--- linux-2.6.30.orig/crypto/ocf/safe/safevar.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safevar.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,230 @@ ++/*- ++ * The linux port of this code done by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * $FreeBSD: src/sys/dev/safe/safevar.h,v 1.2 2006/05/17 18:34:26 pjd Exp $ ++ */ ++#ifndef _SAFE_SAFEVAR_H_ ++#define _SAFE_SAFEVAR_H_ ++ ++/* Maximum queue length */ ++#ifndef SAFE_MAX_NQUEUE ++#define SAFE_MAX_NQUEUE 60 ++#endif ++ ++#define SAFE_MAX_PART 64 /* Maximum scatter/gather depth */ ++#define SAFE_DMA_BOUNDARY 0 /* No boundary for source DMA ops */ ++#define SAFE_MAX_DSIZE 2048 /* MCLBYTES Fixed scatter particle size */ ++#define SAFE_MAX_SSIZE 0x0ffff /* Maximum gather particle size */ ++#define SAFE_MAX_DMA 0xfffff /* Maximum PE operand size (20 bits) */ ++/* total src+dst particle descriptors */ ++#define SAFE_TOTAL_DPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) ++#define SAFE_TOTAL_SPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) ++ ++#define SAFE_RNG_MAXBUFSIZ 128 /* 32-bit words */ ++ ++#define SAFE_CARD(sid) (((sid) & 0xf0000000) >> 28) ++#define SAFE_SESSION(sid) ( (sid) & 0x0fffffff) ++#define SAFE_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) ++ ++#define SAFE_DEF_RTY 0xff /* PCI Retry Timeout */ ++#define SAFE_DEF_TOUT 0xff /* PCI TRDY Timeout */ ++#define SAFE_DEF_CACHELINE 0x01 /* Cache Line setting */ ++ ++#ifdef __KERNEL__ ++/* ++ * State associated with the allocation of each chunk ++ * of memory setup for DMA. ++ */ ++struct safe_dma_alloc { ++ dma_addr_t dma_paddr; ++ void *dma_vaddr; ++}; ++ ++/* ++ * Cryptographic operand state. One of these exists for each ++ * source and destination operand passed in from the crypto ++ * subsystem. When possible source and destination operands ++ * refer to the same memory. More often they are distinct. ++ * We track the virtual address of each operand as well as ++ * where each is mapped for DMA. ++ */ ++struct safe_operand { ++ union { ++ struct sk_buff *skb; ++ struct uio *io; ++ } u; ++ void *map; ++ int mapsize; /* total number of bytes in segs */ ++ struct { ++ dma_addr_t ds_addr; ++ int ds_len; ++ int ds_tlen; ++ } segs[SAFE_MAX_PART]; ++ int nsegs; ++}; ++ ++/* ++ * Packet engine ring entry and cryptographic operation state. ++ * The packet engine requires a ring of descriptors that contain ++ * pointers to various cryptographic state. However the ring ++ * configuration register allows you to specify an arbitrary size ++ * for ring entries. We use this feature to collect most of the ++ * state for each cryptographic request into one spot. Other than ++ * ring entries only the ``particle descriptors'' (scatter/gather ++ * lists) and the actual operand data are kept separate. The ++ * particle descriptors must also be organized in rings. The ++ * operand data can be located aribtrarily (modulo alignment constraints). ++ * ++ * Note that the descriptor ring is mapped onto the PCI bus so ++ * the hardware can DMA data. This means the entire ring must be ++ * contiguous. ++ */ ++struct safe_ringentry { ++ struct safe_desc re_desc; /* command descriptor */ ++ struct safe_sarec re_sa; /* SA record */ ++ struct safe_sastate re_sastate; /* SA state record */ ++ ++ struct cryptop *re_crp; /* crypto operation */ ++ ++ struct safe_operand re_src; /* source operand */ ++ struct safe_operand re_dst; /* destination operand */ ++ ++ int re_sesn; /* crypto session ID */ ++ int re_flags; ++#define SAFE_QFLAGS_COPYOUTIV 0x1 /* copy back on completion */ ++#define SAFE_QFLAGS_COPYOUTICV 0x2 /* copy back on completion */ ++}; ++ ++#define re_src_skb re_src.u.skb ++#define re_src_io re_src.u.io ++#define re_src_map re_src.map ++#define re_src_nsegs re_src.nsegs ++#define re_src_segs re_src.segs ++#define re_src_mapsize re_src.mapsize ++ ++#define re_dst_skb re_dst.u.skb ++#define re_dst_io re_dst.u.io ++#define re_dst_map re_dst.map ++#define re_dst_nsegs re_dst.nsegs ++#define re_dst_segs re_dst.segs ++#define re_dst_mapsize re_dst.mapsize ++ ++struct rndstate_test; ++ ++struct safe_session { ++ u_int32_t ses_used; ++ u_int32_t ses_klen; /* key length in bits */ ++ u_int32_t ses_key[8]; /* DES/3DES/AES key */ ++ u_int32_t ses_mlen; /* hmac length in bytes */ ++ u_int32_t ses_hminner[5]; /* hmac inner state */ ++ u_int32_t ses_hmouter[5]; /* hmac outer state */ ++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */ ++}; ++ ++struct safe_pkq { ++ struct list_head pkq_list; ++ struct cryptkop *pkq_krp; ++}; ++ ++struct safe_softc { ++ softc_device_decl sc_dev; ++ u32 sc_irq; ++ ++ struct pci_dev *sc_pcidev; ++ ocf_iomem_t sc_base_addr; ++ ++ u_int sc_chiprev; /* major/minor chip revision */ ++ int sc_flags; /* device specific flags */ ++#define SAFE_FLAGS_KEY 0x01 /* has key accelerator */ ++#define SAFE_FLAGS_RNG 0x02 /* hardware rng */ ++ int sc_suspended; ++ int sc_needwakeup; /* notify crypto layer */ ++ int32_t sc_cid; /* crypto tag */ ++ ++ struct safe_dma_alloc sc_ringalloc; /* PE ring allocation state */ ++ struct safe_ringentry *sc_ring; /* PE ring */ ++ struct safe_ringentry *sc_ringtop; /* PE ring top */ ++ struct safe_ringentry *sc_front; /* next free entry */ ++ struct safe_ringentry *sc_back; /* next pending entry */ ++ int sc_nqchip; /* # passed to chip */ ++ spinlock_t sc_ringmtx; /* PE ring lock */ ++ struct safe_pdesc *sc_spring; /* src particle ring */ ++ struct safe_pdesc *sc_springtop; /* src particle ring top */ ++ struct safe_pdesc *sc_spfree; /* next free src particle */ ++ struct safe_dma_alloc sc_spalloc; /* src particle ring state */ ++ struct safe_pdesc *sc_dpring; /* dest particle ring */ ++ struct safe_pdesc *sc_dpringtop; /* dest particle ring top */ ++ struct safe_pdesc *sc_dpfree; /* next free dest particle */ ++ struct safe_dma_alloc sc_dpalloc; /* dst particle ring state */ ++ int sc_nsessions; /* # of sessions */ ++ struct safe_session *sc_sessions; /* sessions */ ++ ++ struct timer_list sc_pkto; /* PK polling */ ++ spinlock_t sc_pkmtx; /* PK lock */ ++ struct list_head sc_pkq; /* queue of PK requests */ ++ struct safe_pkq *sc_pkq_cur; /* current processing request */ ++ u_int32_t sc_pk_reslen, sc_pk_resoff; ++ ++ int sc_max_dsize; /* maximum safe DMA size */ ++}; ++#endif /* __KERNEL__ */ ++ ++struct safe_stats { ++ u_int64_t st_ibytes; ++ u_int64_t st_obytes; ++ u_int32_t st_ipackets; ++ u_int32_t st_opackets; ++ u_int32_t st_invalid; /* invalid argument */ ++ u_int32_t st_badsession; /* invalid session id */ ++ u_int32_t st_badflags; /* flags indicate !(mbuf | uio) */ ++ u_int32_t st_nodesc; /* op submitted w/o descriptors */ ++ u_int32_t st_badalg; /* unsupported algorithm */ ++ u_int32_t st_ringfull; /* PE descriptor ring full */ ++ u_int32_t st_peoperr; /* PE marked error */ ++ u_int32_t st_dmaerr; /* PE DMA error */ ++ u_int32_t st_bypasstoobig; /* bypass > 96 bytes */ ++ u_int32_t st_skipmismatch; /* enc part begins before auth part */ ++ u_int32_t st_lenmismatch; /* enc length different auth length */ ++ u_int32_t st_coffmisaligned; /* crypto offset not 32-bit aligned */ ++ u_int32_t st_cofftoobig; /* crypto offset > 255 words */ ++ u_int32_t st_iovmisaligned; /* iov op not aligned */ ++ u_int32_t st_iovnotuniform; /* iov op not suitable */ ++ u_int32_t st_unaligned; /* unaligned src caused copy */ ++ u_int32_t st_notuniform; /* non-uniform src caused copy */ ++ u_int32_t st_nomap; /* bus_dmamap_create failed */ ++ u_int32_t st_noload; /* bus_dmamap_load_* failed */ ++ u_int32_t st_nombuf; /* MGET* failed */ ++ u_int32_t st_nomcl; /* MCLGET* failed */ ++ u_int32_t st_maxqchip; /* max mcr1 ops out for processing */ ++ u_int32_t st_rng; /* RNG requests */ ++ u_int32_t st_rngalarm; /* RNG alarm requests */ ++ u_int32_t st_noicvcopy; /* ICV data copies suppressed */ ++}; ++#endif /* _SAFE_SAFEVAR_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/sha1.c linux-2.6.30/crypto/ocf/safe/sha1.c +--- linux-2.6.30.orig/crypto/ocf/safe/sha1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/sha1.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,279 @@ ++/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++/* ++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) ++ * based on: http://csrc.nist.gov/fips/fip180-1.txt ++ * implemented by Jun-ichiro itojun Itoh ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/crypto/sha1.c,v 1.9 2003/06/10 21:36:57 obrien Exp $"); ++ ++#include ++#include ++#include ++#include ++ ++#include ++#endif ++ ++/* sanity check */ ++#if BYTE_ORDER != BIG_ENDIAN ++# if BYTE_ORDER != LITTLE_ENDIAN ++# define unsupported 1 ++# endif ++#endif ++ ++#ifndef unsupported ++ ++/* constant table */ ++static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; ++#define K(t) _K[(t) / 20] ++ ++#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) ++#define F1(b, c, d) (((b) ^ (c)) ^ (d)) ++#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) ++#define F3(b, c, d) (((b) ^ (c)) ^ (d)) ++ ++#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) ++ ++#undef H ++#define H(n) (ctxt->h.b32[(n)]) ++#define COUNT (ctxt->count) ++#define BCOUNT (ctxt->c.b64[0] / 8) ++#define W(n) (ctxt->m.b32[(n)]) ++ ++#define PUTBYTE(x) { \ ++ ctxt->m.b8[(COUNT % 64)] = (x); \ ++ COUNT++; \ ++ COUNT %= 64; \ ++ ctxt->c.b64[0] += 8; \ ++ if (COUNT % 64 == 0) \ ++ sha1_step(ctxt); \ ++ } ++ ++#define PUTPAD(x) { \ ++ ctxt->m.b8[(COUNT % 64)] = (x); \ ++ COUNT++; \ ++ COUNT %= 64; \ ++ if (COUNT % 64 == 0) \ ++ sha1_step(ctxt); \ ++ } ++ ++static void sha1_step(struct sha1_ctxt *); ++ ++static void ++sha1_step(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ u_int32_t a, b, c, d, e; ++ size_t t, s; ++ u_int32_t tmp; ++ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ struct sha1_ctxt tctxt; ++ bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64); ++ ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; ++ ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; ++ ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; ++ ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; ++ ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; ++ ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; ++ ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; ++ ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; ++ ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; ++ ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; ++ ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; ++ ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; ++ ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; ++ ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; ++ ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; ++ ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; ++ ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; ++ ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; ++ ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; ++ ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; ++ ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; ++ ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; ++ ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; ++ ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; ++ ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; ++ ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; ++ ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; ++ ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; ++ ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; ++ ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; ++ ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; ++ ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; ++#endif ++ ++ a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); ++ ++ for (t = 0; t < 20; t++) { ++ s = t & 0x0f; ++ if (t >= 16) { ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ } ++ tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 20; t < 40; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 40; t < 60; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 60; t < 80; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ ++ H(0) = H(0) + a; ++ H(1) = H(1) + b; ++ H(2) = H(2) + c; ++ H(3) = H(3) + d; ++ H(4) = H(4) + e; ++ ++ bzero(&ctxt->m.b8[0], 64); ++} ++ ++/*------------------------------------------------------------*/ ++ ++void ++sha1_init(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ bzero(ctxt, sizeof(struct sha1_ctxt)); ++ H(0) = 0x67452301; ++ H(1) = 0xefcdab89; ++ H(2) = 0x98badcfe; ++ H(3) = 0x10325476; ++ H(4) = 0xc3d2e1f0; ++} ++ ++void ++sha1_pad(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ size_t padlen; /*pad length in bytes*/ ++ size_t padstart; ++ ++ PUTPAD(0x80); ++ ++ padstart = COUNT % 64; ++ padlen = 64 - padstart; ++ if (padlen < 8) { ++ bzero(&ctxt->m.b8[padstart], padlen); ++ COUNT += padlen; ++ COUNT %= 64; ++ sha1_step(ctxt); ++ padstart = COUNT % 64; /* should be 0 */ ++ padlen = 64 - padstart; /* should be 64 */ ++ } ++ bzero(&ctxt->m.b8[padstart], padlen - 8); ++ COUNT += (padlen - 8); ++ COUNT %= 64; ++#if BYTE_ORDER == BIG_ENDIAN ++ PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); ++ PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); ++ PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); ++ PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); ++#else ++ PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); ++ PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); ++ PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); ++ PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); ++#endif ++} ++ ++void ++sha1_loop(ctxt, input, len) ++ struct sha1_ctxt *ctxt; ++ const u_int8_t *input; ++ size_t len; ++{ ++ size_t gaplen; ++ size_t gapstart; ++ size_t off; ++ size_t copysiz; ++ ++ off = 0; ++ ++ while (off < len) { ++ gapstart = COUNT % 64; ++ gaplen = 64 - gapstart; ++ ++ copysiz = (gaplen < len - off) ? gaplen : len - off; ++ bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz); ++ COUNT += copysiz; ++ COUNT %= 64; ++ ctxt->c.b64[0] += copysiz * 8; ++ if (COUNT % 64 == 0) ++ sha1_step(ctxt); ++ off += copysiz; ++ } ++} ++ ++void ++sha1_result(ctxt, digest0) ++ struct sha1_ctxt *ctxt; ++ caddr_t digest0; ++{ ++ u_int8_t *digest; ++ ++ digest = (u_int8_t *)digest0; ++ sha1_pad(ctxt); ++#if BYTE_ORDER == BIG_ENDIAN ++ bcopy(&ctxt->h.b8[0], digest, 20); ++#else ++ digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; ++ digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; ++ digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; ++ digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; ++ digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; ++ digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; ++ digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; ++ digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; ++ digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; ++ digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; ++#endif ++} ++ ++#endif /*unsupported*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/sha1.h linux-2.6.30/crypto/ocf/safe/sha1.h +--- linux-2.6.30.orig/crypto/ocf/safe/sha1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/sha1.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* $FreeBSD: src/sys/crypto/sha1.h,v 1.8 2002/03/20 05:13:50 alfred Exp $ */ ++/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ ++ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++/* ++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) ++ * based on: http://csrc.nist.gov/fips/fip180-1.txt ++ * implemented by Jun-ichiro itojun Itoh ++ */ ++ ++#ifndef _NETINET6_SHA1_H_ ++#define _NETINET6_SHA1_H_ ++ ++struct sha1_ctxt { ++ union { ++ u_int8_t b8[20]; ++ u_int32_t b32[5]; ++ } h; ++ union { ++ u_int8_t b8[8]; ++ u_int64_t b64[1]; ++ } c; ++ union { ++ u_int8_t b8[64]; ++ u_int32_t b32[16]; ++ } m; ++ u_int8_t count; ++}; ++ ++#ifdef __KERNEL__ ++extern void sha1_init(struct sha1_ctxt *); ++extern void sha1_pad(struct sha1_ctxt *); ++extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t); ++extern void sha1_result(struct sha1_ctxt *, caddr_t); ++ ++/* compatibilty with other SHA1 source codes */ ++typedef struct sha1_ctxt SHA1_CTX; ++#define SHA1Init(x) sha1_init((x)) ++#define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) ++#define SHA1Final(x, y) sha1_result((y), (x)) ++#endif /* __KERNEL__ */ ++ ++#define SHA1_RESULTLEN (160/8) ++ ++#endif /*_NETINET6_SHA1_H_*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/Makefile linux-2.6.30/crypto/ocf/talitos/Makefile +--- linux-2.6.30.orig/crypto/ocf/talitos/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_TALITOS) += talitos.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos.c linux-2.6.30/crypto/ocf/talitos/talitos.c +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1359 @@ ++/* ++ * crypto/ocf/talitos/talitos.c ++ * ++ * An OCF-Linux module that uses Freescale's SEC to do the crypto. ++ * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * This code written by Kim A. B. Phillips ++ * some code copied from files with the following: ++ * Copyright (C) 2004-2007 David McCullough ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* dma_map_single() */ ++#include ++ ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++#include ++#endif ++ ++#include ++#include ++ ++#define DRV_NAME "talitos" ++ ++#include "talitos_dev.h" ++#include "talitos_soft.h" ++ ++#define read_random(p,l) get_random_bytes(p,l) ++ ++const char talitos_driver_name[] = "Talitos OCF"; ++const char talitos_driver_version[] = "0.2"; ++ ++static int talitos_newsession(device_t dev, u_int32_t *sidp, ++ struct cryptoini *cri); ++static int talitos_freesession(device_t dev, u_int64_t tid); ++static int talitos_process(device_t dev, struct cryptop *crp, int hint); ++static void dump_talitos_status(struct talitos_softc *sc); ++static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td, ++ int chsel); ++static void talitos_doneprocessing(struct talitos_softc *sc); ++static void talitos_init_device(struct talitos_softc *sc); ++static void talitos_reset_device_master(struct talitos_softc *sc); ++static void talitos_reset_device(struct talitos_softc *sc); ++static void talitos_errorprocessing(struct talitos_softc *sc); ++#ifdef CONFIG_PPC_MERGE ++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match); ++static int talitos_remove(struct of_device *ofdev); ++#else ++static int talitos_probe(struct platform_device *pdev); ++static int talitos_remove(struct platform_device *pdev); ++#endif ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords); ++static void talitos_rng_init(struct talitos_softc *sc); ++#endif ++ ++static device_method_t talitos_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, talitos_newsession), ++ DEVMETHOD(cryptodev_freesession,talitos_freesession), ++ DEVMETHOD(cryptodev_process, talitos_process), ++}; ++ ++#define debug talitos_debug ++int talitos_debug = 0; ++module_param(talitos_debug, int, 0644); ++MODULE_PARM_DESC(talitos_debug, "Enable debug"); ++ ++static inline void talitos_write(volatile unsigned *addr, u32 val) ++{ ++ out_be32(addr, val); ++} ++ ++static inline u32 talitos_read(volatile unsigned *addr) ++{ ++ u32 val; ++ val = in_be32(addr); ++ return val; ++} ++ ++static void dump_talitos_status(struct talitos_softc *sc) ++{ ++ unsigned int v, v_hi, i, *ptr; ++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI); ++ printk(KERN_INFO "%s: MCR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); ++ printk(KERN_INFO "%s: IMR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); ++ printk(KERN_INFO "%s: ISR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CDPR); ++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CDPR_HI); ++ printk(KERN_INFO "%s: CDPR ch%d 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), i, v, v_hi); ++ } ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCPSR); ++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCPSR_HI); ++ printk(KERN_INFO "%s: CCPSR ch%d 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), i, v, v_hi); ++ } ++ ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF; ++ for (i = 0; i < 16; i++) { ++ v = talitos_read(ptr++); v_hi = talitos_read(ptr++); ++ printk(KERN_INFO "%s: DESCBUF ch0 0x%08x_%08x (tdp%02d)\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi, i); ++ } ++ return; ++} ++ ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++/* ++ * pull random numbers off the RNG FIFO, not exceeding amount available ++ */ ++static int ++talitos_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ struct talitos_softc *sc = (struct talitos_softc *) arg; ++ int rc; ++ u_int32_t v; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* check for things like FIFO underflow */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); ++ if (unlikely(v)) { ++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n", ++ device_get_nameunit(sc->sc_cdev), v); ++ return 0; ++ } ++ /* ++ * OFL is number of available 64-bit words, ++ * shift and convert to a 32-bit word count ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI); ++ v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1); ++ if (maxwords > v) ++ maxwords = v; ++ for (rc = 0; rc < maxwords; rc++) { ++ buf[rc] = talitos_read(sc->sc_base_addr + ++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); ++ } ++ if (maxwords & 1) { ++ /* ++ * RNG will complain with an AE in the RNGISR ++ * if we don't complete the pairs of 32-bit reads ++ * to its 64-bit register based FIFO ++ */ ++ v = talitos_read(sc->sc_base_addr + ++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); ++ } ++ ++ return rc; ++} ++ ++static void ++talitos_rng_init(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* reset RNG EU */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI); ++ v |= TALITOS_RNGRCR_HI_SR; ++ talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v); ++ while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI) ++ & TALITOS_RNGSR_HI_RD) == 0) ++ cpu_relax(); ++ /* ++ * we tell the RNG to start filling the RNG FIFO ++ * by writing the RNGDSR ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI); ++ talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v); ++ /* ++ * 64 bits of data will be pushed onto the FIFO every ++ * 256 SEC cycles until the FIFO is full. The RNG then ++ * attempts to keep the FIFO full. ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); ++ if (v) { ++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n", ++ device_get_nameunit(sc->sc_cdev), v); ++ return; ++ } ++ /* ++ * n.b. we need to add a FIPS test here - if the RNG is going ++ * to fail, it's going to fail at reset time ++ */ ++ return; ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct talitos_softc *sc = device_get_softc(dev); ++ struct talitos_session *ses = NULL; ++ int sesn; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (c->cri_alg == CRYPTO_MD5 || ++ c->cri_alg == CRYPTO_MD5_HMAC || ++ c->cri_alg == CRYPTO_SHA1 || ++ c->cri_alg == CRYPTO_SHA1_HMAC || ++ c->cri_alg == CRYPTO_NULL_HMAC) { ++ if (macini) ++ return EINVAL; ++ macini = c; ++ } else if (c->cri_alg == CRYPTO_DES_CBC || ++ c->cri_alg == CRYPTO_3DES_CBC || ++ c->cri_alg == CRYPTO_AES_CBC || ++ c->cri_alg == CRYPTO_NULL_CBC) { ++ if (encini) ++ return EINVAL; ++ encini = c; ++ } else { ++ DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg); ++ return EINVAL; ++ } ++ } ++ if (encini == NULL && macini == NULL) ++ return EINVAL; ++ if (encini) { ++ /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return EINVAL; ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) { ++ return EINVAL; ++ } ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return EINVAL; ++ break; ++ default: ++ DPRINTF("UNKNOWN encini->cri_alg %d\n", ++ encini->cri_alg); ++ return EINVAL; ++ } ++ } ++ ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct talitos_session *) ++ kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return ENOMEM; ++ memset(ses, 0, sizeof(struct talitos_session)); ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn].ses_used == 0) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ /* allocating session */ ++ sesn = sc->sc_nsessions; ++ ses = (struct talitos_session *) kmalloc( ++ (sesn + 1) * sizeof(struct talitos_session), ++ SLAB_ATOMIC); ++ if (ses == NULL) ++ return ENOMEM; ++ memset(ses, 0, ++ (sesn + 1) * sizeof(struct talitos_session)); ++ memcpy(ses, sc->sc_sessions, ++ sesn * sizeof(struct talitos_session)); ++ memset(sc->sc_sessions, 0, ++ sesn * sizeof(struct talitos_session)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ ++ ses->ses_used = 1; ++ ++ if (encini) { ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ read_random(ses->ses_iv, sizeof(ses->ses_iv)); ++ ++ ses->ses_klen = (encini->cri_klen + 7) / 8; ++ memcpy(ses->ses_key, encini->cri_key, ses->ses_klen); ++ if (macini) { ++ /* doing hash on top of cipher */ ++ ses->ses_hmac_len = (macini->cri_klen + 7) / 8; ++ memcpy(ses->ses_hmac, macini->cri_key, ++ ses->ses_hmac_len); ++ } ++ } else if (macini) { ++ /* doing hash */ ++ ses->ses_klen = (macini->cri_klen + 7) / 8; ++ memcpy(ses->ses_key, macini->cri_key, ses->ses_klen); ++ } ++ ++ /* back compat way of determining MSC result len */ ++ if (macini) { ++ ses->ses_mlen = macini->cri_mlen; ++ if (ses->ses_mlen == 0) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC) ++ ses->ses_mlen = MD5_HASH_LEN; ++ else ++ ses->ses_mlen = SHA1_HASH_LEN; ++ } ++ } ++ ++ /* really should make up a template td here, ++ * and only fill things like i/o and direction in process() */ ++ ++ /* assign session ID */ ++ *sidp = TALITOS_SID(sc->sc_num, sesn); ++ return 0; ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++talitos_freesession(device_t dev, u_int64_t tid) ++{ ++ struct talitos_softc *sc = device_get_softc(dev); ++ int session, ret; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ if (sc == NULL) ++ return EINVAL; ++ session = TALITOS_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ memset(&sc->sc_sessions[session], 0, ++ sizeof(sc->sc_sessions[session])); ++ ret = 0; ++ } else ++ ret = EINVAL; ++ return ret; ++} ++ ++/* ++ * launch device processing - it will come back with done notification ++ * in the form of an interrupt and/or HDR_DONE_BITS in header ++ */ ++static int ++talitos_submit( ++ struct talitos_softc *sc, ++ struct talitos_desc *td, ++ int chsel) ++{ ++ u_int32_t v; ++ ++ v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE); ++ talitos_write(sc->sc_base_addr + ++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0); ++ talitos_write(sc->sc_base_addr + ++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v); ++ return 0; ++} ++ ++static int ++talitos_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ int i, err = 0, ivsize; ++ struct talitos_softc *sc = device_get_softc(dev); ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ caddr_t iv; ++ struct talitos_session *ses; ++ struct talitos_desc *td; ++ unsigned long flags; ++ /* descriptor mappings */ ++ int hmac_key, hmac_data, cipher_iv, cipher_key, ++ in_fifo, out_fifo, cipher_iv_out; ++ static int chsel = -1; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { ++ return EINVAL; ++ } ++ crp->crp_etype = 0; ++ if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) { ++ return EINVAL; ++ } ++ ++ ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)]; ++ ++ /* enter the channel scheduler */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ /* reuse channel that already had/has requests for the required EU */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg) ++ break; ++ } ++ if (i == sc->sc_num_channels) { ++ /* ++ * haven't seen this algo the last sc_num_channels or more ++ * use round robin in this case ++ * nb: sc->sc_num_channels must be power of 2 ++ */ ++ chsel = (chsel + 1) & (sc->sc_num_channels - 1); ++ } else { ++ /* ++ * matches channel with same target execution unit; ++ * use same channel in this case ++ */ ++ chsel = i; ++ } ++ sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg; ++ ++ /* release the channel scheduler lock */ ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ /* acquire the selected channel fifo lock */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags); ++ ++ /* find and reserve next available descriptor-cryptop pair */ ++ for (i = 0; i < sc->sc_chfifo_len; i++) { ++ if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) { ++ /* ++ * ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 for MD/HMAC descs ++ */ ++ memset(&sc->sc_chnfifo[chsel][i].cf_desc, ++ 0, sizeof(*td)); ++ /* reserve it with done notification request bit */ ++ sc->sc_chnfifo[chsel][i].cf_desc.hdr |= ++ TALITOS_DONE_NOTIFY; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags); ++ ++ if (i == sc->sc_chfifo_len) { ++ /* fifo full */ ++ err = ERESTART; ++ goto errout; ++ } ++ ++ td = &sc->sc_chnfifo[chsel][i].cf_desc; ++ sc->sc_chnfifo[chsel][i].cf_crp = crp; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ /* prevent compiler warning */ ++ hmac_key = 0; ++ hmac_data = 0; ++ if (crd2 == NULL) { ++ td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU; ++ /* assign descriptor dword ptr mappings for this desc. type */ ++ cipher_iv = 1; ++ cipher_key = 2; ++ in_fifo = 3; ++ cipher_iv_out = 5; ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1 || ++ crd1->crd_alg == CRYPTO_MD5) { ++ out_fifo = 5; ++ maccrd = crd1; ++ enccrd = NULL; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4) { ++ out_fifo = 4; ++ maccrd = NULL; ++ enccrd = crd1; ++ } else { ++ DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg); ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) { ++ td->hdr |= TD_TYPE_IPSEC_ESP; ++ } else { ++ DPRINTF("unimplemented: multiple descriptor ipsec\n"); ++ err = EINVAL; ++ goto errout; ++ } ++ /* assign descriptor dword ptr mappings for this desc. type */ ++ hmac_key = 0; ++ hmac_data = 1; ++ cipher_iv = 2; ++ cipher_key = 3; ++ in_fifo = 4; ++ out_fifo = 5; ++ cipher_iv_out = 6; ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_MD5 || ++ crd1->crd_alg == CRYPTO_SHA1) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_ARC4) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4 || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_MD5 || ++ crd2->crd_alg == CRYPTO_SHA1) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ /* We cannot order the SEC as requested */ ++ printk("%s: cannot do the order\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ /* assign in_fifo and out_fifo based on input/output struct type */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ /* using SKB buffers */ ++ struct sk_buff *skb = (struct sk_buff *)crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ printk("%s: skb frags unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = skb->len; ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = skb->len; ++ td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* using IOV buffers */ ++ struct uio *uiop = (struct uio *)crp->crp_buf; ++ if (uiop->uio_iovcnt > 1) { ++ printk("%s: iov frags unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, ++ uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = crp->crp_ilen; ++ /* crp_olen is never set; always use crp_ilen */ ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, ++ uiop->uio_iov->iov_base, ++ crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = crp->crp_ilen; ++ } else { ++ /* using contig buffers */ ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, ++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = crp->crp_ilen; ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, ++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = crp->crp_ilen; ++ } ++ if (enccrd) { ++ switch (enccrd->crd_alg) { ++ case CRYPTO_3DES_CBC: ++ td->hdr |= TALITOS_MODE0_DEU_3DES; ++ /* FALLTHROUGH */ ++ case CRYPTO_DES_CBC: ++ td->hdr |= TALITOS_SEL0_DEU ++ | TALITOS_MODE0_DEU_CBC; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ td->hdr |= TALITOS_MODE0_DEU_ENC; ++ ivsize = 2*sizeof(u_int32_t); ++ DPRINTF("%cDES ses %d ch %d len %d\n", ++ (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1', ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_AES_CBC: ++ td->hdr |= TALITOS_SEL0_AESU ++ | TALITOS_MODE0_AESU_CBC; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ td->hdr |= TALITOS_MODE0_AESU_ENC; ++ ivsize = 4*sizeof(u_int32_t); ++ DPRINTF("AES ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ default: ++ printk("%s: unimplemented enccrd->crd_alg %d\n", ++ device_get_nameunit(sc->sc_cdev), enccrd->crd_alg); ++ err = EINVAL; ++ goto errout; ++ } ++ /* ++ * Setup encrypt/decrypt state. When using basic ops ++ * we can't use an inline IV because hash/crypt offset ++ * must be from the end of the IV to the start of the ++ * crypt data and this leaves out the preceding header ++ * from the hash calculation. Instead we place the IV ++ * in the state record and set the hash/crypt offset to ++ * copy both the header+IV. ++ */ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ td->hdr |= TALITOS_DIR_OUTBOUND; ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ iv = enccrd->crd_iv; ++ else ++ iv = (caddr_t) ses->ses_iv; ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ } else { ++ td->hdr |= TALITOS_DIR_INBOUND; ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ iv = enccrd->crd_iv; ++ bcopy(enccrd->crd_iv, iv, ivsize); ++ } else { ++ iv = (caddr_t) ses->ses_iv; ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ } ++ td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize, ++ DMA_TO_DEVICE); ++ td->ptr[cipher_iv].len = ivsize; ++ /* ++ * we don't need the cipher iv out length/pointer ++ * field to do ESP IPsec. Therefore we set the len field as 0, ++ * which tells the SEC not to do anything with this len/ptr ++ * field. Previously, when length/pointer as pointing to iv, ++ * it gave us corruption of packets. ++ */ ++ td->ptr[cipher_iv_out].len = 0; ++ } ++ if (enccrd && maccrd) { ++ /* this is ipsec only for now */ ++ td->hdr |= TALITOS_SEL1_MDEU ++ | TALITOS_MODE1_MDEU_INIT ++ | TALITOS_MODE1_MDEU_PAD; ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ td->hdr |= TALITOS_MODE1_MDEU_MD5; ++ break; ++ case CRYPTO_MD5_HMAC: ++ td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC; ++ break; ++ case CRYPTO_SHA1: ++ td->hdr |= TALITOS_MODE1_MDEU_SHA1; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC; ++ break; ++ default: ++ /* We cannot order the SEC as requested */ ++ printk("%s: cannot do the order\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || ++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { ++ /* ++ * The offset from hash data to the start of ++ * crypt data is the difference in the skips. ++ */ ++ /* ipsec only for now */ ++ td->ptr[hmac_key].ptr = dma_map_single(NULL, ++ ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE); ++ td->ptr[hmac_key].len = ses->ses_hmac_len; ++ td->ptr[in_fifo].ptr += enccrd->crd_skip; ++ td->ptr[in_fifo].len = enccrd->crd_len; ++ td->ptr[out_fifo].ptr += enccrd->crd_skip; ++ td->ptr[out_fifo].len = enccrd->crd_len; ++ /* bytes of HMAC to postpend to ciphertext */ ++ td->ptr[out_fifo].extent = ses->ses_mlen; ++ td->ptr[hmac_data].ptr += maccrd->crd_skip; ++ td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip; ++ } ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ } ++ } ++ if (!enccrd && maccrd) { ++ /* single MD5 or SHA */ ++ td->hdr |= TALITOS_SEL0_MDEU ++ | TALITOS_MODE0_MDEU_INIT ++ | TALITOS_MODE0_MDEU_PAD; ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ td->hdr |= TALITOS_MODE0_MDEU_MD5; ++ DPRINTF("MD5 ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_MD5_HMAC: ++ td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC; ++ break; ++ case CRYPTO_SHA1: ++ td->hdr |= TALITOS_MODE0_MDEU_SHA1; ++ DPRINTF("SHA1 ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_SHA1_HMAC: ++ td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC; ++ break; ++ default: ++ /* We cannot order the SEC as requested */ ++ DPRINTF("cannot do the order\n"); ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_IOV) ++ td->ptr[out_fifo].ptr += maccrd->crd_inject; ++ ++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || ++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { ++ td->ptr[hmac_key].ptr = dma_map_single(NULL, ++ ses->ses_hmac, ses->ses_hmac_len, ++ DMA_TO_DEVICE); ++ td->ptr[hmac_key].len = ses->ses_hmac_len; ++ } ++ } ++ else { ++ /* using process key (session data has duplicate) */ ++ td->ptr[cipher_key].ptr = dma_map_single(NULL, ++ enccrd->crd_key, (enccrd->crd_klen + 7) / 8, ++ DMA_TO_DEVICE); ++ td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8; ++ } ++ /* descriptor complete - GO! */ ++ return talitos_submit(sc, td, chsel); ++ ++errout: ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } ++ return err; ++} ++ ++/* go through all channels descriptors, notifying OCF what has ++ * _and_hasn't_ successfully completed and reset the device ++ * (otherwise it's up to decoding desc hdrs!) ++ */ ++static void talitos_errorprocessing(struct talitos_softc *sc) ++{ ++ unsigned long flags; ++ int i, j; ++ ++ /* disable further scheduling until under control */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ if (debug) dump_talitos_status(sc); ++ /* go through descriptors, try and salvage those successfully done, ++ * and EIO those that weren't ++ */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); ++ for (j = 0; j < sc->sc_chfifo_len; j++) { ++ if (sc->sc_chnfifo[i][j].cf_desc.hdr) { ++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr ++ & TALITOS_HDR_DONE_BITS) ++ != TALITOS_HDR_DONE_BITS) { ++ /* this one didn't finish */ ++ /* signify in crp->etype */ ++ sc->sc_chnfifo[i][j].cf_crp->crp_etype ++ = EIO; ++ } ++ } else ++ continue; /* free entry */ ++ /* either way, notify ocf */ ++ crypto_done(sc->sc_chnfifo[i][j].cf_crp); ++ /* and tag it available again ++ * ++ * memset to ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 MD/HMAC processing ++ */ ++ memset(&sc->sc_chnfifo[i][j].cf_desc, ++ 0, sizeof(struct talitos_desc)); ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); ++ } ++ /* reset and initialize the SEC h/w device */ ++ talitos_reset_device(sc); ++ talitos_init_device(sc); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) ++ talitos_rng_init(sc); ++#endif ++ ++ /* Okay. Stand by. */ ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ return; ++} ++ ++/* go through all channels descriptors, notifying OCF what's been done */ ++static void talitos_doneprocessing(struct talitos_softc *sc) ++{ ++ unsigned long flags; ++ int i, j; ++ ++ /* go through descriptors looking for done bits */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); ++ for (j = 0; j < sc->sc_chfifo_len; j++) { ++ /* descriptor has done bits set? */ ++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr ++ & TALITOS_HDR_DONE_BITS) ++ == TALITOS_HDR_DONE_BITS) { ++ /* notify ocf */ ++ crypto_done(sc->sc_chnfifo[i][j].cf_crp); ++ /* and tag it available again ++ * ++ * memset to ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 MD/HMAC processing ++ */ ++ memset(&sc->sc_chnfifo[i][j].cf_desc, ++ 0, sizeof(struct talitos_desc)); ++ } ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); ++ } ++ return; ++} ++ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++talitos_intr(int irq, void *arg) ++#else ++talitos_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct talitos_softc *sc = arg; ++ u_int32_t v, v_hi; ++ ++ /* ack */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); ++ talitos_write(sc->sc_base_addr + TALITOS_ICR, v); ++ talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi); ++ ++ if (unlikely(v & TALITOS_ISR_ERROR)) { ++ /* Okay, Houston, we've had a problem here. */ ++ printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ talitos_errorprocessing(sc); ++ } else ++ if (likely(v & TALITOS_ISR_DONE)) { ++ talitos_doneprocessing(sc); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Initialize registers we need to touch only once. ++ */ ++static void ++talitos_init_device(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* init all channels */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + ++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI); ++ v |= TALITOS_CH_CCCR_HI_CDWE ++ | TALITOS_CH_CCCR_HI_CDIE; /* invoke interrupt if done */ ++ talitos_write(sc->sc_base_addr + ++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v); ++ } ++ /* enable all interrupts */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR); ++ v |= TALITOS_IMR_ALL; ++ talitos_write(sc->sc_base_addr + TALITOS_IMR, v); ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); ++ v |= TALITOS_IMR_HI_ERRONLY; ++ talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v); ++ return; ++} ++ ++/* ++ * set the master reset bit on the device. ++ */ ++static void ++talitos_reset_device_master(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ ++ /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR); ++ talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR); ++ ++ while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR) ++ cpu_relax(); ++ ++ return; ++} ++ ++/* ++ * Resets the device. Values in the registers are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++talitos_reset_device(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* ++ * Master reset ++ * errata documentation: warning: certain SEC interrupts ++ * are not fully cleared by writing the MCR:SWR bit, ++ * set bit twice to completely reset ++ */ ++ talitos_reset_device_master(sc); /* once */ ++ talitos_reset_device_master(sc); /* and once again */ ++ ++ /* reset all channels */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCCR); ++ talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET); ++ } ++} ++ ++/* Set up the crypto device structure, private data, ++ * and anything else we need before we start */ ++#ifdef CONFIG_PPC_MERGE ++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match) ++#else ++static int talitos_probe(struct platform_device *pdev) ++#endif ++{ ++ struct talitos_softc *sc = NULL; ++ struct resource *r; ++#ifdef CONFIG_PPC_MERGE ++ struct device *device = &ofdev->dev; ++ struct device_node *np = ofdev->node; ++ const unsigned int *prop; ++ int err; ++ struct resource res; ++#endif ++ static int num_chips = 0; ++ int rc; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return -ENOMEM; ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, DRV_NAME, num_chips, talitos_methods); ++ ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++#ifndef CONFIG_PPC_MERGE ++ sc->sc_dev = pdev; ++#endif ++ sc->sc_num = num_chips++; ++ ++#ifdef CONFIG_PPC_MERGE ++ dev_set_drvdata(device, sc); ++#else ++ platform_set_drvdata(sc->sc_dev, sc); ++#endif ++ ++ /* get the irq line */ ++#ifdef CONFIG_PPC_MERGE ++ err = of_address_to_resource(np, 0, &res); ++ if (err) ++ return -EINVAL; ++ r = &res; ++ ++ sc->sc_irq = irq_of_parse_and_map(np, 0); ++#else ++ /* get a pointer to the register memory */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ sc->sc_irq = platform_get_irq(pdev, 0); ++#endif ++ rc = request_irq(sc->sc_irq, talitos_intr, 0, ++ device_get_nameunit(sc->sc_cdev), sc); ++ if (rc) { ++ printk(KERN_ERR "%s: failed to hook irq %d\n", ++ device_get_nameunit(sc->sc_cdev), sc->sc_irq); ++ sc->sc_irq = -1; ++ goto out; ++ } ++ ++ sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start)); ++ if (!sc->sc_base_addr) { ++ printk(KERN_ERR "%s: failed to ioremap\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++ ++ /* figure out our SEC's properties and capabilities */ ++ sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32 ++ | talitos_read(sc->sc_base_addr + TALITOS_ID_HI); ++ DPRINTF("sec id 0x%llx\n", sc->sc_chiprev); ++ ++#ifdef CONFIG_PPC_MERGE ++ /* get SEC properties from device tree, defaulting to SEC 2.0 */ ++ ++ prop = of_get_property(np, "num-channels", NULL); ++ sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0; ++ ++ prop = of_get_property(np, "channel-fifo-len", NULL); ++ sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0; ++ ++ prop = of_get_property(np, "exec-units-mask", NULL); ++ sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0; ++ ++ prop = of_get_property(np, "descriptor-types-mask", NULL); ++ sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0; ++#else ++ /* bulk should go away with openfirmware flat device tree support */ ++ if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) { ++ sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0; ++ sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0; ++ sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0; ++ sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0; ++ } else { ++ printk(KERN_ERR "%s: failed to id device\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++#endif ++ ++ /* + 1 is for the meta-channel lock used by the channel scheduler */ ++ sc->sc_chnfifolock = (spinlock_t *) kmalloc( ++ (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL); ++ if (!sc->sc_chnfifolock) ++ goto out; ++ for (i = 0; i < sc->sc_num_channels + 1; i++) { ++ spin_lock_init(&sc->sc_chnfifolock[i]); ++ } ++ ++ sc->sc_chnlastalg = (int *) kmalloc( ++ sc->sc_num_channels * sizeof(int), GFP_KERNEL); ++ if (!sc->sc_chnlastalg) ++ goto out; ++ memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int)); ++ ++ sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc( ++ sc->sc_num_channels * sizeof(struct desc_cryptop_pair *), ++ GFP_KERNEL); ++ if (!sc->sc_chnfifo) ++ goto out; ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc( ++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair), ++ GFP_KERNEL); ++ if (!sc->sc_chnfifo[i]) ++ goto out; ++ memset(sc->sc_chnfifo[i], 0, ++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair)); ++ } ++ ++ /* reset and initialize the SEC h/w device */ ++ talitos_reset_device(sc); ++ talitos_init_device(sc); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ printk(KERN_ERR "%s: could not get crypto driver id\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++ ++ /* register algorithms with the framework */ ++ printk("%s:", device_get_nameunit(sc->sc_cdev)); ++ ++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) { ++ printk(" rng"); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ talitos_rng_init(sc); ++ crypto_rregister(sc->sc_cid, talitos_read_random, sc); ++#endif ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) { ++ printk(" des/3des"); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) { ++ printk(" aes"); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) { ++ printk(" md5"); ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ /* HMAC support only with IPsec for now */ ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ printk(" sha1"); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ /* HMAC support only with IPsec for now */ ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ } ++ printk("\n"); ++ return 0; ++ ++out: ++#ifndef CONFIG_PPC_MERGE ++ talitos_remove(pdev); ++#endif ++ return -ENOMEM; ++} ++ ++#ifdef CONFIG_PPC_MERGE ++static int talitos_remove(struct of_device *ofdev) ++#else ++static int talitos_remove(struct platform_device *pdev) ++#endif ++{ ++#ifdef CONFIG_PPC_MERGE ++ struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev); ++#else ++ struct talitos_softc *sc = platform_get_drvdata(pdev); ++#endif ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_chnfifo) { ++ for (i = 0; i < sc->sc_num_channels; i++) ++ if (sc->sc_chnfifo[i]) ++ kfree(sc->sc_chnfifo[i]); ++ kfree(sc->sc_chnfifo); ++ } ++ if (sc->sc_chnlastalg) ++ kfree(sc->sc_chnlastalg); ++ if (sc->sc_chnfifolock) ++ kfree(sc->sc_chnfifolock); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_base_addr) ++ iounmap((void *) sc->sc_base_addr); ++ kfree(sc); ++ return 0; ++} ++ ++#ifdef CONFIG_PPC_MERGE ++static struct of_device_id talitos_match[] = { ++ { ++ .type = "crypto", ++ .compatible = "talitos", ++ }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, talitos_match); ++ ++static struct of_platform_driver talitos_driver = { ++ .name = DRV_NAME, ++ .match_table = talitos_match, ++ .probe = talitos_probe, ++ .remove = talitos_remove, ++}; ++ ++static int __init talitos_init(void) ++{ ++ return of_register_platform_driver(&talitos_driver); ++} ++ ++static void __exit talitos_exit(void) ++{ ++ of_unregister_platform_driver(&talitos_driver); ++} ++#else ++/* Structure for a platform device driver */ ++static struct platform_driver talitos_driver = { ++ .probe = talitos_probe, ++ .remove = talitos_remove, ++ .driver = { ++ .name = "fsl-sec2", ++ } ++}; ++ ++static int __init talitos_init(void) ++{ ++ return platform_driver_register(&talitos_driver); ++} ++ ++static void __exit talitos_exit(void) ++{ ++ platform_driver_unregister(&talitos_driver); ++} ++#endif ++ ++module_init(talitos_init); ++module_exit(talitos_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("kim.phillips@freescale.com"); ++MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos_dev.h linux-2.6.30/crypto/ocf/talitos/talitos_dev.h +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos_dev.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos_dev.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,277 @@ ++/* ++ * Freescale SEC (talitos) device dependent data structures ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++ ++/* device ID register values */ ++#define TALITOS_ID_SEC_2_0 0x40 ++#define TALITOS_ID_SEC_2_1 0x40 /* cross ref with IP block revision reg */ ++ ++/* ++ * following num_channels, channel-fifo-depth, exec-unit-mask, and ++ * descriptor-types-mask are for forward-compatibility with openfirmware ++ * flat device trees ++ */ ++ ++/* ++ * num_channels : the number of channels available in each SEC version. ++ */ ++ ++/* n.b. this driver requires these values be a power of 2 */ ++#define TALITOS_NCHANNELS_SEC_1_0 4 ++#define TALITOS_NCHANNELS_SEC_1_2 1 ++#define TALITOS_NCHANNELS_SEC_2_0 4 ++#define TALITOS_NCHANNELS_SEC_2_01 4 ++#define TALITOS_NCHANNELS_SEC_2_1 4 ++#define TALITOS_NCHANNELS_SEC_2_4 4 ++ ++/* ++ * channel-fifo-depth : The number of descriptor ++ * pointers a channel fetch fifo can hold. ++ */ ++#define TALITOS_CHFIFOLEN_SEC_1_0 1 ++#define TALITOS_CHFIFOLEN_SEC_1_2 1 ++#define TALITOS_CHFIFOLEN_SEC_2_0 24 ++#define TALITOS_CHFIFOLEN_SEC_2_01 24 ++#define TALITOS_CHFIFOLEN_SEC_2_1 24 ++#define TALITOS_CHFIFOLEN_SEC_2_4 24 ++ ++/* ++ * exec-unit-mask : The bitmask representing what Execution Units (EUs) ++ * are available. EU information should be encoded following the SEC's ++ * EU_SEL0 bitfield documentation, i.e. as follows: ++ * ++ * bit 31 = set if SEC permits no-EU selection (should be always set) ++ * bit 30 = set if SEC has the ARC4 EU (AFEU) ++ * bit 29 = set if SEC has the des/3des EU (DEU) ++ * bit 28 = set if SEC has the message digest EU (MDEU) ++ * bit 27 = set if SEC has the random number generator EU (RNG) ++ * bit 26 = set if SEC has the public key EU (PKEU) ++ * bit 25 = set if SEC has the aes EU (AESU) ++ * bit 24 = set if SEC has the Kasumi EU (KEU) ++ * ++ */ ++#define TALITOS_HAS_EU_NONE (1<<0) ++#define TALITOS_HAS_EU_AFEU (1<<1) ++#define TALITOS_HAS_EU_DEU (1<<2) ++#define TALITOS_HAS_EU_MDEU (1<<3) ++#define TALITOS_HAS_EU_RNG (1<<4) ++#define TALITOS_HAS_EU_PKEU (1<<5) ++#define TALITOS_HAS_EU_AESU (1<<6) ++#define TALITOS_HAS_EU_KEU (1<<7) ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_EUS_SEC_1_0 0x7f ++#define TALITOS_HAS_EUS_SEC_1_2 0x4d ++#define TALITOS_HAS_EUS_SEC_2_0 0x7f ++#define TALITOS_HAS_EUS_SEC_2_01 0x7f ++#define TALITOS_HAS_EUS_SEC_2_1 0xff ++#define TALITOS_HAS_EUS_SEC_2_4 0x7f ++ ++/* ++ * descriptor-types-mask : The bitmask representing what descriptors ++ * are available. Descriptor type information should be encoded ++ * following the SEC's Descriptor Header Dword DESC_TYPE field ++ * documentation, i.e. as follows: ++ * ++ * bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type ++ * bit 1 = set if SEC supports the ipsec_esp descriptor type ++ * bit 2 = set if SEC supports the common_nonsnoop desc. type ++ * bit 3 = set if SEC supports the 802.11i AES ccmp desc. type ++ * bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type ++ * bit 5 = set if SEC supports the srtp descriptor type ++ * bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type ++ * bit 7 = set if SEC supports the pkeu_assemble descriptor type ++ * bit 8 = set if SEC supports the aesu_key_expand_output desc.type ++ * bit 9 = set if SEC supports the pkeu_ptmul descriptor type ++ * bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type ++ * bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type ++ * ++ * ..and so on and so forth. ++ */ ++#define TALITOS_HAS_DT_AESU_CTR_NONSNOOP (1<<0) ++#define TALITOS_HAS_DT_IPSEC_ESP (1<<1) ++#define TALITOS_HAS_DT_COMMON_NONSNOOP (1<<2) ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_DESCTYPES_SEC_2_0 0x01010ebf ++#define TALITOS_HAS_DESCTYPES_SEC_2_1 0x012b0ebf ++ ++/* ++ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register ++ */ ++ ++/* global register offset addresses */ ++#define TALITOS_ID 0x1020 ++#define TALITOS_ID_HI 0x1024 ++#define TALITOS_MCR 0x1030 /* master control register */ ++#define TALITOS_MCR_HI 0x1038 /* master control register */ ++#define TALITOS_MCR_SWR 0x1 ++#define TALITOS_IMR 0x1008 /* interrupt mask register */ ++#define TALITOS_IMR_ALL 0x00010fff /* enable all interrupts mask */ ++#define TALITOS_IMR_ERRONLY 0x00010aaa /* enable error interrupts */ ++#define TALITOS_IMR_HI 0x100C /* interrupt mask register */ ++#define TALITOS_IMR_HI_ALL 0x00323333 /* enable all interrupts mask */ ++#define TALITOS_IMR_HI_ERRONLY 0x00222222 /* enable error interrupts */ ++#define TALITOS_ISR 0x1010 /* interrupt status register */ ++#define TALITOS_ISR_ERROR 0x00010faa /* errors mask */ ++#define TALITOS_ISR_DONE 0x00000055 /* channel(s) done mask */ ++#define TALITOS_ISR_HI 0x1014 /* interrupt status register */ ++#define TALITOS_ICR 0x1018 /* interrupt clear register */ ++#define TALITOS_ICR_HI 0x101C /* interrupt clear register */ ++ ++/* channel register address stride */ ++#define TALITOS_CH_OFFSET 0x100 ++ ++/* channel register offset addresses and bits */ ++#define TALITOS_CH_CCCR 0x1108 /* Crypto-Channel Config Register */ ++#define TALITOS_CH_CCCR_RESET 0x1 /* Channel Reset bit */ ++#define TALITOS_CH_CCCR_HI 0x110c /* Crypto-Channel Config Register */ ++#define TALITOS_CH_CCCR_HI_CDWE 0x10 /* Channel done writeback enable bit */ ++#define TALITOS_CH_CCCR_HI_NT 0x4 /* Notification type bit */ ++#define TALITOS_CH_CCCR_HI_CDIE 0x2 /* Channel Done Interrupt Enable bit */ ++#define TALITOS_CH_CCPSR 0x1110 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_CCPSR_HI 0x1114 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_FF 0x1148 /* Fetch FIFO */ ++#define TALITOS_CH_FF_HI 0x114c /* Fetch FIFO's FETCH_ADRS */ ++#define TALITOS_CH_CDPR 0x1140 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_CDPR_HI 0x1144 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_DESCBUF 0x1180 /* (thru 11bf) Crypto-Channel ++ * Descriptor Buffer (debug) */ ++ ++/* execution unit register offset addresses and bits */ ++#define TALITOS_DEUSR 0x2028 /* DEU status register */ ++#define TALITOS_DEUSR_HI 0x202c /* DEU status register */ ++#define TALITOS_DEUISR 0x2030 /* DEU interrupt status register */ ++#define TALITOS_DEUISR_HI 0x2034 /* DEU interrupt status register */ ++#define TALITOS_DEUICR 0x2038 /* DEU interrupt control register */ ++#define TALITOS_DEUICR_HI 0x203c /* DEU interrupt control register */ ++#define TALITOS_AESUISR 0x4030 /* AESU interrupt status register */ ++#define TALITOS_AESUISR_HI 0x4034 /* AESU interrupt status register */ ++#define TALITOS_AESUICR 0x4038 /* AESU interrupt control register */ ++#define TALITOS_AESUICR_HI 0x403c /* AESU interrupt control register */ ++#define TALITOS_MDEUISR 0x6030 /* MDEU interrupt status register */ ++#define TALITOS_MDEUISR_HI 0x6034 /* MDEU interrupt status register */ ++#define TALITOS_RNGSR 0xa028 /* RNG status register */ ++#define TALITOS_RNGSR_HI 0xa02c /* RNG status register */ ++#define TALITOS_RNGSR_HI_RD 0x1 /* RNG Reset done */ ++#define TALITOS_RNGSR_HI_OFL 0xff0000/* number of dwords in RNG output FIFO*/ ++#define TALITOS_RNGDSR 0xa010 /* RNG data size register */ ++#define TALITOS_RNGDSR_HI 0xa014 /* RNG data size register */ ++#define TALITOS_RNG_FIFO 0xa800 /* RNG FIFO - pool of random numbers */ ++#define TALITOS_RNGISR 0xa030 /* RNG Interrupt status register */ ++#define TALITOS_RNGISR_HI 0xa034 /* RNG Interrupt status register */ ++#define TALITOS_RNGRCR 0xa018 /* RNG Reset control register */ ++#define TALITOS_RNGRCR_HI 0xa01c /* RNG Reset control register */ ++#define TALITOS_RNGRCR_HI_SR 0x1 /* RNG RNGRCR:Software Reset */ ++ ++/* descriptor pointer entry */ ++struct talitos_desc_ptr { ++ u16 len; /* length */ ++ u8 extent; /* jump (to s/g link table) and extent */ ++ u8 res; /* reserved */ ++ u32 ptr; /* pointer */ ++}; ++ ++/* descriptor */ ++struct talitos_desc { ++ u32 hdr; /* header */ ++ u32 res; /* reserved */ ++ struct talitos_desc_ptr ptr[7]; /* ptr/len pair array */ ++}; ++ ++/* talitos descriptor header (hdr) bits */ ++ ++/* primary execution unit select */ ++#define TALITOS_SEL0_AFEU 0x10000000 ++#define TALITOS_SEL0_DEU 0x20000000 ++#define TALITOS_SEL0_MDEU 0x30000000 ++#define TALITOS_SEL0_RNG 0x40000000 ++#define TALITOS_SEL0_PKEU 0x50000000 ++#define TALITOS_SEL0_AESU 0x60000000 ++ ++/* primary execution unit mode (MODE0) and derivatives */ ++#define TALITOS_MODE0_AESU_CBC 0x00200000 ++#define TALITOS_MODE0_AESU_ENC 0x00100000 ++#define TALITOS_MODE0_DEU_CBC 0x00400000 ++#define TALITOS_MODE0_DEU_3DES 0x00200000 ++#define TALITOS_MODE0_DEU_ENC 0x00100000 ++#define TALITOS_MODE0_MDEU_INIT 0x01000000 /* init starting regs */ ++#define TALITOS_MODE0_MDEU_HMAC 0x00800000 ++#define TALITOS_MODE0_MDEU_PAD 0x00400000 /* PD */ ++#define TALITOS_MODE0_MDEU_MD5 0x00200000 ++#define TALITOS_MODE0_MDEU_SHA256 0x00100000 ++#define TALITOS_MODE0_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define TALITOS_MODE0_MDEU_MD5_HMAC \ ++ (TALITOS_MODE0_MDEU_MD5 | TALITOS_MODE0_MDEU_HMAC) ++#define TALITOS_MODE0_MDEU_SHA256_HMAC \ ++ (TALITOS_MODE0_MDEU_SHA256 | TALITOS_MODE0_MDEU_HMAC) ++#define TALITOS_MODE0_MDEU_SHA1_HMAC \ ++ (TALITOS_MODE0_MDEU_SHA1 | TALITOS_MODE0_MDEU_HMAC) ++ ++/* secondary execution unit select (SEL1) */ ++/* it's MDEU or nothing */ ++#define TALITOS_SEL1_MDEU 0x00030000 ++ ++/* secondary execution unit mode (MODE1) and derivatives */ ++#define TALITOS_MODE1_MDEU_INIT 0x00001000 /* init starting regs */ ++#define TALITOS_MODE1_MDEU_HMAC 0x00000800 ++#define TALITOS_MODE1_MDEU_PAD 0x00000400 /* PD */ ++#define TALITOS_MODE1_MDEU_MD5 0x00000200 ++#define TALITOS_MODE1_MDEU_SHA256 0x00000100 ++#define TALITOS_MODE1_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define TALITOS_MODE1_MDEU_MD5_HMAC \ ++ (TALITOS_MODE1_MDEU_MD5 | TALITOS_MODE1_MDEU_HMAC) ++#define TALITOS_MODE1_MDEU_SHA256_HMAC \ ++ (TALITOS_MODE1_MDEU_SHA256 | TALITOS_MODE1_MDEU_HMAC) ++#define TALITOS_MODE1_MDEU_SHA1_HMAC \ ++ (TALITOS_MODE1_MDEU_SHA1 | TALITOS_MODE1_MDEU_HMAC) ++ ++/* direction of overall data flow (DIR) */ ++#define TALITOS_DIR_OUTBOUND 0x00000000 ++#define TALITOS_DIR_INBOUND 0x00000002 ++ ++/* done notification (DN) */ ++#define TALITOS_DONE_NOTIFY 0x00000001 ++ ++/* descriptor types */ ++/* odd numbers here are valid on SEC2 and greater only (e.g. ipsec_esp) */ ++#define TD_TYPE_AESU_CTR_NONSNOOP (0 << 3) ++#define TD_TYPE_IPSEC_ESP (1 << 3) ++#define TD_TYPE_COMMON_NONSNOOP_NO_AFEU (2 << 3) ++#define TD_TYPE_HMAC_SNOOP_NO_AFEU (4 << 3) ++ ++#define TALITOS_HDR_DONE_BITS 0xff000000 ++ ++#define DPRINTF(a...) do { \ ++ if (debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_cdev) : "talitos"); \ ++ printk(a); \ ++ } \ ++ } while (0) +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos_soft.h linux-2.6.30/crypto/ocf/talitos/talitos_soft.h +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos_soft.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos_soft.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,77 @@ ++/* ++ * Freescale SEC data structures for integration with ocf-linux ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * paired descriptor and associated crypto operation ++ */ ++struct desc_cryptop_pair { ++ struct talitos_desc cf_desc; /* descriptor ptr */ ++ struct cryptop *cf_crp; /* cryptop ptr */ ++}; ++ ++/* ++ * Holds data specific to a single talitos device. ++ */ ++struct talitos_softc { ++ softc_device_decl sc_cdev; ++ struct platform_device *sc_dev; /* device backpointer */ ++ ocf_iomem_t sc_base_addr; ++ int sc_irq; ++ int sc_num; /* if we have multiple chips */ ++ int32_t sc_cid; /* crypto tag */ ++ u64 sc_chiprev; /* major/minor chip revision */ ++ int sc_nsessions; ++ struct talitos_session *sc_sessions; ++ int sc_num_channels;/* number of crypto channels */ ++ int sc_chfifo_len; /* channel fetch fifo len */ ++ int sc_exec_units; /* execution units mask */ ++ int sc_desc_types; /* descriptor types mask */ ++ /* ++ * mutual exclusion for intra-channel resources, e.g. fetch fifos ++ * the last entry is a meta-channel lock used by the channel scheduler ++ */ ++ spinlock_t *sc_chnfifolock; ++ /* sc_chnlastalgo contains last algorithm for that channel */ ++ int *sc_chnlastalg; ++ /* sc_chnfifo holds pending descriptor--crypto operation pairs */ ++ struct desc_cryptop_pair **sc_chnfifo; ++}; ++ ++struct talitos_session { ++ u_int32_t ses_used; ++ u_int32_t ses_klen; /* key length in bits */ ++ u_int32_t ses_key[8]; /* DES/3DES/AES key */ ++ u_int32_t ses_hmac[5]; /* hmac inner state */ ++ u_int32_t ses_hmac_len; /* hmac length */ ++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */ ++ u_int32_t ses_mlen; /* desired hash result len (12=ipsec or 16) */ ++}; ++ ++#define TALITOS_SESSION(sid) ((sid) & 0x0fffffff) ++#define TALITOS_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) +diff -Nur linux-2.6.30.orig/crypto/ocf/uio.h linux-2.6.30/crypto/ocf/uio.h +--- linux-2.6.30.orig/crypto/ocf/uio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/uio.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,54 @@ ++#ifndef _OCF_UIO_H_ ++#define _OCF_UIO_H_ ++ ++#include ++ ++/* ++ * The linux uio.h doesn't have all we need. To be fully api compatible ++ * with the BSD cryptodev, we need to keep this around. Perhaps this can ++ * be moved back into the linux/uio.h ++ * ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ * --------------------------------------------------------------------------- ++ */ ++ ++struct uio { ++ struct iovec *uio_iov; ++ int uio_iovcnt; ++ off_t uio_offset; ++ int uio_resid; ++#if 0 ++ enum uio_seg uio_segflg; ++ enum uio_rw uio_rw; ++ struct thread *uio_td; ++#endif ++}; ++ ++#endif +diff -Nur linux-2.6.30.orig/drivers/char/random.c linux-2.6.30/drivers/char/random.c +--- linux-2.6.30.orig/drivers/char/random.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/char/random.c 2009-06-11 10:55:27.000000000 +0200 +@@ -129,6 +129,9 @@ + * unsigned int value); + * void add_interrupt_randomness(int irq); + * ++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++ * int random_input_wait(void); ++ * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * +@@ -140,6 +143,13 @@ + * a better measure, since the timing of the disk interrupts are more + * unpredictable. + * ++ * random_input_words() just provides a raw block of entropy to the input ++ * pool, such as from a hardware entropy generator. ++ * ++ * random_input_wait() suspends the caller until such time as the ++ * entropy pool falls below the write threshold, and returns a count of how ++ * much entropy (in bits) is needed to sustain the pool. ++ * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. +@@ -712,6 +722,61 @@ + } + #endif + ++/* ++ * random_input_words - add bulk entropy to pool ++ * ++ * @buf: buffer to add ++ * @wordcount: number of __u32 words to add ++ * @ent_count: total amount of entropy (in bits) to credit ++ * ++ * this provides bulk input of entropy to the input pool ++ * ++ */ ++void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++{ ++ mix_pool_bytes(&input_pool, buf, wordcount*4); ++ ++ credit_entropy_bits(&input_pool, ent_count); ++ ++ DEBUG_ENT("crediting %d bits => %d\n", ++ ent_count, input_pool.entropy_count); ++ /* ++ * Wake up waiting processes if we have enough ++ * entropy. ++ */ ++ if (input_pool.entropy_count >= random_read_wakeup_thresh) ++ wake_up_interruptible(&random_read_wait); ++} ++EXPORT_SYMBOL(random_input_words); ++ ++/* ++ * random_input_wait - wait until random needs entropy ++ * ++ * this function sleeps until the /dev/random subsystem actually ++ * needs more entropy, and then return the amount of entropy ++ * that it would be nice to have added to the system. ++ */ ++int random_input_wait(void) ++{ ++ int count; ++ ++ wait_event_interruptible(random_write_wait, ++ input_pool.entropy_count < random_write_wakeup_thresh); ++ ++ count = random_write_wakeup_thresh - input_pool.entropy_count; ++ ++ /* likely we got woken up due to a signal */ ++ if (count <= 0) count = random_read_wakeup_thresh; ++ ++ DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n", ++ count, ++ input_pool.entropy_count, random_write_wakeup_thresh); ++ ++ return count; ++} ++EXPORT_SYMBOL(random_input_wait); ++ ++ + #define EXTRACT_SIZE 10 + + /********************************************************************* +diff -Nur linux-2.6.30.orig/fs/fcntl.c linux-2.6.30/fs/fcntl.c +--- linux-2.6.30.orig/fs/fcntl.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/fcntl.c 2009-06-11 10:55:27.000000000 +0200 +@@ -142,6 +142,7 @@ + } + return ret; + } ++EXPORT_SYMBOL(sys_dup); + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +diff -Nur linux-2.6.30.orig/include/linux/miscdevice.h linux-2.6.30/include/linux/miscdevice.h +--- linux-2.6.30.orig/include/linux/miscdevice.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/include/linux/miscdevice.h 2009-06-11 10:55:27.000000000 +0200 +@@ -12,6 +12,7 @@ + #define APOLLO_MOUSE_MINOR 7 + #define PC110PAD_MINOR 9 + /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ ++#define CRYPTODEV_MINOR 70 /* /dev/crypto */ + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 +diff -Nur linux-2.6.30.orig/include/linux/random.h linux-2.6.30/include/linux/random.h +--- linux-2.6.30.orig/include/linux/random.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/include/linux/random.h 2009-06-11 10:55:27.000000000 +0200 +@@ -34,6 +34,30 @@ + /* Clear the entropy pool and associated counters. (Superuser only.) */ + #define RNDCLEARPOOL _IO( 'R', 0x06 ) + ++#ifdef CONFIG_FIPS_RNG ++ ++/* Size of seed value - equal to AES blocksize */ ++#define AES_BLOCK_SIZE_BYTES 16 ++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES ++/* Size of AES key */ ++#define KEY_SIZE_BYTES 16 ++ ++/* ioctl() structure used by FIPS 140-2 Tests */ ++struct rand_fips_test { ++ unsigned char key[KEY_SIZE_BYTES]; /* Input */ ++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char result[SEED_SIZE_BYTES]; /* Output */ ++}; ++ ++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */ ++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test) ++ ++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */ ++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test) ++ ++#endif /* #ifdef CONFIG_FIPS_RNG */ ++ + struct rand_pool_info { + int entropy_count; + int buf_size; +@@ -50,6 +74,10 @@ + unsigned int value); + extern void add_interrupt_randomness(int irq); + ++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count); ++extern int random_input_wait(void); ++#define HAS_RANDOM_INPUT_WAIT 1 ++ + extern void get_random_bytes(void *buf, int nbytes); + void generate_random_uuid(unsigned char uuid_out[16]); + diff --git a/target/linux/patches/2.6.30.1/swconfig.patch b/target/linux/patches/2.6.30.1/swconfig.patch new file mode 100644 index 000000000..3297bb116 --- /dev/null +++ b/target/linux/patches/2.6.30.1/swconfig.patch @@ -0,0 +1,1075 @@ +diff -Nur linux-2.6.30.orig/drivers/net/phy/Kconfig linux-2.6.30/drivers/net/phy/Kconfig +--- linux-2.6.30.orig/drivers/net/phy/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/net/phy/Kconfig 2009-06-11 09:22:50.000000000 +0200 +@@ -13,6 +13,12 @@ + + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ + comment "MII PHY device drivers" + + config MARVELL_PHY +diff -Nur linux-2.6.30.orig/drivers/net/phy/Makefile linux-2.6.30/drivers/net/phy/Makefile +--- linux-2.6.30.orig/drivers/net/phy/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/net/phy/Makefile 2009-06-11 09:22:50.000000000 +0200 +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +diff -Nur linux-2.6.30.orig/drivers/net/phy/swconfig.c linux-2.6.30/drivers/net/phy/swconfig.c +--- linux-2.6.30.orig/drivers/net/phy/swconfig.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/drivers/net/phy/swconfig.c 2009-06-11 09:22:50.000000000 +0200 +@@ -0,0 +1,872 @@ ++/* ++ * swconfig.c: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++#ifdef DEBUG ++#define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__) ++#else ++#define DPRINTF(...) do {} while(0) ++#endif ++ ++MODULE_AUTHOR("Felix Fietkau "); ++MODULE_LICENSE("GPL"); ++ ++static int swdev_id = 0; ++static struct list_head swdevs; ++static spinlock_t swdevs_lock = SPIN_LOCK_UNLOCKED; ++struct swconfig_callback; ++ ++struct swconfig_callback ++{ ++ struct sk_buff *msg; ++ struct genlmsghdr *hdr; ++ struct genl_info *info; ++ int cmd; ++ ++ /* callback for filling in the message data */ ++ int (*fill)(struct swconfig_callback *cb, void *arg); ++ ++ /* callback for closing the message before sending it */ ++ int (*close)(struct swconfig_callback *cb, void *arg); ++ ++ struct nlattr *nest[4]; ++ int args[4]; ++}; ++ ++/* defaults */ ++ ++static int ++swconfig_get_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ int ret; ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ if (!dev->get_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ ret = dev->get_vlan_ports(dev, val); ++ printk("SET PORTS %d\n", val->len); ++ return ret; ++} ++ ++static int ++swconfig_set_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ int i; ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ /* validate ports */ ++ if (val->len > dev->ports) ++ return -EINVAL; ++ ++ for (i = 0; i < val->len; i++) { ++ if (val->value.ports[i].id >= dev->ports) ++ return -EINVAL; ++ } ++ ++ if (!dev->set_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ printk("SET PORTS %d\n", val->len); ++ return dev->set_vlan_ports(dev, val); ++} ++ ++static int ++swconfig_apply_config(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->apply_config) ++ return 0; ++ ++ return dev->apply_config(dev); ++} ++ ++ ++enum global_defaults { ++ GLOBAL_APPLY, ++}; ++ ++enum vlan_defaults { ++ VLAN_PORTS, ++}; ++ ++enum port_defaults { ++ PORT_LINK, ++}; ++ ++static struct switch_attr default_global[] = { ++ [GLOBAL_APPLY] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "apply", ++ .description = "Activate changes in the hardware", ++ .set = swconfig_apply_config, ++ } ++}; ++ ++static struct switch_attr default_port[] = { ++ [PORT_LINK] = { ++ .type = SWITCH_TYPE_INT, ++ .name = "link", ++ .description = "Current link speed", ++ } ++}; ++ ++static struct switch_attr default_vlan[] = { ++ [VLAN_PORTS] = { ++ .type = SWITCH_TYPE_PORTS, ++ .name = "ports", ++ .description = "VLAN port mapping", ++ .set = swconfig_set_vlan_ports, ++ .get = swconfig_get_vlan_ports, ++ }, ++}; ++ ++ ++static void swconfig_defaults_init(struct switch_dev *dev) ++{ ++ dev->def_global = 0; ++ dev->def_vlan = 0; ++ dev->def_port = 0; ++ ++ if (dev->get_vlan_ports || dev->set_vlan_ports) ++ set_bit(VLAN_PORTS, &dev->def_vlan); ++ ++ /* always present, can be no-op */ ++ set_bit(GLOBAL_APPLY, &dev->def_global); ++} ++ ++ ++static struct genl_family switch_fam = { ++ .id = GENL_ID_GENERATE, ++ .name = "switch", ++ .hdrsize = 0, ++ .version = 1, ++ .maxattr = SWITCH_ATTR_MAX, ++}; ++ ++static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { ++ [SWITCH_ATTR_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, ++ [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, ++ [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, ++}; ++ ++static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { ++ [SWITCH_PORT_ID] = { .type = NLA_U32 }, ++ [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, ++}; ++ ++static inline void ++swconfig_lock(void) ++{ ++ spin_lock(&swdevs_lock); ++} ++ ++static inline void ++swconfig_unlock(void) ++{ ++ spin_unlock(&swdevs_lock); ++} ++ ++static struct switch_dev * ++swconfig_get_dev(struct genl_info *info) ++{ ++ struct switch_dev *dev = NULL; ++ struct switch_dev *p; ++ int id; ++ ++ if (!info->attrs[SWITCH_ATTR_ID]) ++ goto done; ++ ++ id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); ++ swconfig_lock(); ++ list_for_each_entry(p, &swdevs, dev_list) { ++ if (id != p->id) ++ continue; ++ ++ dev = p; ++ break; ++ } ++ if (dev) ++ spin_lock(&dev->lock); ++ else ++ DPRINTF("device %d not found\n", id); ++ swconfig_unlock(); ++done: ++ return dev; ++} ++ ++static inline void ++swconfig_put_dev(struct switch_dev *dev) ++{ ++ spin_unlock(&dev->lock); ++} ++ ++static int ++swconfig_dump_attr(struct swconfig_callback *cb, void *arg) ++{ ++ struct switch_attr *op = arg; ++ struct genl_info *info = cb->info; ++ struct sk_buff *msg = cb->msg; ++ int id = cb->args[0]; ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id); ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name); ++ if (op->description) ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION, ++ op->description); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++/* spread multipart messages across multiple message buffers */ ++static int ++swconfig_send_multipart(struct swconfig_callback *cb, void *arg) ++{ ++ struct genl_info *info = cb->info; ++ int restart = 0; ++ int err; ++ ++ do { ++ if (!cb->msg) { ++ cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (cb->msg == NULL) ++ goto error; ++ } ++ ++ if (!(cb->fill(cb, arg) < 0)) ++ break; ++ ++ /* fill failed, check if this was already the second attempt */ ++ if (restart) ++ goto error; ++ ++ /* try again in a new message, send the current one */ ++ restart = 1; ++ if (cb->close) { ++ if (cb->close(cb, arg) < 0) ++ goto error; ++ } ++ err = genlmsg_unicast(cb->msg, info->snd_pid); ++ cb->msg = NULL; ++ if (err < 0) ++ goto error; ++ ++ } while (restart); ++ ++ return 0; ++ ++error: ++ if (cb->msg) ++ nlmsg_free(cb->msg); ++ return -1; ++} ++ ++static int ++swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_dev *dev; ++ struct swconfig_callback cb; ++ int err = -EINVAL; ++ int i; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_LIST_GLOBAL: ++ alist = &dev->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_LIST_VLAN: ++ alist = &dev->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ break; ++ case SWITCH_CMD_LIST_PORT: ++ alist = &dev->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ break; ++ default: ++ WARN_ON(1); ++ goto out; ++ } ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.info = info; ++ cb.fill = swconfig_dump_attr; ++ for (i = 0; i < alist->n_attr; i++) { ++ if (alist->attr[i].disabled) ++ continue; ++ cb.args[0] = i; ++ err = swconfig_send_multipart(&cb, &alist->attr[i]); ++ if (err < 0) ++ goto error; ++ } ++ ++ /* defaults */ ++ for (i = 0; i < n_def; i++) { ++ if (!test_bit(i, def_active)) ++ continue; ++ cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; ++ err = swconfig_send_multipart(&cb, &def_list[i]); ++ if (err < 0) ++ goto error; ++ } ++ swconfig_put_dev(dev); ++ ++ if (!cb.msg) ++ return 0; ++ ++ return genlmsg_unicast(cb.msg, info->snd_pid); ++ ++error: ++ if (cb.msg) ++ nlmsg_free(cb.msg); ++out: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static struct switch_attr * ++swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, ++ struct switch_val *val) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_attr *attr = NULL; ++ int attr_id; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ if (!info->attrs[SWITCH_ATTR_OP_ID]) ++ goto done; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_SET_GLOBAL: ++ case SWITCH_CMD_GET_GLOBAL: ++ alist = &dev->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_SET_VLAN: ++ case SWITCH_CMD_GET_VLAN: ++ alist = &dev->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ if (!info->attrs[SWITCH_ATTR_OP_VLAN]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); ++ break; ++ case SWITCH_CMD_SET_PORT: ++ case SWITCH_CMD_GET_PORT: ++ alist = &dev->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ if (!info->attrs[SWITCH_ATTR_OP_PORT]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); ++ break; ++ default: ++ WARN_ON(1); ++ goto done; ++ } ++ ++ if (!alist) ++ goto done; ++ ++ attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); ++ if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { ++ attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; ++ if (attr_id >= n_def) ++ goto done; ++ if (!test_bit(attr_id, def_active)) ++ goto done; ++ attr = &def_list[attr_id]; ++ } else { ++ if (attr_id >= alist->n_attr) ++ goto done; ++ attr = &alist->attr[attr_id]; ++ } ++ ++ if (attr->disabled) ++ attr = NULL; ++ ++done: ++ if (!attr) ++ DPRINTF("attribute lookup failed\n"); ++ val->attr = attr; ++ return attr; ++} ++ ++static int ++swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, ++ struct switch_val *val, int max) ++{ ++ struct nlattr *nla; ++ int rem; ++ ++ val->len = 0; ++ nla_for_each_nested(nla, head, rem) { ++ struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; ++ struct switch_port *port = &val->value.ports[val->len]; ++ ++ if (val->len >= max) ++ return -EINVAL; ++ ++ if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, ++ port_policy)) ++ return -EINVAL; ++ ++ if (!tb[SWITCH_PORT_ID]) ++ return -EINVAL; ++ ++ port->id = nla_get_u32(tb[SWITCH_PORT_ID]); ++ if (tb[SWITCH_PORT_FLAG_TAGGED]) ++ port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ } ++ ++ return 0; ++} ++ ++static int ++swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct switch_val val; ++ int err = -EINVAL; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->set) ++ goto error; ++ ++ val.attr = attr; ++ switch(attr->type) { ++ case SWITCH_TYPE_NOVAL: ++ break; ++ case SWITCH_TYPE_INT: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) ++ goto error; ++ val.value.i = ++ nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); ++ break; ++ case SWITCH_TYPE_STRING: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) ++ goto error; ++ val.value.s = ++ nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); ++ break; ++ case SWITCH_TYPE_PORTS: ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ ++ /* TODO: implement multipart? */ ++ if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { ++ err = swconfig_parse_ports(skb, ++ info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports); ++ if (err < 0) ++ goto error; ++ } else { ++ val.len = 0; ++ err = 0; ++ } ++ break; ++ default: ++ goto error; ++ } ++ ++ err = attr->set(dev, attr, &val); ++error: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static int ++swconfig_close_portlist(struct swconfig_callback *cb, void *arg) ++{ ++ if (cb->nest[0]) ++ nla_nest_end(cb->msg, cb->nest[0]); ++ return 0; ++} ++ ++static int ++swconfig_send_port(struct swconfig_callback *cb, void *arg) ++{ ++ const struct switch_port *port = arg; ++ struct nlattr *p = NULL; ++ ++ if (!cb->nest[0]) { ++ cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); ++ if (!cb->nest[0]) ++ return -1; ++ } ++ ++ p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); ++ if (!p) ++ goto error; ++ ++ NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id); ++ if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ++ NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED); ++ ++ nla_nest_end(cb->msg, p); ++ return 0; ++ ++nla_put_failure: ++ nla_nest_cancel(cb->msg, p); ++error: ++ nla_nest_cancel(cb->msg, cb->nest[0]); ++ return -1; ++} ++ ++static int ++swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, ++ const struct switch_val *val) ++{ ++ struct swconfig_callback cb; ++ int err = 0; ++ int i; ++ ++ if (!val->value.ports) ++ return -EINVAL; ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.cmd = attr; ++ cb.msg = *msg; ++ cb.info = info; ++ cb.fill = swconfig_send_port; ++ cb.close = swconfig_close_portlist; ++ ++ cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); ++ for (i = 0; i < val->len; i++) { ++ err = swconfig_send_multipart(&cb, &val->value.ports[i]); ++ if (err) ++ goto done; ++ } ++ err = val->len; ++ swconfig_close_portlist(&cb, NULL); ++ *msg = cb.msg; ++ ++done: ++ return err; ++} ++ ++static int ++swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct sk_buff *msg = NULL; ++ struct switch_val val; ++ int err = -EINVAL; ++ int cmd = hdr->cmd; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->get) ++ goto error_dev; ++ ++ if (attr->type == SWITCH_TYPE_PORTS) { ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ } ++ ++ err = attr->get(dev, attr, &val); ++ if (err) ++ goto error; ++ ++ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (!msg) ++ goto error; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ 0, cmd); ++ if (IS_ERR(hdr)) ++ goto nla_put_failure; ++ ++ switch(attr->type) { ++ case SWITCH_TYPE_INT: ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i); ++ break; ++ case SWITCH_TYPE_STRING: ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s); ++ break; ++ case SWITCH_TYPE_PORTS: ++ err = swconfig_send_ports(&msg, info, ++ SWITCH_ATTR_OP_VALUE_PORTS, &val); ++ if (err < 0) ++ goto nla_put_failure; ++ break; ++ default: ++ DPRINTF("invalid type in attribute\n"); ++ err = -EINVAL; ++ goto error; ++ } ++ err = genlmsg_end(msg, hdr); ++ if (err < 0) ++ goto nla_put_failure; ++ ++ swconfig_put_dev(dev); ++ return genlmsg_unicast(msg, info->snd_pid); ++ ++nla_put_failure: ++ if (msg) ++ nlmsg_free(msg); ++error_dev: ++ swconfig_put_dev(dev); ++error: ++ if (!err) ++ err = -ENOMEM; ++ return err; ++} ++ ++static int ++swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, ++ const struct switch_dev *dev) ++{ ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, ++ SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname); ++ NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans); ++ NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static int swconfig_dump_switches(struct sk_buff *skb, ++ struct netlink_callback *cb) ++{ ++ struct switch_dev *dev; ++ int start = cb->args[0]; ++ int idx = 0; ++ ++ swconfig_lock(); ++ list_for_each_entry(dev, &swdevs, dev_list) { ++ if (++idx <= start) ++ continue; ++ if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid, ++ cb->nlh->nlmsg_seq, NLM_F_MULTI, ++ dev) < 0) ++ break; ++ } ++ swconfig_unlock(); ++ cb->args[0] = idx; ++ ++ return skb->len; ++} ++ ++static int ++swconfig_done(struct netlink_callback *cb) ++{ ++ return 0; ++} ++ ++static struct genl_ops swconfig_ops[] = { ++ { ++ .cmd = SWITCH_CMD_LIST_GLOBAL, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_VLAN, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_PORT, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_GLOBAL, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_VLAN, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_PORT, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_GLOBAL, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_VLAN, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_PORT, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_SWITCH, ++ .dumpit = swconfig_dump_switches, ++ .policy = switch_policy, ++ .done = swconfig_done, ++ } ++}; ++ ++int ++register_switch(struct switch_dev *dev, struct net_device *netdev) ++{ ++ INIT_LIST_HEAD(&dev->dev_list); ++ if (netdev) { ++ dev->netdev = netdev; ++ if (!dev->devname) ++ dev->devname = netdev->name; ++ } ++ BUG_ON(!dev->devname); ++ ++ if (dev->ports > 0) { ++ dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports, ++ GFP_KERNEL); ++ if (!dev->portbuf) ++ return -ENOMEM; ++ } ++ dev->id = ++swdev_id; ++ swconfig_defaults_init(dev); ++ spin_lock_init(&dev->lock); ++ swconfig_lock(); ++ list_add(&dev->dev_list, &swdevs); ++ swconfig_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(register_switch); ++ ++void ++unregister_switch(struct switch_dev *dev) ++{ ++ kfree(dev->portbuf); ++ spin_lock(&dev->lock); ++ swconfig_lock(); ++ list_del(&dev->dev_list); ++ swconfig_unlock(); ++} ++EXPORT_SYMBOL_GPL(unregister_switch); ++ ++ ++static int __init ++swconfig_init(void) ++{ ++ int i, err; ++ ++ INIT_LIST_HEAD(&swdevs); ++ err = genl_register_family(&switch_fam); ++ if (err) ++ return err; ++ ++ for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) { ++ err = genl_register_ops(&switch_fam, &swconfig_ops[i]); ++ if (err) ++ goto unregister; ++ } ++ ++ return 0; ++ ++unregister: ++ genl_unregister_family(&switch_fam); ++ return err; ++} ++ ++static void __exit ++swconfig_exit(void) ++{ ++ genl_unregister_family(&switch_fam); ++} ++ ++module_init(swconfig_init); ++module_exit(swconfig_exit); ++ +diff -Nur linux-2.6.30.orig/include/linux/switch.h linux-2.6.30/include/linux/switch.h +--- linux-2.6.30.orig/include/linux/switch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/include/linux/switch.h 2009-06-11 09:22:50.000000000 +0200 +@@ -0,0 +1,168 @@ ++/* ++ * switch.h: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * 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. ++ */ ++ ++#ifndef __LINUX_SWITCH_H ++#define __LINUX_SWITCH_H ++ ++#include ++#include ++#include ++#include ++#ifndef __KERNEL__ ++#include ++#include ++#include ++#else ++#include ++#endif ++ ++/* main attributes */ ++enum { ++ SWITCH_ATTR_UNSPEC, ++ /* global */ ++ SWITCH_ATTR_TYPE, ++ /* device */ ++ SWITCH_ATTR_ID, ++ SWITCH_ATTR_NAME, ++ SWITCH_ATTR_DEV_NAME, ++ SWITCH_ATTR_VLANS, ++ SWITCH_ATTR_PORTS, ++ /* attributes */ ++ SWITCH_ATTR_OP_ID, ++ SWITCH_ATTR_OP_TYPE, ++ SWITCH_ATTR_OP_NAME, ++ SWITCH_ATTR_OP_PORT, ++ SWITCH_ATTR_OP_VLAN, ++ SWITCH_ATTR_OP_VALUE_INT, ++ SWITCH_ATTR_OP_VALUE_STR, ++ SWITCH_ATTR_OP_VALUE_PORTS, ++ SWITCH_ATTR_OP_DESCRIPTION, ++ /* port lists */ ++ SWITCH_ATTR_PORT, ++ SWITCH_ATTR_MAX ++}; ++ ++/* commands */ ++enum { ++ SWITCH_CMD_UNSPEC, ++ SWITCH_CMD_GET_SWITCH, ++ SWITCH_CMD_NEW_ATTR, ++ SWITCH_CMD_LIST_GLOBAL, ++ SWITCH_CMD_GET_GLOBAL, ++ SWITCH_CMD_SET_GLOBAL, ++ SWITCH_CMD_LIST_PORT, ++ SWITCH_CMD_GET_PORT, ++ SWITCH_CMD_SET_PORT, ++ SWITCH_CMD_LIST_VLAN, ++ SWITCH_CMD_GET_VLAN, ++ SWITCH_CMD_SET_VLAN ++}; ++ ++/* data types */ ++enum switch_val_type { ++ SWITCH_TYPE_UNSPEC, ++ SWITCH_TYPE_INT, ++ SWITCH_TYPE_STRING, ++ SWITCH_TYPE_PORTS, ++ SWITCH_TYPE_NOVAL, ++}; ++ ++/* port nested attributes */ ++enum { ++ SWITCH_PORT_UNSPEC, ++ SWITCH_PORT_ID, ++ SWITCH_PORT_FLAG_TAGGED, ++ SWITCH_PORT_ATTR_MAX ++}; ++ ++#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 ++ ++#ifdef __KERNEL__ ++ ++struct switch_dev; ++struct switch_op; ++struct switch_val; ++struct switch_attr; ++struct switch_attrlist; ++ ++int register_switch(struct switch_dev *dev, struct net_device *netdev); ++void unregister_switch(struct switch_dev *dev); ++ ++struct switch_attrlist { ++ /* filled in by the driver */ ++ int n_attr; ++ struct switch_attr *attr; ++}; ++ ++ ++struct switch_dev { ++ int id; ++ void *priv; ++ const char *name; ++ ++ /* NB: either devname or netdev must be set */ ++ const char *devname; ++ struct net_device *netdev; ++ ++ int ports; ++ int vlans; ++ int cpu_port; ++ struct switch_attrlist attr_global, attr_port, attr_vlan; ++ ++ spinlock_t lock; ++ struct switch_port *portbuf; ++ struct list_head dev_list; ++ unsigned long def_global, def_port, def_vlan; ++ ++ int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*apply_config)(struct switch_dev *dev); ++}; ++ ++struct switch_port { ++ u32 id; ++ u32 flags; ++}; ++ ++struct switch_val { ++ struct switch_attr *attr; ++ int port_vlan; ++ int len; ++ union { ++ const char *s; ++ u32 i; ++ struct switch_port *ports; ++ } value; ++}; ++ ++struct switch_attr { ++ int disabled; ++ int type; ++ const char *name; ++ const char *description; ++ ++ int (*set)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); ++ int (*get)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); ++ ++ /* for driver internal use */ ++ int id; ++ int ofs; ++ int max; ++}; ++ ++#endif ++ ++#endif diff --git a/target/linux/patches/2.6.30.1/yaffs2.patch b/target/linux/patches/2.6.30.1/yaffs2.patch new file mode 100644 index 000000000..a19ab9c84 --- /dev/null +++ b/target/linux/patches/2.6.30.1/yaffs2.patch @@ -0,0 +1,15066 @@ +diff -Nur linux-2.6.30.orig/fs/Kconfig linux-2.6.30/fs/Kconfig +--- linux-2.6.30.orig/fs/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/Kconfig 2009-06-11 09:21:04.000000000 +0200 +@@ -162,6 +162,10 @@ + source "fs/befs/Kconfig" + source "fs/bfs/Kconfig" + source "fs/efs/Kconfig" ++ ++# Patched by YAFFS ++source "fs/yaffs2/Kconfig" ++ + source "fs/jffs2/Kconfig" + # UBIFS File system configuration + source "fs/ubifs/Kconfig" +diff -Nur linux-2.6.30.orig/fs/Makefile linux-2.6.30/fs/Makefile +--- linux-2.6.30.orig/fs/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/Makefile 2009-06-11 09:21:31.000000000 +0200 +@@ -124,3 +124,4 @@ + obj-$(CONFIG_BTRFS_FS) += btrfs/ + obj-$(CONFIG_GFS2_FS) += gfs2/ + obj-$(CONFIG_EXOFS_FS) += exofs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ +diff -Nur linux-2.6.30.orig/fs/Makefile.pre.yaffs linux-2.6.30/fs/Makefile.pre.yaffs +--- linux-2.6.30.orig/fs/Makefile.pre.yaffs 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/Makefile.pre.yaffs 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,126 @@ ++# ++# Makefile for the Linux filesystems. ++# ++# 14 Sep 2000, Christoph Hellwig ++# Rewritten to use lists instead of if-statements. ++# ++ ++obj-y := open.o read_write.o file_table.o super.o \ ++ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ++ ioctl.o readdir.o select.o fifo.o dcache.o inode.o \ ++ attr.o bad_inode.o file.o filesystems.o namespace.o \ ++ seq_file.o xattr.o libfs.o fs-writeback.o \ ++ pnode.o drop_caches.o splice.o sync.o utimes.o \ ++ stack.o ++ ++ifeq ($(CONFIG_BLOCK),y) ++obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o ++else ++obj-y += no-block.o ++endif ++ ++obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o ++obj-y += notify/ ++obj-$(CONFIG_EPOLL) += eventpoll.o ++obj-$(CONFIG_ANON_INODES) += anon_inodes.o ++obj-$(CONFIG_SIGNALFD) += signalfd.o ++obj-$(CONFIG_TIMERFD) += timerfd.o ++obj-$(CONFIG_EVENTFD) += eventfd.o ++obj-$(CONFIG_AIO) += aio.o ++obj-$(CONFIG_FILE_LOCKING) += locks.o ++obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o ++ ++nfsd-$(CONFIG_NFSD) := nfsctl.o ++obj-y += $(nfsd-y) $(nfsd-m) ++ ++obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o ++obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o ++obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o ++ ++# binfmt_script is always there ++obj-y += binfmt_script.o ++ ++obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o ++obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o ++obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o ++obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o ++obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o ++ ++obj-$(CONFIG_FS_MBCACHE) += mbcache.o ++obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o ++obj-$(CONFIG_NFS_COMMON) += nfs_common/ ++obj-$(CONFIG_GENERIC_ACL) += generic_acl.o ++ ++obj-$(CONFIG_QUOTA) += dquot.o ++obj-$(CONFIG_QFMT_V1) += quota_v1.o ++obj-$(CONFIG_QFMT_V2) += quota_v2.o ++obj-$(CONFIG_QUOTA_TREE) += quota_tree.o ++obj-$(CONFIG_QUOTACTL) += quota.o ++ ++obj-$(CONFIG_PROC_FS) += proc/ ++obj-y += partitions/ ++obj-$(CONFIG_SYSFS) += sysfs/ ++obj-$(CONFIG_CONFIGFS_FS) += configfs/ ++obj-y += devpts/ ++ ++obj-$(CONFIG_PROFILING) += dcookies.o ++obj-$(CONFIG_DLM) += dlm/ ++ ++# Do not add any filesystems before this line ++obj-$(CONFIG_REISERFS_FS) += reiserfs/ ++obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 ++obj-$(CONFIG_EXT2_FS) += ext2/ ++# We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2 ++# unless explicitly requested by rootfstype ++obj-$(CONFIG_EXT4_FS) += ext4/ ++obj-$(CONFIG_JBD) += jbd/ ++obj-$(CONFIG_JBD2) += jbd2/ ++obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ ++obj-y += ramfs/ ++obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ ++obj-$(CONFIG_CODA_FS) += coda/ ++obj-$(CONFIG_MINIX_FS) += minix/ ++obj-$(CONFIG_FAT_FS) += fat/ ++obj-$(CONFIG_BFS_FS) += bfs/ ++obj-$(CONFIG_ISO9660_FS) += isofs/ ++obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ ++obj-$(CONFIG_HFS_FS) += hfs/ ++obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ ++obj-$(CONFIG_VXFS_FS) += freevxfs/ ++obj-$(CONFIG_NFS_FS) += nfs/ ++obj-$(CONFIG_EXPORTFS) += exportfs/ ++obj-$(CONFIG_NFSD) += nfsd/ ++obj-$(CONFIG_LOCKD) += lockd/ ++obj-$(CONFIG_NLS) += nls/ ++obj-$(CONFIG_SYSV_FS) += sysv/ ++obj-$(CONFIG_SMB_FS) += smbfs/ ++obj-$(CONFIG_CIFS) += cifs/ ++obj-$(CONFIG_NCP_FS) += ncpfs/ ++obj-$(CONFIG_HPFS_FS) += hpfs/ ++obj-$(CONFIG_NTFS_FS) += ntfs/ ++obj-$(CONFIG_UFS_FS) += ufs/ ++obj-$(CONFIG_EFS_FS) += efs/ ++obj-$(CONFIG_JFFS2_FS) += jffs2/ ++obj-$(CONFIG_UBIFS_FS) += ubifs/ ++obj-$(CONFIG_AFFS_FS) += affs/ ++obj-$(CONFIG_ROMFS_FS) += romfs/ ++obj-$(CONFIG_QNX4FS_FS) += qnx4/ ++obj-$(CONFIG_AUTOFS_FS) += autofs/ ++obj-$(CONFIG_AUTOFS4_FS) += autofs4/ ++obj-$(CONFIG_ADFS_FS) += adfs/ ++obj-$(CONFIG_FUSE_FS) += fuse/ ++obj-$(CONFIG_UDF_FS) += udf/ ++obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ ++obj-$(CONFIG_OMFS_FS) += omfs/ ++obj-$(CONFIG_JFS_FS) += jfs/ ++obj-$(CONFIG_XFS_FS) += xfs/ ++obj-$(CONFIG_9P_FS) += 9p/ ++obj-$(CONFIG_AFS_FS) += afs/ ++obj-$(CONFIG_BEFS_FS) += befs/ ++obj-$(CONFIG_HOSTFS) += hostfs/ ++obj-$(CONFIG_HPPFS) += hppfs/ ++obj-$(CONFIG_DEBUG_FS) += debugfs/ ++obj-$(CONFIG_OCFS2_FS) += ocfs2/ ++obj-$(CONFIG_BTRFS_FS) += btrfs/ ++obj-$(CONFIG_GFS2_FS) += gfs2/ +diff -Nur linux-2.6.30.orig/fs/yaffs2/devextras.h linux-2.6.30/fs/yaffs2/devextras.h +--- linux-2.6.30.orig/fs/yaffs2/devextras.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/devextras.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,196 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This file is just holds extra declarations of macros that would normally ++ * be providesd in the Linux kernel. These macros have been written from ++ * scratch but are functionally equivalent to the Linux ones. ++ * ++ */ ++ ++#ifndef __EXTRAS_H__ ++#define __EXTRAS_H__ ++ ++ ++#if !(defined __KERNEL__) ++ ++/* Definition of types */ ++typedef unsigned char __u8; ++typedef unsigned short __u16; ++typedef unsigned __u32; ++ ++#endif ++ ++/* ++ * This is a simple doubly linked list implementation that matches the ++ * way the Linux kernel doubly linked list implementation works. ++ */ ++ ++struct ylist_head { ++ struct ylist_head *next; /* next in chain */ ++ struct ylist_head *prev; /* previous in chain */ ++}; ++ ++ ++/* Initialise a static list */ ++#define YLIST_HEAD(name) \ ++struct ylist_head name = { &(name), &(name)} ++ ++ ++ ++/* Initialise a list head to an empty list */ ++#define YINIT_LIST_HEAD(p) \ ++do { \ ++ (p)->next = (p);\ ++ (p)->prev = (p); \ ++} while (0) ++ ++ ++/* Add an element to a list */ ++static __inline__ void ylist_add(struct ylist_head *newEntry, ++ struct ylist_head *list) ++{ ++ struct ylist_head *listNext = list->next; ++ ++ list->next = newEntry; ++ newEntry->prev = list; ++ newEntry->next = listNext; ++ listNext->prev = newEntry; ++ ++} ++ ++static __inline__ void ylist_add_tail(struct ylist_head *newEntry, ++ struct ylist_head *list) ++{ ++ struct ylist_head *listPrev = list->prev; ++ ++ list->prev = newEntry; ++ newEntry->next = list; ++ newEntry->prev = listPrev; ++ listPrev->next = newEntry; ++ ++} ++ ++ ++/* Take an element out of its current list, with or without ++ * reinitialising the links.of the entry*/ ++static __inline__ void ylist_del(struct ylist_head *entry) ++{ ++ struct ylist_head *listNext = entry->next; ++ struct ylist_head *listPrev = entry->prev; ++ ++ listNext->prev = listPrev; ++ listPrev->next = listNext; ++ ++} ++ ++static __inline__ void ylist_del_init(struct ylist_head *entry) ++{ ++ ylist_del(entry); ++ entry->next = entry->prev = entry; ++} ++ ++ ++/* Test if the list is empty */ ++static __inline__ int ylist_empty(struct ylist_head *entry) ++{ ++ return (entry->next == entry); ++} ++ ++ ++/* ylist_entry takes a pointer to a list entry and offsets it to that ++ * we can find a pointer to the object it is embedded in. ++ */ ++ ++ ++#define ylist_entry(entry, type, member) \ ++ ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) ++ ++ ++/* ylist_for_each and list_for_each_safe iterate over lists. ++ * ylist_for_each_safe uses temporary storage to make the list delete safe ++ */ ++ ++#define ylist_for_each(itervar, list) \ ++ for (itervar = (list)->next; itervar != (list); itervar = itervar->next) ++ ++#define ylist_for_each_safe(itervar, saveVar, list) \ ++ for (itervar = (list)->next, saveVar = (list)->next->next; \ ++ itervar != (list); itervar = saveVar, saveVar = saveVar->next) ++ ++ ++#if !(defined __KERNEL__) ++ ++ ++#ifndef WIN32 ++#include ++#endif ++ ++ ++#ifdef CONFIG_YAFFS_PROVIDE_DEFS ++/* File types */ ++ ++ ++#define DT_UNKNOWN 0 ++#define DT_FIFO 1 ++#define DT_CHR 2 ++#define DT_DIR 4 ++#define DT_BLK 6 ++#define DT_REG 8 ++#define DT_LNK 10 ++#define DT_SOCK 12 ++#define DT_WHT 14 ++ ++ ++#ifndef WIN32 ++#include ++#endif ++ ++/* ++ * Attribute flags. These should be or-ed together to figure out what ++ * has been changed! ++ */ ++#define ATTR_MODE 1 ++#define ATTR_UID 2 ++#define ATTR_GID 4 ++#define ATTR_SIZE 8 ++#define ATTR_ATIME 16 ++#define ATTR_MTIME 32 ++#define ATTR_CTIME 64 ++ ++struct iattr { ++ unsigned int ia_valid; ++ unsigned ia_mode; ++ unsigned ia_uid; ++ unsigned ia_gid; ++ unsigned ia_size; ++ unsigned ia_atime; ++ unsigned ia_mtime; ++ unsigned ia_ctime; ++ unsigned int ia_attr_flags; ++}; ++ ++#endif ++ ++#else ++ ++#include ++#include ++#include ++ ++#endif ++ ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/Kconfig linux-2.6.30/fs/yaffs2/Kconfig +--- linux-2.6.30.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/Kconfig 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,156 @@ ++# ++# YAFFS file system configurations ++# ++ ++config YAFFS_FS ++ tristate "YAFFS2 file system support" ++ default n ++ depends on MTD_BLOCK ++ select YAFFS_YAFFS1 ++ select YAFFS_YAFFS2 ++ help ++ YAFFS2, or Yet Another Flash Filing System, is a filing system ++ optimised for NAND Flash chips. ++ ++ To compile the YAFFS2 file system support as a module, choose M ++ here: the module will be called yaffs2. ++ ++ If unsure, say N. ++ ++ Further information on YAFFS2 is available at ++ . ++ ++config YAFFS_YAFFS1 ++ bool "512 byte / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable YAFFS1 support -- yaffs for 512 byte / page devices ++ ++ Not needed for 2K-page devices. ++ ++ If unsure, say Y. ++ ++config YAFFS_9BYTE_TAGS ++ bool "Use older-style on-NAND data format with pageStatus byte" ++ depends on YAFFS_YAFFS1 ++ default n ++ help ++ ++ Older-style on-NAND data format has a "pageStatus" byte to record ++ chunk/page state. This byte is zero when the page is discarded. ++ Choose this option if you have existing on-NAND data using this ++ format that you need to continue to support. New data written ++ also uses the older-style format. Note: Use of this option ++ generally requires that MTD's oob layout be adjusted to use the ++ older-style format. See notes on tags formats and MTD versions ++ in yaffs_mtdif1.c. ++ ++ If unsure, say N. ++ ++config YAFFS_DOES_ECC ++ bool "Lets Yaffs do its own ECC" ++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This enables Yaffs to use its own ECC functions instead of using ++ the ones from the generic MTD-NAND driver. ++ ++ If unsure, say N. ++ ++config YAFFS_ECC_WRONG_ORDER ++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" ++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This makes yaffs_ecc.c use the same ecc byte order as Steven ++ Hill's nand_ecc.c. If not set, then you get the same ecc byte ++ order as SmartMedia. ++ ++ If unsure, say N. ++ ++config YAFFS_YAFFS2 ++ bool "2048 byte (or larger) / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices ++ ++ If unsure, say Y. ++ ++config YAFFS_AUTO_YAFFS2 ++ bool "Autoselect yaffs2 format" ++ depends on YAFFS_YAFFS2 ++ default y ++ help ++ Without this, you need to explicitely use yaffs2 as the file ++ system type. With this, you can say "yaffs" and yaffs or yaffs2 ++ will be used depending on the device page size (yaffs on ++ 512-byte page devices, yaffs2 on 2K page devices). ++ ++ If unsure, say Y. ++ ++config YAFFS_DISABLE_LAZY_LOAD ++ bool "Disable lazy loading" ++ depends on YAFFS_YAFFS2 ++ default n ++ help ++ "Lazy loading" defers loading file details until they are ++ required. This saves mount time, but makes the first look-up ++ a bit longer. ++ ++ Lazy loading will only happen if enabled by this option being 'n' ++ and if the appropriate tags are available, else yaffs2 will ++ automatically fall back to immediate loading and do the right ++ thing. ++ ++ Lazy laoding will be required by checkpointing. ++ ++ Setting this to 'y' will disable lazy loading. ++ ++ If unsure, say N. ++ ++ ++config YAFFS_DISABLE_WIDE_TNODES ++ bool "Turn off wide tnodes" ++ depends on YAFFS_FS ++ default n ++ help ++ Wide tnodes are only used for NAND arrays >=32MB for 512-byte ++ page devices and >=128MB for 2k page devices. They use slightly ++ more RAM but are faster since they eliminate chunk group ++ searching. ++ ++ Setting this to 'y' will force tnode width to 16 bits and save ++ memory but make large arrays slower. ++ ++ If unsure, say N. ++ ++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bool "Force chunk erase check" ++ depends on YAFFS_FS ++ default n ++ help ++ Normally YAFFS only checks chunks before writing until an erased ++ chunk is found. This helps to detect any partially written ++ chunks that might have happened due to power loss. ++ ++ Enabling this forces on the test that chunks are erased in flash ++ before writing to them. This takes more time but is potentially ++ a bit more secure. ++ ++ Suggest setting Y during development and ironing out driver ++ issues etc. Suggest setting to N if you want faster writing. ++ ++ If unsure, say Y. ++ ++config YAFFS_SHORT_NAMES_IN_RAM ++ bool "Cache short names in RAM" ++ depends on YAFFS_FS ++ default y ++ help ++ If this config is set, then short names are stored with the ++ yaffs_Object. This costs an extra 16 bytes of RAM per object, ++ but makes look-ups faster. ++ ++ If unsure, say Y. +diff -Nur linux-2.6.30.orig/fs/yaffs2/Makefile linux-2.6.30/fs/yaffs2/Makefile +--- linux-2.6.30.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/Makefile 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux YAFFS filesystem routines. ++# ++ ++obj-$(CONFIG_YAFFS_FS) += yaffs.o ++ ++yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o ++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o ++yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o ++yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +diff -Nur linux-2.6.30.orig/fs/yaffs2/moduleconfig.h linux-2.6.30/fs/yaffs2/moduleconfig.h +--- linux-2.6.30.orig/fs/yaffs2/moduleconfig.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/moduleconfig.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Martin Fouts ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CONFIG_H__ ++#define __YAFFS_CONFIG_H__ ++ ++#ifdef YAFFS_OUT_OF_TREE ++ ++/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */ ++#define CONFIG_YAFFS_FS ++#define CONFIG_YAFFS_YAFFS1 ++#define CONFIG_YAFFS_YAFFS2 ++ ++/* These options are independent of each other. Select those that matter. */ ++ ++/* Default: Not selected */ ++/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ ++/* #define CONFIG_YAFFS_DOES_ECC */ ++ ++/* Default: Not selected */ ++/* Meaning: ECC byte order is 'wrong'. Only meaningful if */ ++/* CONFIG_YAFFS_DOES_ECC is set */ ++/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ ++ ++/* Default: Selected */ ++/* Meaning: Disables testing whether chunks are erased before writing to them*/ ++#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK ++ ++/* Default: Selected */ ++/* Meaning: Cache short names, taking more RAM, but faster look-ups */ ++#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ ++/* Default: 10 */ ++/* Meaning: set the count of blocks to reserve for checkpointing */ ++#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 ++ ++/* ++Older-style on-NAND data format has a "pageStatus" byte to record ++chunk/page state. This byte is zeroed when the page is discarded. ++Choose this option if you have existing on-NAND data in this format ++that you need to continue to support. New data written also uses the ++older-style format. ++Note: Use of this option generally requires that MTD's oob layout be ++adjusted to use the older-style format. See notes on tags formats and ++MTD versions in yaffs_mtdif1.c. ++*/ ++/* Default: Not selected */ ++/* Meaning: Use older-style on-NAND data format with pageStatus byte */ ++/* #define CONFIG_YAFFS_9BYTE_TAGS */ ++ ++#endif /* YAFFS_OUT_OF_TREE */ ++ ++#endif /* __YAFFS_CONFIG_H__ */ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,394 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_checkptrw_c_version = ++ "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $"; ++ ++ ++#include "yaffs_checkptrw.h" ++#include "yaffs_getblockinfo.h" ++ ++static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) ++{ ++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; ++ ++ T(YAFFS_TRACE_CHECKPOINT, ++ (TSTR("checkpt blocks available = %d" TENDSTR), ++ blocksAvailable)); ++ ++ return (blocksAvailable <= 0) ? 0 : 1; ++} ++ ++ ++static int yaffs_CheckpointErase(yaffs_Device *dev) ++{ ++ int i; ++ ++ if (!dev->eraseBlockInNAND) ++ return 0; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), ++ dev->internalStartBlock, dev->internalEndBlock)); ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i)); ++ if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { ++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } else { ++ dev->markNANDBlockBad(dev, i); ++ bi->blockState = YAFFS_BLOCK_STATE_DEAD; ++ } ++ } ++ } ++ ++ dev->blocksInCheckpoint = 0; ++ ++ return 1; ++} ++ ++ ++static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) ++{ ++ int i; ++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; ++ T(YAFFS_TRACE_CHECKPOINT, ++ (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), ++ dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); ++ ++ if (dev->checkpointNextBlock >= 0 && ++ dev->checkpointNextBlock <= dev->internalEndBlock && ++ blocksAvailable > 0) { ++ ++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { ++ dev->checkpointNextBlock = i + 1; ++ dev->checkpointCurrentBlock = i; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i)); ++ return; ++ } ++ } ++ } ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR))); ++ ++ dev->checkpointNextBlock = -1; ++ dev->checkpointCurrentBlock = -1; ++} ++ ++static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) ++{ ++ int i; ++ yaffs_ExtendedTags tags; ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), ++ dev->blocksInCheckpoint, dev->checkpointNextBlock)); ++ ++ if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) ++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { ++ int chunk = i * dev->nChunksPerBlock; ++ int realignedChunk = chunk - dev->chunkOffset; ++ ++ dev->readChunkWithTagsFromNAND(dev, realignedChunk, ++ NULL, &tags); ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), ++ i, tags.objectId, tags.sequenceNumber, tags.eccResult)); ++ ++ if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) { ++ /* Right kind of block */ ++ dev->checkpointNextBlock = tags.objectId; ++ dev->checkpointCurrentBlock = i; ++ dev->checkpointBlockList[dev->blocksInCheckpoint] = i; ++ dev->blocksInCheckpoint++; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i)); ++ return; ++ } ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR))); ++ ++ dev->checkpointNextBlock = -1; ++ dev->checkpointCurrentBlock = -1; ++} ++ ++ ++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) ++{ ++ ++ /* Got the functions we need? */ ++ if (!dev->writeChunkWithTagsToNAND || ++ !dev->readChunkWithTagsFromNAND || ++ !dev->eraseBlockInNAND || ++ !dev->markNANDBlockBad) ++ return 0; ++ ++ if (forWriting && !yaffs_CheckpointSpaceOk(dev)) ++ return 0; ++ ++ if (!dev->checkpointBuffer) ++ dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ ++ dev->checkpointPageSequence = 0; ++ ++ dev->checkpointOpenForWrite = forWriting; ++ ++ dev->checkpointByteCount = 0; ++ dev->checkpointSum = 0; ++ dev->checkpointXor = 0; ++ dev->checkpointCurrentBlock = -1; ++ dev->checkpointCurrentChunk = -1; ++ dev->checkpointNextBlock = dev->internalStartBlock; ++ ++ /* Erase all the blocks in the checkpoint area */ ++ if (forWriting) { ++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); ++ dev->checkpointByteOffset = 0; ++ return yaffs_CheckpointErase(dev); ++ } else { ++ int i; ++ /* Set to a value that will kick off a read */ ++ dev->checkpointByteOffset = dev->nDataBytesPerChunk; ++ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) ++ * going to be way more than we need */ ++ dev->blocksInCheckpoint = 0; ++ dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; ++ dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); ++ for (i = 0; i < dev->checkpointMaxBlocks; i++) ++ dev->checkpointBlockList[i] = -1; ++ } ++ ++ return 1; ++} ++ ++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) ++{ ++ __u32 compositeSum; ++ compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); ++ *sum = compositeSum; ++ return 1; ++} ++ ++static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) ++{ ++ int chunk; ++ int realignedChunk; ++ ++ yaffs_ExtendedTags tags; ++ ++ if (dev->checkpointCurrentBlock < 0) { ++ yaffs_CheckpointFindNextErasedBlock(dev); ++ dev->checkpointCurrentChunk = 0; ++ } ++ ++ if (dev->checkpointCurrentBlock < 0) ++ return 0; ++ ++ tags.chunkDeleted = 0; ++ tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ ++ tags.chunkId = dev->checkpointPageSequence + 1; ++ tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA; ++ tags.byteCount = dev->nDataBytesPerChunk; ++ if (dev->checkpointCurrentChunk == 0) { ++ /* First chunk we write for the block? Set block state to ++ checkpoint */ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock); ++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; ++ dev->blocksInCheckpoint++; ++ } ++ ++ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; ++ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), ++ chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId)); ++ ++ realignedChunk = chunk - dev->chunkOffset; ++ ++ dev->writeChunkWithTagsToNAND(dev, realignedChunk, ++ dev->checkpointBuffer, &tags); ++ dev->checkpointByteOffset = 0; ++ dev->checkpointPageSequence++; ++ dev->checkpointCurrentChunk++; ++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { ++ dev->checkpointCurrentChunk = 0; ++ dev->checkpointCurrentBlock = -1; ++ } ++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); ++ ++ return 1; ++} ++ ++ ++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) ++{ ++ int i = 0; ++ int ok = 1; ++ ++ ++ __u8 * dataBytes = (__u8 *)data; ++ ++ ++ ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ if (!dev->checkpointOpenForWrite) ++ return -1; ++ ++ while (i < nBytes && ok) { ++ dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes; ++ dev->checkpointSum += *dataBytes; ++ dev->checkpointXor ^= *dataBytes; ++ ++ dev->checkpointByteOffset++; ++ i++; ++ dataBytes++; ++ dev->checkpointByteCount++; ++ ++ ++ if (dev->checkpointByteOffset < 0 || ++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) ++ ok = yaffs_CheckpointFlushBuffer(dev); ++ } ++ ++ return i; ++} ++ ++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) ++{ ++ int i = 0; ++ int ok = 1; ++ yaffs_ExtendedTags tags; ++ ++ ++ int chunk; ++ int realignedChunk; ++ ++ __u8 *dataBytes = (__u8 *)data; ++ ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ if (dev->checkpointOpenForWrite) ++ return -1; ++ ++ while (i < nBytes && ok) { ++ ++ ++ if (dev->checkpointByteOffset < 0 || ++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { ++ ++ if (dev->checkpointCurrentBlock < 0) { ++ yaffs_CheckpointFindNextCheckpointBlock(dev); ++ dev->checkpointCurrentChunk = 0; ++ } ++ ++ if (dev->checkpointCurrentBlock < 0) ++ ok = 0; ++ else { ++ chunk = dev->checkpointCurrentBlock * ++ dev->nChunksPerBlock + ++ dev->checkpointCurrentChunk; ++ ++ realignedChunk = chunk - dev->chunkOffset; ++ ++ /* read in the next chunk */ ++ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ ++ dev->readChunkWithTagsFromNAND(dev, ++ realignedChunk, ++ dev->checkpointBuffer, ++ &tags); ++ ++ if (tags.chunkId != (dev->checkpointPageSequence + 1) || ++ tags.eccResult > YAFFS_ECC_RESULT_FIXED || ++ tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ ok = 0; ++ ++ dev->checkpointByteOffset = 0; ++ dev->checkpointPageSequence++; ++ dev->checkpointCurrentChunk++; ++ ++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) ++ dev->checkpointCurrentBlock = -1; ++ } ++ } ++ ++ if (ok) { ++ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; ++ dev->checkpointSum += *dataBytes; ++ dev->checkpointXor ^= *dataBytes; ++ dev->checkpointByteOffset++; ++ i++; ++ dataBytes++; ++ dev->checkpointByteCount++; ++ } ++ } ++ ++ return i; ++} ++ ++int yaffs_CheckpointClose(yaffs_Device *dev) ++{ ++ ++ if (dev->checkpointOpenForWrite) { ++ if (dev->checkpointByteOffset != 0) ++ yaffs_CheckpointFlushBuffer(dev); ++ } else { ++ int i; ++ for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]); ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) ++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; ++ else { ++ /* Todo this looks odd... */ ++ } ++ } ++ YFREE(dev->checkpointBlockList); ++ dev->checkpointBlockList = NULL; ++ } ++ ++ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; ++ dev->nErasedBlocks -= dev->blocksInCheckpoint; ++ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR), ++ dev->checkpointByteCount)); ++ ++ if (dev->checkpointBuffer) { ++ /* free the buffer */ ++ YFREE(dev->checkpointBuffer); ++ dev->checkpointBuffer = NULL; ++ return 1; ++ } else ++ return 0; ++} ++ ++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) ++{ ++ /* Erase the first checksum block */ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR))); ++ ++ if (!yaffs_CheckpointSpaceOk(dev)) ++ return 0; ++ ++ return yaffs_CheckpointErase(dev); ++} ++ ++ ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CHECKPTRW_H__ ++#define __YAFFS_CHECKPTRW_H__ ++ ++#include "yaffs_guts.h" ++ ++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); ++ ++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); ++ ++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); ++ ++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); ++ ++int yaffs_CheckpointClose(yaffs_Device *dev); ++ ++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); ++ ++ ++#endif ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.30/fs/yaffs2/yaffs_ecc.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_ecc.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,326 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC ++ * blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++/* Table generated by gen-ecc.c ++ * Using a table means we do not have to calculate p1..p4 and p1'..p4' ++ * for each byte of data. These are instead provided in a table in bits7..2. ++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore ++ * this bytes influence on the line parity. ++ */ ++ ++const char *yaffs_ecc_c_version = ++ "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++#include "yaffs_ecc.h" ++ ++static const unsigned char column_parity_table[] = { ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++}; ++ ++/* Count the bits in an unsigned char or a U32 */ ++ ++static int yaffs_CountBits(unsigned char x) ++{ ++ int r = 0; ++ while (x) { ++ if (x & 1) ++ r++; ++ x >>= 1; ++ } ++ return r; ++} ++ ++static int yaffs_CountBits32(unsigned x) ++{ ++ int r = 0; ++ while (x) { ++ if (x & 1) ++ r++; ++ x >>= 1; ++ } ++ return r; ++} ++ ++/* Calculate the ECC for a 256-byte block of data */ ++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) ++{ ++ unsigned int i; ++ ++ unsigned char col_parity = 0; ++ unsigned char line_parity = 0; ++ unsigned char line_parity_prime = 0; ++ unsigned char t; ++ unsigned char b; ++ ++ for (i = 0; i < 256; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ } ++ ++ ecc[2] = (~col_parity) | 0x03; ++ ++ t = 0; ++ if (line_parity & 0x80) ++ t |= 0x80; ++ if (line_parity_prime & 0x80) ++ t |= 0x40; ++ if (line_parity & 0x40) ++ t |= 0x20; ++ if (line_parity_prime & 0x40) ++ t |= 0x10; ++ if (line_parity & 0x20) ++ t |= 0x08; ++ if (line_parity_prime & 0x20) ++ t |= 0x04; ++ if (line_parity & 0x10) ++ t |= 0x02; ++ if (line_parity_prime & 0x10) ++ t |= 0x01; ++ ecc[1] = ~t; ++ ++ t = 0; ++ if (line_parity & 0x08) ++ t |= 0x80; ++ if (line_parity_prime & 0x08) ++ t |= 0x40; ++ if (line_parity & 0x04) ++ t |= 0x20; ++ if (line_parity_prime & 0x04) ++ t |= 0x10; ++ if (line_parity & 0x02) ++ t |= 0x08; ++ if (line_parity_prime & 0x02) ++ t |= 0x04; ++ if (line_parity & 0x01) ++ t |= 0x02; ++ if (line_parity_prime & 0x01) ++ t |= 0x01; ++ ecc[0] = ~t; ++ ++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER ++ /* Swap the bytes into the wrong order */ ++ t = ecc[0]; ++ ecc[0] = ecc[1]; ++ ecc[1] = t; ++#endif ++} ++ ++ ++/* Correct the ECC on a 256 byte block of data */ ++ ++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc) ++{ ++ unsigned char d0, d1, d2; /* deltas */ ++ ++ d0 = read_ecc[0] ^ test_ecc[0]; ++ d1 = read_ecc[1] ^ test_ecc[1]; ++ d2 = read_ecc[2] ^ test_ecc[2]; ++ ++ if ((d0 | d1 | d2) == 0) ++ return 0; /* no error */ ++ ++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && ++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && ++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { ++ /* Single bit (recoverable) error in data */ ++ ++ unsigned byte; ++ unsigned bit; ++ ++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER ++ /* swap the bytes to correct for the wrong order */ ++ unsigned char t; ++ ++ t = d0; ++ d0 = d1; ++ d1 = t; ++#endif ++ ++ bit = byte = 0; ++ ++ if (d1 & 0x80) ++ byte |= 0x80; ++ if (d1 & 0x20) ++ byte |= 0x40; ++ if (d1 & 0x08) ++ byte |= 0x20; ++ if (d1 & 0x02) ++ byte |= 0x10; ++ if (d0 & 0x80) ++ byte |= 0x08; ++ if (d0 & 0x20) ++ byte |= 0x04; ++ if (d0 & 0x08) ++ byte |= 0x02; ++ if (d0 & 0x02) ++ byte |= 0x01; ++ ++ if (d2 & 0x80) ++ bit |= 0x04; ++ if (d2 & 0x20) ++ bit |= 0x02; ++ if (d2 & 0x08) ++ bit |= 0x01; ++ ++ data[byte] ^= (1 << bit); ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ if ((yaffs_CountBits(d0) + ++ yaffs_CountBits(d1) + ++ yaffs_CountBits(d2)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ read_ecc[0] = test_ecc[0]; ++ read_ecc[1] = test_ecc[1]; ++ read_ecc[2] = test_ecc[2]; ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++ ++} ++ ++ ++/* ++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data ++ */ ++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *eccOther) ++{ ++ unsigned int i; ++ ++ unsigned char col_parity = 0; ++ unsigned line_parity = 0; ++ unsigned line_parity_prime = 0; ++ unsigned char b; ++ ++ for (i = 0; i < nBytes; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { ++ /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ ++ } ++ ++ eccOther->colParity = (col_parity >> 2) & 0x3f; ++ eccOther->lineParity = line_parity; ++ eccOther->lineParityPrime = line_parity_prime; ++} ++ ++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *read_ecc, ++ const yaffs_ECCOther *test_ecc) ++{ ++ unsigned char cDelta; /* column parity delta */ ++ unsigned lDelta; /* line parity delta */ ++ unsigned lDeltaPrime; /* line parity delta */ ++ unsigned bit; ++ ++ cDelta = read_ecc->colParity ^ test_ecc->colParity; ++ lDelta = read_ecc->lineParity ^ test_ecc->lineParity; ++ lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime; ++ ++ if ((cDelta | lDelta | lDeltaPrime) == 0) ++ return 0; /* no error */ ++ ++ if (lDelta == ~lDeltaPrime && ++ (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) { ++ /* Single bit (recoverable) error in data */ ++ ++ bit = 0; ++ ++ if (cDelta & 0x20) ++ bit |= 0x04; ++ if (cDelta & 0x08) ++ bit |= 0x02; ++ if (cDelta & 0x02) ++ bit |= 0x01; ++ ++ if (lDelta >= nBytes) ++ return -1; ++ ++ data[lDelta] ^= (1 << bit); ++ ++ return 1; /* corrected */ ++ } ++ ++ if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + ++ yaffs_CountBits(cDelta)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ *read_ecc = *test_ecc; ++ return 1; /* corrected */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.30/fs/yaffs2/yaffs_ecc.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_ecc.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC ++ * blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#ifndef __YAFFS_ECC_H__ ++#define __YAFFS_ECC_H__ ++ ++typedef struct { ++ unsigned char colParity; ++ unsigned lineParity; ++ unsigned lineParityPrime; ++} yaffs_ECCOther; ++ ++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); ++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc); ++ ++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *ecc); ++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *read_ecc, ++ const yaffs_ECCOther *test_ecc); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c linux-2.6.30/fs/yaffs2/yaffs_fs.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_fs.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,2529 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2009 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * Acknowledgements: ++ * Luc van OostenRyck for numerous patches. ++ * Nick Bane for numerous patches. ++ * Nick Bane for 2.5/2.6 integration. ++ * Andras Toth for mknod rdev issue. ++ * Michael Fischer for finding the problem with inode inconsistency. ++ * Some code bodily lifted from JFFS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * ++ * This is the file system front-end to YAFFS that hooks it up to ++ * the VFS. ++ * ++ * Special notes: ++ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with ++ * this superblock ++ * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this ++ * superblock ++ * >> inode->u.generic_ip points to the associated yaffs_Object. ++ */ ++ ++const char *yaffs_fs_c_version = ++ "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $"; ++extern const char *yaffs_guts_c_version; ++ ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "asm/div64.h" ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++#include /* Added NCB 15-8-2003 */ ++#include ++#define UnlockPage(p) unlock_page(p) ++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) ++ ++/* FIXME: use sb->s_id instead ? */ ++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) ++ ++#else ++ ++#include ++#define BDEVNAME_SIZE 0 ++#define yaffs_devname(sb, buf) kdevname(sb->s_dev) ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) ++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ ++#define __user ++#endif ++ ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define YPROC_ROOT (&proc_root) ++#else ++#define YPROC_ROOT NULL ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++#define WRITE_SIZE_STR "writesize" ++#define WRITE_SIZE(mtd) ((mtd)->writesize) ++#else ++#define WRITE_SIZE_STR "oobblock" ++#define WRITE_SIZE(mtd) ((mtd)->oobblock) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) ++#define YAFFS_USE_WRITE_BEGIN_END 1 ++#else ++#define YAFFS_USE_WRITE_BEGIN_END 0 ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) ++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) ++{ ++ uint64_t result = partition_size; ++ do_div(result, block_size); ++ return (uint32_t)result; ++} ++#else ++#define YCALCBLOCKS(s, b) ((s)/(b)) ++#endif ++ ++#include ++ ++#include "yportenv.h" ++#include "yaffs_guts.h" ++ ++#include ++#include "yaffs_mtdif.h" ++#include "yaffs_mtdif1.h" ++#include "yaffs_mtdif2.h" ++ ++unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; ++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; ++unsigned int yaffs_auto_checkpoint = 1; ++ ++/* Module Parameters */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++module_param(yaffs_traceMask, uint, 0644); ++module_param(yaffs_wr_attempts, uint, 0644); ++module_param(yaffs_auto_checkpoint, uint, 0644); ++#else ++MODULE_PARM(yaffs_traceMask, "i"); ++MODULE_PARM(yaffs_wr_attempts, "i"); ++MODULE_PARM(yaffs_auto_checkpoint, "i"); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++/* use iget and read_inode */ ++#define Y_IGET(sb, inum) iget((sb), (inum)) ++static void yaffs_read_inode(struct inode *inode); ++ ++#else ++/* Call local equivalent */ ++#define YAFFS_USE_OWN_IGET ++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); ++#endif ++ ++/*#define T(x) printk x */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) ++#else ++#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip) ++#endif ++ ++#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) ++#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info) ++#else ++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) ++#endif ++ ++static void yaffs_put_super(struct super_block *sb); ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t *pos); ++static ssize_t yaffs_hold_space(struct file *f); ++static void yaffs_release_space(struct file *f); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id); ++#else ++static int yaffs_file_flush(struct file *file); ++#endif ++ ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync); ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n); ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n); ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); ++#endif ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry); ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry); ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname); ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t dev); ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int dev); ++#endif ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry); ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait); ++static void yaffs_write_super(struct super_block *sb); ++#else ++static int yaffs_sync_fs(struct super_block *sb); ++static int yaffs_write_super(struct super_block *sb); ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf); ++#endif ++ ++#ifdef YAFFS_HAS_PUT_INODE ++static void yaffs_put_inode(struct inode *inode); ++#endif ++ ++static void yaffs_delete_inode(struct inode *); ++static void yaffs_clear_inode(struct inode *); ++ ++static int yaffs_readpage(struct file *file, struct page *page); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc); ++#else ++static int yaffs_writepage(struct page *page); ++#endif ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END != 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata); ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata); ++#else ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to); ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to); ++ ++#endif ++ ++static int yaffs_readlink(struct dentry *dentry, char __user *buffer, ++ int buflen); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); ++#endif ++ ++static struct address_space_operations yaffs_file_address_operations = { ++ .readpage = yaffs_readpage, ++ .writepage = yaffs_writepage, ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++ .write_begin = yaffs_write_begin, ++ .write_end = yaffs_write_end, ++#else ++ .prepare_write = yaffs_prepare_write, ++ .commit_write = yaffs_commit_write, ++#endif ++}; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = generic_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .sendfile = generic_file_sendfile, ++}; ++ ++#else ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = generic_file_read, ++ .write = generic_file_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ .sendfile = generic_file_sendfile, ++#endif ++}; ++#endif ++ ++static const struct inode_operations yaffs_file_inode_operations = { ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct inode_operations yaffs_symlink_inode_operations = { ++ .readlink = yaffs_readlink, ++ .follow_link = yaffs_follow_link, ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct inode_operations yaffs_dir_inode_operations = { ++ .create = yaffs_create, ++ .lookup = yaffs_lookup, ++ .link = yaffs_link, ++ .unlink = yaffs_unlink, ++ .symlink = yaffs_symlink, ++ .mkdir = yaffs_mkdir, ++ .rmdir = yaffs_unlink, ++ .mknod = yaffs_mknod, ++ .rename = yaffs_rename, ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct file_operations yaffs_dir_operations = { ++ .read = generic_read_dir, ++ .readdir = yaffs_readdir, ++ .fsync = yaffs_sync_object, ++}; ++ ++static const struct super_operations yaffs_super_ops = { ++ .statfs = yaffs_statfs, ++ ++#ifndef YAFFS_USE_OWN_IGET ++ .read_inode = yaffs_read_inode, ++#endif ++#ifdef YAFFS_HAS_PUT_INODE ++ .put_inode = yaffs_put_inode, ++#endif ++ .put_super = yaffs_put_super, ++ .delete_inode = yaffs_delete_inode, ++ .clear_inode = yaffs_clear_inode, ++ .sync_fs = yaffs_sync_fs, ++ .write_super = yaffs_write_super, ++}; ++ ++static void yaffs_GrossLock(yaffs_Device *dev) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); ++ down(&dev->grossLock); ++ T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); ++} ++ ++static void yaffs_GrossUnlock(yaffs_Device *dev) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); ++ up(&dev->grossLock); ++} ++ ++static int yaffs_readlink(struct dentry *dentry, char __user *buffer, ++ int buflen) ++{ ++ unsigned char *alias; ++ int ret; ++ ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (!alias) ++ return -ENOMEM; ++ ++ ret = vfs_readlink(dentry, buffer, buflen, alias); ++ kfree(alias); ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++#endif ++{ ++ unsigned char *alias; ++ int ret; ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (!alias) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = vfs_follow_link(nd, alias); ++ kfree(alias); ++out: ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ return ERR_PTR(ret); ++#else ++ return ret; ++#endif ++} ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ yaffs_Object *obj); ++ ++/* ++ * Lookup is used to find objects in the fs ++ */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n) ++#else ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) ++#endif ++{ ++ yaffs_Object *obj; ++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ ++ ++ yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_lookup for %d:%s\n", ++ yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); ++ ++ obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), ++ dentry->d_name.name); ++ ++ obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ ++ ++ /* Can't hold gross lock when calling yaffs_get_inode() */ ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_lookup found %d\n", obj->objectId)); ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ ++ if (inode) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_loookup dentry \n")); ++/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to ++ * d_add even if NULL inode */ ++#if 0 ++ /*dget(dentry); // try to solve directory bug */ ++ d_add(dentry, inode); ++ ++ /* return dentry; */ ++ return NULL; ++#endif ++ } ++ ++ } else { ++ T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); ++ ++ } ++ ++/* added NCB for 2.5/6 compatability - forces add even if inode is ++ * NULL which creates dentry hash */ ++ d_add(dentry, inode); ++ ++ return NULL; ++} ++ ++ ++#ifdef YAFFS_HAS_PUT_INODE ++ ++/* For now put inode is just for debugging ++ * Put inode is called when the inode **structure** is put. ++ */ ++static void yaffs_put_inode(struct inode *inode) ++{ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count))); ++ ++} ++#endif ++ ++/* clear is called to tell the fs to release any per-inode data it holds */ ++static void yaffs_clear_inode(struct inode *inode) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ obj = yaffs_InodeToObject(inode); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object")); ++ ++ if (obj) { ++ dev = obj->myDev; ++ yaffs_GrossLock(dev); ++ ++ /* Clear the association between the inode and ++ * the yaffs_Object. ++ */ ++ obj->myInode = NULL; ++ yaffs_InodeToObjectLV(inode) = NULL; ++ ++ /* If the object freeing was deferred, then the real ++ * free happens now. ++ * This should fix the inode inconsistency problem. ++ */ ++ ++ yaffs_HandleDeferedFree(obj); ++ ++ yaffs_GrossUnlock(dev); ++ } ++ ++} ++ ++/* delete is called when the link count is zero and the inode ++ * is put (ie. nobody wants to know about it anymore, time to ++ * delete the file). ++ * NB Must call clear_inode() ++ */ ++static void yaffs_delete_inode(struct inode *inode) ++{ ++ yaffs_Object *obj = yaffs_InodeToObject(inode); ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object")); ++ ++ if (obj) { ++ dev = obj->myDev; ++ yaffs_GrossLock(dev); ++ yaffs_DeleteObject(obj); ++ yaffs_GrossUnlock(dev); ++ } ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ truncate_inode_pages(&inode->i_data, 0); ++#endif ++ clear_inode(inode); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id) ++#else ++static int yaffs_file_flush(struct file *file) ++#endif ++{ ++ yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); ++ ++ yaffs_Device *dev = obj->myDev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_flush object %d (%s)\n", obj->objectId, ++ obj->dirty ? "dirty" : "clean")); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushFile(obj, 1); ++ ++ yaffs_GrossUnlock(dev); ++ ++ return 0; ++} ++ ++static int yaffs_readpage_nolock(struct file *f, struct page *pg) ++{ ++ /* Lifted from jffs2 */ ++ ++ yaffs_Object *obj; ++ unsigned char *pg_buf; ++ int ret; ++ ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n", ++ (unsigned)(pg->index << PAGE_CACHE_SHIFT), ++ (unsigned)PAGE_CACHE_SIZE)); ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ BUG_ON(!PageLocked(pg)); ++#else ++ if (!PageLocked(pg)) ++ PAGE_BUG(pg); ++#endif ++ ++ pg_buf = kmap(pg); ++ /* FIXME: Can kmap fail? */ ++ ++ yaffs_GrossLock(dev); ++ ++ ret = yaffs_ReadDataFromFile(obj, pg_buf, ++ pg->index << PAGE_CACHE_SHIFT, ++ PAGE_CACHE_SIZE); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (ret >= 0) ++ ret = 0; ++ ++ if (ret) { ++ ClearPageUptodate(pg); ++ SetPageError(pg); ++ } else { ++ SetPageUptodate(pg); ++ ClearPageError(pg); ++ } ++ ++ flush_dcache_page(pg); ++ kunmap(pg); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); ++ return ret; ++} ++ ++static int yaffs_readpage_unlock(struct file *f, struct page *pg) ++{ ++ int ret = yaffs_readpage_nolock(f, pg); ++ UnlockPage(pg); ++ return ret; ++} ++ ++static int yaffs_readpage(struct file *f, struct page *pg) ++{ ++ return yaffs_readpage_unlock(f, pg); ++} ++ ++/* writepage inspired by/stolen from smbfs */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc) ++#else ++static int yaffs_writepage(struct page *page) ++#endif ++{ ++ struct address_space *mapping = page->mapping; ++ loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; ++ struct inode *inode; ++ unsigned long end_index; ++ char *buffer; ++ yaffs_Object *obj; ++ int nWritten = 0; ++ unsigned nBytes; ++ ++ if (!mapping) ++ BUG(); ++ inode = mapping->host; ++ if (!inode) ++ BUG(); ++ ++ if (offset > inode->i_size) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_writepage at %08x, inode size = %08x!!!\n", ++ (unsigned)(page->index << PAGE_CACHE_SHIFT), ++ (unsigned)inode->i_size)); ++ T(YAFFS_TRACE_OS, ++ (" -> don't care!!\n")); ++ unlock_page(page); ++ return 0; ++ } ++ ++ end_index = inode->i_size >> PAGE_CACHE_SHIFT; ++ ++ /* easy case */ ++ if (page->index < end_index) ++ nBytes = PAGE_CACHE_SIZE; ++ else ++ nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); ++ ++ get_page(page); ++ ++ buffer = kmap(page); ++ ++ obj = yaffs_InodeToObject(inode); ++ yaffs_GrossLock(obj->myDev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_writepage at %08x, size %08x\n", ++ (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); ++ T(YAFFS_TRACE_OS, ++ ("writepag0: obj = %05x, ino = %05x\n", ++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); ++ ++ nWritten = yaffs_WriteDataToFile(obj, buffer, ++ page->index << PAGE_CACHE_SHIFT, nBytes, 0); ++ ++ T(YAFFS_TRACE_OS, ++ ("writepag1: obj = %05x, ino = %05x\n", ++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); ++ ++ yaffs_GrossUnlock(obj->myDev); ++ ++ kunmap(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ put_page(page); ++ ++ return (nWritten == nBytes) ? 0 : -ENOSPC; ++} ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct page *pg = NULL; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ uint32_t offset = pos & (PAGE_CACHE_SIZE - 1); ++ uint32_t to = offset + len; ++ ++ int ret = 0; ++ int space_held = 0; ++ ++ T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); ++ /* Get a page */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) ++ pg = grab_cache_page_write_begin(mapping, index, flags); ++#else ++ pg = __grab_cache_page(mapping, index); ++#endif ++ ++ *pagep = pg; ++ if (!pg) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ /* Get fs space */ ++ space_held = yaffs_hold_space(filp); ++ ++ if (!space_held) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ /* Update page if required */ ++ ++ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) ++ ret = yaffs_readpage_nolock(filp, pg); ++ ++ if (ret) ++ goto out; ++ ++ /* Happy path return */ ++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); ++ ++ return 0; ++ ++out: ++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); ++ if (space_held) ++ yaffs_release_space(filp); ++ if (pg) { ++ unlock_page(pg); ++ page_cache_release(pg); ++ } ++ return ret; ++} ++ ++#else ++ ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); ++ ++ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) ++ return yaffs_readpage_nolock(f, pg); ++ return 0; ++} ++#endif ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata) ++{ ++ int ret = 0; ++ void *addr, *kva; ++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); ++ ++ kva = kmap(pg); ++ addr = kva + offset_into_page; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_write_end addr %x pos %x nBytes %d\n", ++ (unsigned) addr, ++ (int)pos, copied)); ++ ++ ret = yaffs_file_write(filp, addr, copied, &pos); ++ ++ if (ret != copied) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_write_end not same size ret %d copied %d\n", ++ ret, copied)); ++ SetPageError(pg); ++ ClearPageUptodate(pg); ++ } else { ++ SetPageUptodate(pg); ++ } ++ ++ kunmap(pg); ++ ++ yaffs_release_space(filp); ++ unlock_page(pg); ++ page_cache_release(pg); ++ return ret; ++} ++#else ++ ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to) ++{ ++ void *addr, *kva; ++ ++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; ++ int nBytes = to - offset; ++ int nWritten; ++ ++ unsigned spos = pos; ++ unsigned saddr; ++ ++ kva = kmap(pg); ++ addr = kva + offset; ++ ++ saddr = (unsigned) addr; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write addr %x pos %x nBytes %d\n", ++ saddr, spos, nBytes)); ++ ++ nWritten = yaffs_file_write(f, addr, nBytes, &pos); ++ ++ if (nWritten != nBytes) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write not same size nWritten %d nBytes %d\n", ++ nWritten, nBytes)); ++ SetPageError(pg); ++ ClearPageUptodate(pg); ++ } else { ++ SetPageUptodate(pg); ++ } ++ ++ kunmap(pg); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write returning %d\n", ++ nWritten == nBytes ? 0 : nWritten)); ++ ++ return nWritten == nBytes ? 0 : nWritten; ++} ++#endif ++ ++ ++static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) ++{ ++ if (inode && obj) { ++ ++ ++ /* Check mode against the variant type and attempt to repair if broken. */ ++ __u32 mode = obj->yst_mode; ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (!S_ISREG(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFREG; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (!S_ISLNK(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFLNK; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!S_ISDIR(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFDIR; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ default: ++ /* TODO? */ ++ break; ++ } ++ ++ inode->i_flags |= S_NOATIME; ++ ++ inode->i_ino = obj->objectId; ++ inode->i_mode = obj->yst_mode; ++ inode->i_uid = obj->yst_uid; ++ inode->i_gid = obj->yst_gid; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++ inode->i_blksize = inode->i_sb->s_blocksize; ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++ inode->i_rdev = old_decode_dev(obj->yst_rdev); ++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime); ++ inode->i_atime.tv_nsec = 0; ++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; ++ inode->i_mtime.tv_nsec = 0; ++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; ++ inode->i_ctime.tv_nsec = 0; ++#else ++ inode->i_rdev = obj->yst_rdev; ++ inode->i_atime = obj->yst_atime; ++ inode->i_mtime = obj->yst_mtime; ++ inode->i_ctime = obj->yst_ctime; ++#endif ++ inode->i_size = yaffs_GetObjectFileLength(obj); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ ++ inode->i_nlink = yaffs_GetObjectLinkCount(obj); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", ++ inode->i_mode, inode->i_uid, inode->i_gid, ++ (int)inode->i_size, atomic_read(&inode->i_count))); ++ ++ switch (obj->yst_mode & S_IFMT) { ++ default: /* fifo, device or socket */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ init_special_inode(inode, obj->yst_mode, ++ old_decode_dev(obj->yst_rdev)); ++#else ++ init_special_inode(inode, obj->yst_mode, ++ (dev_t) (obj->yst_rdev)); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ inode->i_op = &yaffs_file_inode_operations; ++ inode->i_fop = &yaffs_file_operations; ++ inode->i_mapping->a_ops = ++ &yaffs_file_address_operations; ++ break; ++ case S_IFDIR: /* directory */ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ break; ++ case S_IFLNK: /* symlink */ ++ inode->i_op = &yaffs_symlink_inode_operations; ++ break; ++ } ++ ++ yaffs_InodeToObjectLV(inode) = obj; ++ ++ obj->myInode = inode; ++ ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_FileInode invalid parameters\n")); ++ } ++ ++} ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ yaffs_Object *obj) ++{ ++ struct inode *inode; ++ ++ if (!sb) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for NULL super_block!!\n")); ++ return NULL; ++ ++ } ++ ++ if (!obj) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for NULL object!!\n")); ++ return NULL; ++ ++ } ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for object %d\n", obj->objectId)); ++ ++ inode = Y_IGET(sb, obj->objectId); ++ if (IS_ERR(inode)) ++ return NULL; ++ ++ /* NB Side effect: iget calls back to yaffs_read_inode(). */ ++ /* iget also increments the inode's i_count */ ++ /* NB You can't be holding grossLock or deadlock will happen! */ ++ ++ return inode; ++} ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t *pos) ++{ ++ yaffs_Object *obj; ++ int nWritten, ipos; ++ struct inode *inode; ++ yaffs_Device *dev; ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ inode = f->f_dentry->d_inode; ++ ++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) ++ ipos = inode->i_size; ++ else ++ ipos = *pos; ++ ++ if (!obj) ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write: hey obj is null!\n")); ++ else ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write about to write writing %zu bytes" ++ "to object %d at %d\n", ++ n, obj->objectId, ipos)); ++ ++ nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write writing %zu bytes, %d written at %d\n", ++ n, nWritten, ipos)); ++ ++ if (nWritten > 0) { ++ ipos += nWritten; ++ *pos = ipos; ++ if (ipos > inode->i_size) { ++ inode->i_size = ipos; ++ inode->i_blocks = (ipos + 511) >> 9; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write size updated to %d bytes, " ++ "%d blocks\n", ++ ipos, (int)(inode->i_blocks))); ++ } ++ ++ } ++ yaffs_GrossUnlock(dev); ++ return nWritten == 0 ? -ENOSPC : nWritten; ++} ++ ++/* Space holding and freeing is done to ensure we have space available for write_begin/end */ ++/* For now we just assume few parallel writes and check against a small number. */ ++/* Todo: need to do this with a counter to handle parallel reads better */ ++ ++static ssize_t yaffs_hold_space(struct file *f) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ int nFreeChunks; ++ ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ nFreeChunks = yaffs_GetNumberOfFreeChunks(dev); ++ ++ yaffs_GrossUnlock(dev); ++ ++ return (nFreeChunks > 20) ? 1 : 0; ++} ++ ++static void yaffs_release_space(struct file *f) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ ++ yaffs_GrossUnlock(dev); ++} ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ struct inode *inode = f->f_dentry->d_inode; ++ unsigned long offset, curoffs; ++ struct ylist_head *i; ++ yaffs_Object *l; ++ ++ char name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ offset = f->f_pos; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); ++ ++ if (offset == 0) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: entry . ino %d \n", ++ (int)inode->i_ino)); ++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) ++ goto out; ++ offset++; ++ f->f_pos++; ++ } ++ if (offset == 1) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: entry .. ino %d \n", ++ (int)f->f_dentry->d_parent->d_inode->i_ino)); ++ if (filldir(dirent, "..", 2, offset, ++ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) ++ goto out; ++ offset++; ++ f->f_pos++; ++ } ++ ++ curoffs = 1; ++ ++ /* If the directory has changed since the open or last call to ++ readdir, rewind to after the 2 canned entries. */ ++ ++ if (f->f_version != inode->i_version) { ++ offset = 2; ++ f->f_pos = offset; ++ f->f_version = inode->i_version; ++ } ++ ++ ylist_for_each(i, &obj->variant.directoryVariant.children) { ++ curoffs++; ++ if (curoffs >= offset) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ ++ yaffs_GetObjectName(l, name, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: %s inode %d\n", name, ++ yaffs_GetObjectInode(l))); ++ ++ if (filldir(dirent, ++ name, ++ strlen(name), ++ offset, ++ yaffs_GetObjectInode(l), ++ yaffs_GetObjectType(l)) < 0) ++ goto up_and_out; ++ ++ offset++; ++ f->f_pos++; ++ } ++ } ++ ++up_and_out: ++out: ++ yaffs_GrossUnlock(dev); ++ ++ return 0; ++} ++ ++/* ++ * File creation. Allocate an inode, and we're done.. ++ */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define YCRED(x) x ++#else ++#define YCRED(x) (x->cred) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t rdev) ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int rdev) ++#endif ++{ ++ struct inode *inode; ++ ++ yaffs_Object *obj = NULL; ++ yaffs_Device *dev; ++ ++ yaffs_Object *parent = yaffs_InodeToObject(dir); ++ ++ int error = -ENOSPC; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) ++ mode |= S_ISGID; ++ ++ if (parent) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: parent object %d type %d\n", ++ parent->objectId, parent->variantType)); ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: could not get parent object\n")); ++ return -EPERM; ++ } ++ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " ++ "mode %x dev %x\n", ++ dentry->d_name.name, mode, rdev)); ++ ++ dev = parent->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ switch (mode & S_IFMT) { ++ default: ++ /* Special (socket, fifo, device...) */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n")); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, ++ gid, old_encode_dev(rdev)); ++#else ++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, ++ gid, rdev); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); ++ obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, ++ gid); ++ break; ++ case S_IFDIR: /* directory */ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: making directory\n")); ++ obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, ++ uid, gid); ++ break; ++ case S_IFLNK: /* symlink */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); ++ obj = NULL; /* Do we ever get here? */ ++ break; ++ } ++ ++ /* Can not call yaffs_get_inode() with gross lock held */ ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); ++ d_instantiate(dentry, inode); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod created object %d count = %d\n", ++ obj->objectId, atomic_read(&inode->i_count))); ++ error = 0; ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod failed making object\n")); ++ error = -ENOMEM; ++ } ++ ++ return error; ++} ++ ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ int retVal; ++ T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); ++ retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); ++ return retVal; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n) ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_create\n")); ++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); ++} ++ ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int retVal; ++ ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), ++ dentry->d_name.name)); ++ ++ dev = yaffs_InodeToObject(dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); ++ ++ if (retVal == YAFFS_OK) { ++ dentry->d_inode->i_nlink--; ++ dir->i_version++; ++ yaffs_GrossUnlock(dev); ++ mark_inode_dirty(dentry->d_inode); ++ return 0; ++ } ++ yaffs_GrossUnlock(dev); ++ return -ENOTEMPTY; ++} ++ ++/* ++ * Create a link... ++ */ ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *inode = old_dentry->d_inode; ++ yaffs_Object *obj = NULL; ++ yaffs_Object *link = NULL; ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_link\n")); ++ ++ obj = yaffs_InodeToObject(inode); ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ ++ link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, ++ obj); ++ ++ if (link) { ++ old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); ++ d_instantiate(dentry, old_dentry->d_inode); ++ atomic_inc(&old_dentry->d_inode->i_count); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_link link count %d i_count %d\n", ++ old_dentry->d_inode->i_nlink, ++ atomic_read(&old_dentry->d_inode->i_count))); ++ } ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (link) ++ return 0; ++ ++ return -EPERM; ++} ++ ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); ++ ++ dev = yaffs_InodeToObject(dir)->myDev; ++ yaffs_GrossLock(dev); ++ obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, ++ S_IFLNK | S_IRWXUGO, uid, gid, symname); ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ struct inode *inode; ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ d_instantiate(dentry, inode); ++ T(YAFFS_TRACE_OS, ("symlink created OK\n")); ++ return 0; ++ } else { ++ T(YAFFS_TRACE_OS, ("symlink not created\n")); ++ } ++ ++ return -ENOMEM; ++} ++ ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ obj = yaffs_DentryToObject(dentry); ++ ++ dev = obj->myDev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); ++ yaffs_GrossLock(dev); ++ yaffs_FlushFile(obj, 1); ++ yaffs_GrossUnlock(dev); ++ return 0; ++} ++ ++/* ++ * The VFS layer already does all the dentry stuff for rename. ++ * ++ * NB: POSIX says you can rename an object over an old object of the same name ++ */ ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++{ ++ yaffs_Device *dev; ++ int retVal = YAFFS_FAIL; ++ yaffs_Object *target; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_rename\n")); ++ dev = yaffs_InodeToObject(old_dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ /* Check if the target is an existing directory that is not empty. */ ++ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), ++ new_dentry->d_name.name); ++ ++ ++ ++ if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !ylist_empty(&target->variant.directoryVariant.children)) { ++ ++ T(YAFFS_TRACE_OS, ("target is non-empty dir\n")); ++ ++ retVal = YAFFS_FAIL; ++ } else { ++ /* Now does unlinking internally using shadowing mechanism */ ++ T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); ++ ++ retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), ++ old_dentry->d_name.name, ++ yaffs_InodeToObject(new_dir), ++ new_dentry->d_name.name); ++ } ++ yaffs_GrossUnlock(dev); ++ ++ if (retVal == YAFFS_OK) { ++ if (target) { ++ new_dentry->d_inode->i_nlink--; ++ mark_inode_dirty(new_dentry->d_inode); ++ } ++ ++ return 0; ++ } else { ++ return -ENOTEMPTY; ++ } ++} ++ ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error; ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_setattr of object %d\n", ++ yaffs_InodeToObject(inode)->objectId)); ++ ++ error = inode_change_ok(inode, attr); ++ if (error == 0) { ++ dev = yaffs_InodeToObject(inode)->myDev; ++ yaffs_GrossLock(dev); ++ if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == ++ YAFFS_OK) { ++ error = 0; ++ } else { ++ error = -EPERM; ++ } ++ yaffs_GrossUnlock(dev); ++ if (!error) ++ error = inode_setattr(inode, attr); ++ } ++ return error; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ struct super_block *sb = dentry->d_sb; ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++#endif ++ ++ T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); ++ ++ yaffs_GrossLock(dev); ++ ++ buf->f_type = YAFFS_MAGIC; ++ buf->f_bsize = sb->s_blocksize; ++ buf->f_namelen = 255; ++ ++ if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) { ++ /* Do this if chunk size is not a power of 2 */ ++ ++ uint64_t bytesInDev; ++ uint64_t bytesFree; ++ ++ bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) * ++ ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); ++ ++ do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ ++ buf->f_blocks = bytesInDev; ++ ++ bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) * ++ ((uint64_t)(dev->nDataBytesPerChunk)); ++ ++ do_div(bytesFree, sb->s_blocksize); ++ ++ buf->f_bfree = bytesFree; ++ ++ } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { ++ ++ buf->f_blocks = ++ (dev->endBlock - dev->startBlock + 1) * ++ dev->nChunksPerBlock / ++ (sb->s_blocksize / dev->nDataBytesPerChunk); ++ buf->f_bfree = ++ yaffs_GetNumberOfFreeChunks(dev) / ++ (sb->s_blocksize / dev->nDataBytesPerChunk); ++ } else { ++ buf->f_blocks = ++ (dev->endBlock - dev->startBlock + 1) * ++ dev->nChunksPerBlock * ++ (dev->nDataBytesPerChunk / sb->s_blocksize); ++ ++ buf->f_bfree = ++ yaffs_GetNumberOfFreeChunks(dev) * ++ (dev->nDataBytesPerChunk / sb->s_blocksize); ++ } ++ ++ buf->f_files = 0; ++ buf->f_ffree = 0; ++ buf->f_bavail = buf->f_bfree; ++ ++ yaffs_GrossUnlock(dev); ++ return 0; ++} ++ ++ ++static int yaffs_do_sync_fs(struct super_block *sb) ++{ ++ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); ++ ++ if (sb->s_dirt) { ++ yaffs_GrossLock(dev); ++ ++ if (dev) { ++ yaffs_FlushEntireDeviceCache(dev); ++ yaffs_CheckpointSave(dev); ++ } ++ ++ yaffs_GrossUnlock(dev); ++ ++ sb->s_dirt = 0; ++ } ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static void yaffs_write_super(struct super_block *sb) ++#else ++static int yaffs_write_super(struct super_block *sb) ++#endif ++{ ++ ++ T(YAFFS_TRACE_OS, ("yaffs_write_super\n")); ++ if (yaffs_auto_checkpoint >= 2) ++ yaffs_do_sync_fs(sb); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ return 0; ++#endif ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait) ++#else ++static int yaffs_sync_fs(struct super_block *sb) ++#endif ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); ++ ++ if (yaffs_auto_checkpoint >= 1) ++ yaffs_do_sync_fs(sb); ++ ++ return 0; ++} ++ ++#ifdef YAFFS_USE_OWN_IGET ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) ++{ ++ struct inode *inode; ++ yaffs_Object *obj; ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_iget for %lu\n", ino)); ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_GrossLock(dev); ++ ++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); ++ ++ yaffs_FillInodeFromObject(inode, obj); ++ ++ yaffs_GrossUnlock(dev); ++ ++ unlock_new_inode(inode); ++ return inode; ++} ++ ++#else ++ ++static void yaffs_read_inode(struct inode *inode) ++{ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_Object *obj; ++ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_inode for %d\n", (int)inode->i_ino)); ++ ++ yaffs_GrossLock(dev); ++ ++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); ++ ++ yaffs_FillInodeFromObject(inode, obj); ++ ++ yaffs_GrossUnlock(dev); ++} ++ ++#endif ++ ++static YLIST_HEAD(yaffs_dev_list); ++ ++#if 0 /* not used */ ++static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ if (*flags & MS_RDONLY) { ++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_remount_fs: %s: RO\n", dev->name)); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushEntireDeviceCache(dev); ++ ++ yaffs_CheckpointSave(dev); ++ ++ if (mtd->sync) ++ mtd->sync(mtd); ++ ++ yaffs_GrossUnlock(dev); ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_remount_fs: %s: RW\n", dev->name)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void yaffs_put_super(struct super_block *sb) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushEntireDeviceCache(dev); ++ ++ yaffs_CheckpointSave(dev); ++ ++ if (dev->putSuperFunc) ++ dev->putSuperFunc(sb); ++ ++ yaffs_Deinitialise(dev); ++ ++ yaffs_GrossUnlock(dev); ++ ++ /* we assume this is protected by lock_kernel() in mount/umount */ ++ ylist_del(&dev->devList); ++ ++ if (dev->spareBuffer) { ++ YFREE(dev->spareBuffer); ++ dev->spareBuffer = NULL; ++ } ++ ++ kfree(dev); ++} ++ ++ ++static void yaffs_MTDPutSuper(struct super_block *sb) ++{ ++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; ++ ++ if (mtd->sync) ++ mtd->sync(mtd); ++ ++ put_mtd_device(mtd); ++} ++ ++ ++static void yaffs_MarkSuperBlockDirty(void *vsb) ++{ ++ struct super_block *sb = (struct super_block *)vsb; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); ++ if (sb) ++ sb->s_dirt = 1; ++} ++ ++typedef struct { ++ int inband_tags; ++ int skip_checkpoint_read; ++ int skip_checkpoint_write; ++ int no_cache; ++} yaffs_options; ++ ++#define MAX_OPT_LEN 20 ++static int yaffs_parse_options(yaffs_options *options, const char *options_str) ++{ ++ char cur_opt[MAX_OPT_LEN + 1]; ++ int p; ++ int error = 0; ++ ++ /* Parse through the options which is a comma seperated list */ ++ ++ while (options_str && *options_str && !error) { ++ memset(cur_opt, 0, MAX_OPT_LEN + 1); ++ p = 0; ++ ++ while (*options_str && *options_str != ',') { ++ if (p < MAX_OPT_LEN) { ++ cur_opt[p] = *options_str; ++ p++; ++ } ++ options_str++; ++ } ++ ++ if (!strcmp(cur_opt, "inband-tags")) ++ options->inband_tags = 1; ++ else if (!strcmp(cur_opt, "no-cache")) ++ options->no_cache = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint-read")) ++ options->skip_checkpoint_read = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint-write")) ++ options->skip_checkpoint_write = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint")) { ++ options->skip_checkpoint_read = 1; ++ options->skip_checkpoint_write = 1; ++ } else { ++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", ++ cur_opt); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++ ++static struct super_block *yaffs_internal_read_super(int yaffsVersion, ++ struct super_block *sb, ++ void *data, int silent) ++{ ++ int nBlocks; ++ struct inode *inode = NULL; ++ struct dentry *root; ++ yaffs_Device *dev = 0; ++ char devname_buf[BDEVNAME_SIZE + 1]; ++ struct mtd_info *mtd; ++ int err; ++ char *data_str = (char *)data; ++ ++ yaffs_options options; ++ ++ sb->s_magic = YAFFS_MAGIC; ++ sb->s_op = &yaffs_super_ops; ++ sb->s_flags |= MS_NOATIME; ++ ++ if (!sb) ++ printk(KERN_INFO "yaffs: sb is NULL\n"); ++ else if (!sb->s_dev) ++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); ++ else if (!yaffs_devname(sb, devname_buf)) ++ printk(KERN_INFO "yaffs: devname is NULL\n"); ++ else ++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", ++ sb->s_dev, ++ yaffs_devname(sb, devname_buf)); ++ ++ if (!data_str) ++ data_str = ""; ++ ++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); ++ ++ memset(&options, 0, sizeof(options)); ++ ++ if (yaffs_parse_options(&options, data_str)) { ++ /* Option parsing failed */ ++ return NULL; ++ } ++ ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); ++ ++#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY ++ T(YAFFS_TRACE_OS, ++ ("yaffs: Write verification disabled. All guarantees " ++ "null and void\n")); ++#endif ++ ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " ++ "\"%s\"\n", ++ MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ yaffs_devname(sb, devname_buf))); ++ ++ /* Check it's an mtd device..... */ ++ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) ++ return NULL; /* This isn't an mtd device */ ++ ++ /* Get the device */ ++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); ++ if (!mtd) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device #%u doesn't appear to exist\n", ++ MINOR(sb->s_dev))); ++ return NULL; ++ } ++ /* Check it's NAND */ ++ if (mtd->type != MTD_NANDFLASH) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); ++ return NULL; ++ } ++ ++ T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); ++ T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); ++ T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); ++ T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); ++ T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); ++ T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); ++ T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); ++ T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); ++ T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); ++ T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++ T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); ++#else ++ T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); ++#endif ++ ++#ifdef CONFIG_YAFFS_AUTO_YAFFS2 ++ ++ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); ++ yaffsVersion = 2; ++ } ++ ++ /* Added NCB 26/5/2006 for completeness */ ++ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); ++ yaffsVersion = 1; ++ } ++ ++#endif ++ ++ if (yaffsVersion == 2) { ++ /* Check for version 2 style functions */ ++ if (!mtd->erase || ++ !mtd->block_isbad || ++ !mtd->block_markbad || ++ !mtd->read || ++ !mtd->write || ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ !mtd->read_oob || !mtd->write_oob) { ++#else ++ !mtd->write_ecc || ++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { ++#endif ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support required " ++ "functions\n"));; ++ return NULL; ++ } ++ ++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || ++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && ++ !options.inband_tags) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not have the " ++ "right page sizes\n")); ++ return NULL; ++ } ++ } else { ++ /* Check for V1 style functions */ ++ if (!mtd->erase || ++ !mtd->read || ++ !mtd->write || ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ !mtd->read_oob || !mtd->write_oob) { ++#else ++ !mtd->write_ecc || ++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { ++#endif ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support required " ++ "functions\n"));; ++ return NULL; ++ } ++ ++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || ++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support have the " ++ "right page sizes\n")); ++ return NULL; ++ } ++ } ++ ++ /* OK, so if we got here, we have an MTD that's NAND and looks ++ * like it has the right capabilities ++ * Set the yaffs_Device up for mtd ++ */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); ++#else ++ sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); ++#endif ++ if (!dev) { ++ /* Deep shit could not allocate device structure */ ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs_read_super: Failed trying to allocate " ++ "yaffs_Device. \n")); ++ return NULL; ++ } ++ ++ memset(dev, 0, sizeof(yaffs_Device)); ++ dev->genericDevice = mtd; ++ dev->name = mtd->name; ++ ++ /* Set up the memory size parameters.... */ ++ ++ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); ++ ++ dev->startBlock = 0; ++ dev->endBlock = nBlocks - 1; ++ dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; ++ dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; ++ dev->nReservedBlocks = 5; ++ dev->nShortOpCaches = (options.no_cache) ? 0 : 10; ++ dev->inbandTags = options.inband_tags; ++ ++ /* ... and the functions. */ ++ if (yaffsVersion == 2) { ++ dev->writeChunkWithTagsToNAND = ++ nandmtd2_WriteChunkWithTagsToNAND; ++ dev->readChunkWithTagsFromNAND = ++ nandmtd2_ReadChunkWithTagsFromNAND; ++ dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; ++ dev->queryNANDBlock = nandmtd2_QueryNANDBlock; ++ dev->spareBuffer = YMALLOC(mtd->oobsize); ++ dev->isYaffs2 = 1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ dev->totalBytesPerChunk = mtd->writesize; ++ dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; ++#else ++ dev->totalBytesPerChunk = mtd->oobblock; ++ dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; ++#endif ++ nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); ++ ++ dev->startBlock = 0; ++ dev->endBlock = nBlocks - 1; ++ } else { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ /* use the MTD interface in yaffs_mtdif1.c */ ++ dev->writeChunkWithTagsToNAND = ++ nandmtd1_WriteChunkWithTagsToNAND; ++ dev->readChunkWithTagsFromNAND = ++ nandmtd1_ReadChunkWithTagsFromNAND; ++ dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; ++ dev->queryNANDBlock = nandmtd1_QueryNANDBlock; ++#else ++ dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; ++ dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; ++#endif ++ dev->isYaffs2 = 0; ++ } ++ /* ... and common functions */ ++ dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; ++ dev->initialiseNAND = nandmtd_InitialiseNAND; ++ ++ dev->putSuperFunc = yaffs_MTDPutSuper; ++ ++ dev->superBlock = (void *)sb; ++ dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; ++ ++ ++#ifndef CONFIG_YAFFS_DOES_ECC ++ dev->useNANDECC = 1; ++#endif ++ ++#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES ++ dev->wideTnodesDisabled = 1; ++#endif ++ ++ dev->skipCheckpointRead = options.skip_checkpoint_read; ++ dev->skipCheckpointWrite = options.skip_checkpoint_write; ++ ++ /* we assume this is protected by lock_kernel() in mount/umount */ ++ ylist_add_tail(&dev->devList, &yaffs_dev_list); ++ ++ init_MUTEX(&dev->grossLock); ++ ++ yaffs_GrossLock(dev); ++ ++ err = yaffs_GutsInitialise(dev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_super: guts initialised %s\n", ++ (err == YAFFS_OK) ? "OK" : "FAILED")); ++ ++ /* Release lock before yaffs_get_inode() */ ++ yaffs_GrossUnlock(dev); ++ ++ /* Create root inode */ ++ if (err == YAFFS_OK) ++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, ++ yaffs_Root(dev)); ++ ++ if (!inode) ++ return NULL; ++ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); ++ ++ root = d_alloc_root(inode); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); ++ ++ if (!root) { ++ iput(inode); ++ return NULL; ++ } ++ sb->s_root = root; ++ sb->s_dirt = !dev->isCheckpointed; ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); ++ return sb; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data, struct vfsmount *mnt) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs", ++ .get_sb = yaffs_read_super, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs_read_super(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs2_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs2", ++ .get_sb = yaffs2_read_super, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs2_read_super(struct super_block *sb, ++ void *data, int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++#endif /* CONFIG_YAFFS_YAFFS2 */ ++ ++static struct proc_dir_entry *my_proc_entry; ++ ++static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) ++{ ++ buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); ++ buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); ++ buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); ++ buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); ++ buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); ++ buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); ++ buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); ++ buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); ++ buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); ++ buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); ++ buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); ++ buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); ++ buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); ++ buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); ++ buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); ++ buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); ++ buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); ++ buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); ++ buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); ++ buf += sprintf(buf, "passiveGCs......... %d\n", ++ dev->passiveGarbageCollections); ++ buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); ++ buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); ++ buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); ++ buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); ++ buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); ++ buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); ++ buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); ++ buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); ++ buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); ++ buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); ++ buf += ++ sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); ++ buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); ++ buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); ++ buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); ++ ++ return buf; ++} ++ ++static int yaffs_proc_read(char *page, ++ char **start, ++ off_t offset, int count, int *eof, void *data) ++{ ++ struct ylist_head *item; ++ char *buf = page; ++ int step = offset; ++ int n = 0; ++ ++ /* Get proc_file_read() to step 'offset' by one on each sucessive call. ++ * We use 'offset' (*ppos) to indicate where we are in devList. ++ * This also assumes the user has posted a read buffer large ++ * enough to hold the complete output; but that's life in /proc. ++ */ ++ ++ *(int *)start = 1; ++ ++ /* Print header first */ ++ if (step == 0) { ++ buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ ++ "\n%s\n%s\n", yaffs_fs_c_version, ++ yaffs_guts_c_version); ++ } ++ ++ /* hold lock_kernel while traversing yaffs_dev_list */ ++ lock_kernel(); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ ylist_for_each(item, &yaffs_dev_list) { ++ yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); ++ if (n < step) { ++ n++; ++ continue; ++ } ++ buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); ++ buf = yaffs_dump_dev(buf, dev); ++ break; ++ } ++ unlock_kernel(); ++ ++ return buf - page < count ? buf - page : count; ++} ++ ++/** ++ * Set the verbosity of the warnings and error messages. ++ * ++ * Note that the names can only be a..z or _ with the current code. ++ */ ++ ++static struct { ++ char *mask_name; ++ unsigned mask_bitfield; ++} mask_flags[] = { ++ {"allocate", YAFFS_TRACE_ALLOCATE}, ++ {"always", YAFFS_TRACE_ALWAYS}, ++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, ++ {"buffers", YAFFS_TRACE_BUFFERS}, ++ {"bug", YAFFS_TRACE_BUG}, ++ {"checkpt", YAFFS_TRACE_CHECKPOINT}, ++ {"deletion", YAFFS_TRACE_DELETION}, ++ {"erase", YAFFS_TRACE_ERASE}, ++ {"error", YAFFS_TRACE_ERROR}, ++ {"gc_detail", YAFFS_TRACE_GC_DETAIL}, ++ {"gc", YAFFS_TRACE_GC}, ++ {"mtd", YAFFS_TRACE_MTD}, ++ {"nandaccess", YAFFS_TRACE_NANDACCESS}, ++ {"os", YAFFS_TRACE_OS}, ++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, ++ {"scan", YAFFS_TRACE_SCAN}, ++ {"tracing", YAFFS_TRACE_TRACING}, ++ ++ {"verify", YAFFS_TRACE_VERIFY}, ++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, ++ {"verify_full", YAFFS_TRACE_VERIFY_FULL}, ++ {"verify_all", YAFFS_TRACE_VERIFY_ALL}, ++ ++ {"write", YAFFS_TRACE_WRITE}, ++ {"all", 0xffffffff}, ++ {"none", 0}, ++ {NULL, 0}, ++}; ++ ++#define MAX_MASK_NAME_LENGTH 40 ++static int yaffs_proc_write(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ unsigned rg = 0, mask_bitfield; ++ char *end; ++ char *mask_name; ++ const char *x; ++ char substring[MAX_MASK_NAME_LENGTH + 1]; ++ int i; ++ int done = 0; ++ int add, len = 0; ++ int pos = 0; ++ ++ rg = yaffs_traceMask; ++ ++ while (!done && (pos < count)) { ++ done = 1; ++ while ((pos < count) && isspace(buf[pos])) ++ pos++; ++ ++ switch (buf[pos]) { ++ case '+': ++ case '-': ++ case '=': ++ add = buf[pos]; ++ pos++; ++ break; ++ ++ default: ++ add = ' '; ++ break; ++ } ++ mask_name = NULL; ++ ++ mask_bitfield = simple_strtoul(buf + pos, &end, 0); ++ ++ if (end > buf + pos) { ++ mask_name = "numeral"; ++ len = end - (buf + pos); ++ pos += len; ++ done = 0; ++ } else { ++ for (x = buf + pos, i = 0; ++ (*x == '_' || (*x >= 'a' && *x <= 'z')) && ++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) ++ substring[i] = *x; ++ substring[i] = '\0'; ++ ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ if (strcmp(substring, mask_flags[i].mask_name) == 0) { ++ mask_name = mask_flags[i].mask_name; ++ mask_bitfield = mask_flags[i].mask_bitfield; ++ done = 0; ++ break; ++ } ++ } ++ } ++ ++ if (mask_name != NULL) { ++ done = 0; ++ switch (add) { ++ case '-': ++ rg &= ~mask_bitfield; ++ break; ++ case '+': ++ rg |= mask_bitfield; ++ break; ++ case '=': ++ rg = mask_bitfield; ++ break; ++ default: ++ rg |= mask_bitfield; ++ break; ++ } ++ } ++ } ++ ++ yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; ++ ++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask); ++ ++ if (rg & YAFFS_TRACE_ALWAYS) { ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ char flag; ++ flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; ++ printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); ++ } ++ } ++ ++ return count; ++} ++ ++/* Stuff to handle installation of file systems */ ++struct file_system_to_install { ++ struct file_system_type *fst; ++ int installed; ++}; ++ ++static struct file_system_to_install fs_to_install[] = { ++ {&yaffs_fs_type, 0}, ++ {&yaffs2_fs_type, 0}, ++ {NULL, 0} ++}; ++ ++static int __init init_yaffs_fs(void) ++{ ++ int error = 0; ++ struct file_system_to_install *fsinst; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); ++ ++ /* Install the proc_fs entry */ ++ my_proc_entry = create_proc_entry("yaffs", ++ S_IRUGO | S_IFREG, ++ YPROC_ROOT); ++ ++ if (my_proc_entry) { ++ my_proc_entry->write_proc = yaffs_proc_write; ++ my_proc_entry->read_proc = yaffs_proc_read; ++ my_proc_entry->data = NULL; ++ } else ++ return -ENOMEM; ++ ++ /* Now add the file system entries */ ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst && !error) { ++ error = register_filesystem(fsinst->fst); ++ if (!error) ++ fsinst->installed = 1; ++ fsinst++; ++ } ++ ++ /* Any errors? uninstall */ ++ if (error) { ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++ } ++ ++ return error; ++} ++ ++static void __exit exit_yaffs_fs(void) ++{ ++ ++ struct file_system_to_install *fsinst; ++ ++ T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ ++ " removing. \n")); ++ ++ remove_proc_entry("yaffs", YPROC_ROOT); ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++} ++ ++module_init(init_yaffs_fs) ++module_exit(exit_yaffs_fs) ++ ++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); ++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GETBLOCKINFO_H__ ++#define __YAFFS_GETBLOCKINFO_H__ ++ ++#include "yaffs_guts.h" ++ ++/* Function to manipulate block info */ ++static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), ++ blk)); ++ YBUG(); ++ } ++ return &dev->blockInfo[blk - dev->internalStartBlock]; ++} ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c linux-2.6.30/fs/yaffs2/yaffs_guts.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_guts.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,7552 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_guts_c_version = ++ "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $"; ++ ++#include "yportenv.h" ++ ++#include "yaffsinterface.h" ++#include "yaffs_guts.h" ++#include "yaffs_tagsvalidity.h" ++#include "yaffs_getblockinfo.h" ++ ++#include "yaffs_tagscompat.h" ++#ifndef CONFIG_YAFFS_USE_OWN_SORT ++#include "yaffs_qsort.h" ++#endif ++#include "yaffs_nand.h" ++ ++#include "yaffs_checkptrw.h" ++ ++#include "yaffs_nand.h" ++#include "yaffs_packedtags2.h" ++ ++ ++#define YAFFS_PASSIVE_GC_CHUNKS 2 ++ ++#include "yaffs_ecc.h" ++ ++ ++/* Robustification (if it ever comes about...) */ ++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, ++ int erasedOk); ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_ExtendedTags *tags); ++ ++/* Other local prototypes */ ++static int yaffs_UnlinkObject(yaffs_Object *obj); ++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); ++ ++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); ++ ++static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags, ++ int useReserve); ++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, ++ int chunkInNAND, int inScan); ++ ++static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, ++ yaffs_ObjectType type); ++static void yaffs_AddObjectToDirectory(yaffs_Object *directory, ++ yaffs_Object *obj); ++static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, ++ int force, int isShrink, int shadows); ++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); ++static int yaffs_CheckStructures(void); ++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, ++ int chunkOffset, int *limit); ++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); ++ ++static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); ++ ++ ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND); ++ ++static int yaffs_UnlinkWorker(yaffs_Object *obj); ++ ++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, ++ int chunkInObject); ++ ++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, ++ yaffs_BlockInfo **blockUsedPtr); ++ ++static void yaffs_VerifyFreeChunks(yaffs_Device *dev); ++ ++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); ++ ++static void yaffs_VerifyDirectory(yaffs_Object *directory); ++#ifdef YAFFS_PARANOID ++static int yaffs_CheckFileSanity(yaffs_Object *in); ++#else ++#define yaffs_CheckFileSanity(in) ++#endif ++ ++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); ++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); ++ ++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); ++ ++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags); ++ ++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, ++ unsigned pos); ++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId); ++ ++ ++/* Function to calculate chunk and offset */ ++ ++static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, ++ __u32 *offsetOut) ++{ ++ int chunk; ++ __u32 offset; ++ ++ chunk = (__u32)(addr >> dev->chunkShift); ++ ++ if (dev->chunkDiv == 1) { ++ /* easy power of 2 case */ ++ offset = (__u32)(addr & dev->chunkMask); ++ } else { ++ /* Non power-of-2 case */ ++ ++ loff_t chunkBase; ++ ++ chunk /= dev->chunkDiv; ++ ++ chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; ++ offset = (__u32)(addr - chunkBase); ++ } ++ ++ *chunkOut = chunk; ++ *offsetOut = offset; ++} ++ ++/* Function to return the number of shifts for a power of 2 greater than or ++ * equal to the given number ++ * Note we don't try to cater for all possible numbers and this does not have to ++ * be hellishly efficient. ++ */ ++ ++static __u32 ShiftsGE(__u32 x) ++{ ++ int extraBits; ++ int nShifts; ++ ++ nShifts = extraBits = 0; ++ ++ while (x > 1) { ++ if (x & 1) ++ extraBits++; ++ x >>= 1; ++ nShifts++; ++ } ++ ++ if (extraBits) ++ nShifts++; ++ ++ return nShifts; ++} ++ ++/* Function to return the number of shifts to get a 1 in bit 0 ++ */ ++ ++static __u32 Shifts(__u32 x) ++{ ++ int nShifts; ++ ++ nShifts = 0; ++ ++ if (!x) ++ return 0; ++ ++ while (!(x&1)) { ++ x >>= 1; ++ nShifts++; ++ } ++ ++ return nShifts; ++} ++ ++ ++ ++/* ++ * Temporary buffer manipulations. ++ */ ++ ++static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) ++{ ++ int i; ++ __u8 *buf = (__u8 *)1; ++ ++ memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer)); ++ ++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { ++ dev->tempBuffer[i].line = 0; /* not in use */ ++ dev->tempBuffer[i].buffer = buf = ++ YMALLOC_DMA(dev->totalBytesPerChunk); ++ } ++ ++ return buf ? YAFFS_OK : YAFFS_FAIL; ++} ++ ++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo) ++{ ++ int i, j; ++ ++ dev->tempInUse++; ++ if (dev->tempInUse > dev->maxTemp) ++ dev->maxTemp = dev->tempInUse; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].line == 0) { ++ dev->tempBuffer[i].line = lineNo; ++ if ((i + 1) > dev->maxTemp) { ++ dev->maxTemp = i + 1; ++ for (j = 0; j <= i; j++) ++ dev->tempBuffer[j].maxLine = ++ dev->tempBuffer[j].line; ++ } ++ ++ return dev->tempBuffer[i].buffer; ++ } ++ } ++ ++ T(YAFFS_TRACE_BUFFERS, ++ (TSTR("Out of temp buffers at line %d, other held by lines:"), ++ lineNo)); ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) ++ T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); ++ ++ T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); ++ ++ /* ++ * If we got here then we have to allocate an unmanaged one ++ * This is not good. ++ */ ++ ++ dev->unmanagedTempAllocations++; ++ return YMALLOC(dev->nDataBytesPerChunk); ++ ++} ++ ++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, ++ int lineNo) ++{ ++ int i; ++ ++ dev->tempInUse--; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].buffer == buffer) { ++ dev->tempBuffer[i].line = 0; ++ return; ++ } ++ } ++ ++ if (buffer) { ++ /* assume it is an unmanaged one. */ ++ T(YAFFS_TRACE_BUFFERS, ++ (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), ++ lineNo)); ++ YFREE(buffer); ++ dev->unmanagedTempDeallocations++; ++ } ++ ++} ++ ++/* ++ * Determine if we have a managed buffer. ++ */ ++int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) ++{ ++ int i; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].buffer == buffer) ++ return 1; ++ } ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].data == buffer) ++ return 1; ++ } ++ ++ if (buffer == dev->checkpointBuffer) ++ return 1; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); ++ return 0; ++} ++ ++ ++ ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), ++ blk)); ++ YBUG(); ++ } ++ return dev->chunkBits + ++ (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); ++} ++ ++static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || ++ chunk < 0 || chunk >= dev->nChunksPerBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), ++ blk, chunk)); ++ YBUG(); ++ } ++} ++ ++static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ memset(blkBits, 0, dev->chunkBitmapStride); ++} ++ ++static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ blkBits[chunk / 8] &= ~(1 << (chunk & 7)); ++} ++ ++static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ blkBits[chunk / 8] |= (1 << (chunk & 7)); ++} ++ ++static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; ++} ++ ++static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ int i; ++ for (i = 0; i < dev->chunkBitmapStride; i++) { ++ if (*blkBits) ++ return 1; ++ blkBits++; ++ } ++ return 0; ++} ++ ++static int yaffs_CountChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ int i; ++ int n = 0; ++ for (i = 0; i < dev->chunkBitmapStride; i++) { ++ __u8 x = *blkBits; ++ while (x) { ++ if (x & 1) ++ n++; ++ x >>= 1; ++ } ++ ++ blkBits++; ++ } ++ return n; ++} ++ ++/* ++ * Verification code ++ */ ++ ++static int yaffs_SkipVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_SkipFullVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_SkipNANDVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); ++} ++ ++static const char *blockStateName[] = { ++"Unknown", ++"Needs scanning", ++"Scanning", ++"Empty", ++"Allocating", ++"Full", ++"Dirty", ++"Checkpoint", ++"Collecting", ++"Dead" ++}; ++ ++static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) ++{ ++ int actuallyUsed; ++ int inUse; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Report illegal runtime states */ ++ if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); ++ ++ switch (bi->blockState) { ++ case YAFFS_BLOCK_STATE_UNKNOWN: ++ case YAFFS_BLOCK_STATE_SCANNING: ++ case YAFFS_BLOCK_STATE_NEEDS_SCANNING: ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), ++ n, blockStateName[bi->blockState])); ++ } ++ ++ /* Check pages in use and soft deletions are legal */ ++ ++ actuallyUsed = bi->pagesInUse - bi->softDeletions; ++ ++ if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || ++ bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || ++ actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), ++ n, bi->pagesInUse, bi->softDeletions)); ++ ++ ++ /* Check chunk bitmap legal */ ++ inUse = yaffs_CountChunkBits(dev, n); ++ if (inUse != bi->pagesInUse) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), ++ n, bi->pagesInUse, inUse)); ++ ++ /* Check that the sequence number is valid. ++ * Ten million is legal, but is very unlikely ++ */ ++ if (dev->isYaffs2 && ++ (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && ++ (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000)) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR), ++ n, bi->sequenceNumber)); ++} ++ ++static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, ++ int n) ++{ ++ yaffs_VerifyBlock(dev, bi, n); ++ ++ /* After collection the block should be in the erased state */ ++ /* This will need to change if we do partial gc */ ++ ++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && ++ bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), ++ n, bi->blockState)); ++ } ++} ++ ++static void yaffs_VerifyBlocks(yaffs_Device *dev) ++{ ++ int i; ++ int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; ++ int nIllegalBlockStates = 0; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ yaffs_VerifyBlock(dev, bi, i); ++ ++ if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) ++ nBlocksPerState[bi->blockState]++; ++ else ++ nIllegalBlockStates++; ++ } ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); ++ if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); ++ ++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("%s %d blocks"TENDSTR), ++ blockStateName[i], nBlocksPerState[i])); ++ ++ if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), ++ dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); ++ ++ if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Erased block count wrong dev %d count %d"TENDSTR), ++ dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); ++ ++ if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), ++ nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); ++ ++} ++ ++/* ++ * Verify the object header. oh must be valid, but obj and tags may be NULL in which ++ * case those tests will not be performed. ++ */ ++static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ if (!(tags && obj && oh)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), ++ (__u32)tags, (__u32)obj, (__u32)oh)); ++ return; ++ } ++ ++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || ++ oh->type > YAFFS_OBJECT_TYPE_MAX) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), ++ tags->objectId, oh->type)); ++ ++ if (tags->objectId != obj->objectId) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch objectId %d"TENDSTR), ++ tags->objectId, obj->objectId)); ++ ++ ++ /* ++ * Check that the object's parent ids match if parentCheck requested. ++ * ++ * Tests do not apply to the root object. ++ */ ++ ++ if (parentCheck && tags->objectId > 1 && !obj->parent) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), ++ tags->objectId, oh->parentObjectId)); ++ ++ if (parentCheck && obj->parent && ++ oh->parentObjectId != obj->parent->objectId && ++ (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || ++ obj->parent->objectId != YAFFS_OBJECTID_DELETED)) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), ++ tags->objectId, oh->parentObjectId, obj->parent->objectId)); ++ ++ if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */ ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header name is NULL"TENDSTR), ++ obj->objectId)); ++ ++ if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header name is 0xFF"TENDSTR), ++ obj->objectId)); ++} ++ ++ ++ ++static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ yaffs_Device *dev = obj->myDev; ++ int ok = 1; ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (tn->internal[i]) { ++ ok = yaffs_VerifyTnodeWorker(obj, ++ tn->internal[i], ++ level - 1, ++ (chunkOffset<objectId; ++ ++ chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; ++ ++ for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { ++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ ++ if (theChunk > 0) { ++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); ++ if (tags.objectId != objectId || tags.chunkId != chunkOffset) { ++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), ++ objectId, chunkOffset, theChunk, ++ tags.objectId, tags.chunkId)); ++ } ++ } ++ chunkOffset++; ++ } ++ } ++ } ++ ++ return ok; ++ ++} ++ ++ ++static void yaffs_VerifyFile(yaffs_Object *obj) ++{ ++ int requiredTallness; ++ int actualTallness; ++ __u32 lastChunk; ++ __u32 x; ++ __u32 i; ++ yaffs_Device *dev; ++ yaffs_ExtendedTags tags; ++ yaffs_Tnode *tn; ++ __u32 objectId; ++ ++ if (!obj) ++ return; ++ ++ if (yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ dev = obj->myDev; ++ objectId = obj->objectId; ++ ++ /* Check file size is consistent with tnode depth */ ++ lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; ++ x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (x > 0) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ actualTallness = obj->variant.fileVariant.topLevel; ++ ++ if (requiredTallness > actualTallness) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), ++ obj->objectId, actualTallness, requiredTallness)); ++ ++ ++ /* Check that the chunks in the tnode tree are all correct. ++ * We do this by scanning through the tnode tree and ++ * checking the tags for every chunk match. ++ */ ++ ++ if (yaffs_SkipNANDVerification(dev)) ++ return; ++ ++ for (i = 1; i <= lastChunk; i++) { ++ tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i); ++ ++ if (tn) { ++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk > 0) { ++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); ++ if (tags.objectId != objectId || tags.chunkId != i) { ++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), ++ objectId, i, theChunk, ++ tags.objectId, tags.chunkId)); ++ } ++ } ++ } ++ } ++} ++ ++ ++static void yaffs_VerifyHardLink(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ /* Verify sane equivalent object */ ++} ++ ++static void yaffs_VerifySymlink(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ /* Verify symlink string */ ++} ++ ++static void yaffs_VerifySpecial(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++} ++ ++static void yaffs_VerifyObject(yaffs_Object *obj) ++{ ++ yaffs_Device *dev; ++ ++ __u32 chunkMin; ++ __u32 chunkMax; ++ ++ __u32 chunkIdOk; ++ __u32 chunkInRange; ++ __u32 chunkShouldNotBeDeleted; ++ __u32 chunkValid; ++ ++ if (!obj) ++ return; ++ ++ if (obj->beingCreated) ++ return; ++ ++ dev = obj->myDev; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Check sane object header chunk */ ++ ++ chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; ++ chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; ++ ++ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); ++ chunkIdOk = chunkInRange || obj->hdrChunk == 0; ++ chunkValid = chunkInRange && ++ yaffs_CheckChunkBit(dev, ++ obj->hdrChunk / dev->nChunksPerBlock, ++ obj->hdrChunk % dev->nChunksPerBlock); ++ chunkShouldNotBeDeleted = chunkInRange && !chunkValid; ++ ++ if (!obj->fake && ++ (!chunkIdOk || chunkShouldNotBeDeleted)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), ++ obj->objectId, obj->hdrChunk, ++ chunkIdOk ? "" : ",out of range", ++ chunkShouldNotBeDeleted ? ",marked as deleted" : "")); ++ } ++ ++ if (chunkValid && !yaffs_SkipNANDVerification(dev)) { ++ yaffs_ExtendedTags tags; ++ yaffs_ObjectHeader *oh; ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ oh = (yaffs_ObjectHeader *)buffer; ++ ++ yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer, ++ &tags); ++ ++ yaffs_VerifyObjectHeader(obj, oh, &tags, 1); ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ } ++ ++ /* Verify it has a parent */ ++ if (obj && !obj->fake && ++ (!obj->parent || obj->parent->myDev != dev)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), ++ obj->objectId, obj->parent)); ++ } ++ ++ /* Verify parent is a directory */ ++ if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), ++ obj->objectId, obj->parent->variantType)); ++ } ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ yaffs_VerifyFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_VerifySymlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ yaffs_VerifyDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ yaffs_VerifyHardLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ yaffs_VerifySpecial(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has illegaltype %d"TENDSTR), ++ obj->objectId, obj->variantType)); ++ break; ++ } ++} ++ ++static void yaffs_VerifyObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ int i; ++ struct ylist_head *lh; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ ylist_for_each(lh, &dev->objectBucket[i].list) { ++ if (lh) { ++ obj = ylist_entry(lh, yaffs_Object, hashLink); ++ yaffs_VerifyObject(obj); ++ } ++ } ++ } ++} ++ ++ ++/* ++ * Simple hash function. Needs to have a reasonable spread ++ */ ++ ++static Y_INLINE int yaffs_HashFunction(int n) ++{ ++ n = abs(n); ++ return n % YAFFS_NOBJECT_BUCKETS; ++} ++ ++/* ++ * Access functions to useful fake objects. ++ * Note that root might have a presence in NAND if permissions are set. ++ */ ++ ++yaffs_Object *yaffs_Root(yaffs_Device *dev) ++{ ++ return dev->rootDir; ++} ++ ++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev) ++{ ++ return dev->lostNFoundDir; ++} ++ ++ ++/* ++ * Erased NAND checking functions ++ */ ++ ++int yaffs_CheckFF(__u8 *buffer, int nBytes) ++{ ++ /* Horrible, slow implementation */ ++ while (nBytes--) { ++ if (*buffer != 0xFF) ++ return 0; ++ buffer++; ++ } ++ return 1; ++} ++ ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND) ++{ ++ int retval = YAFFS_OK; ++ __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); ++ yaffs_ExtendedTags tags; ++ int result; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); ++ ++ if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) ++ retval = YAFFS_FAIL; ++ ++ if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { ++ T(YAFFS_TRACE_NANDACCESS, ++ (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); ++ retval = YAFFS_FAIL; ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, data, __LINE__); ++ ++ return retval; ++ ++} ++ ++static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, ++ const __u8 *data, ++ yaffs_ExtendedTags *tags, ++ int useReserve) ++{ ++ int attempts = 0; ++ int writeOk = 0; ++ int chunk; ++ ++ yaffs_InvalidateCheckpoint(dev); ++ ++ do { ++ yaffs_BlockInfo *bi = 0; ++ int erasedOk = 0; ++ ++ chunk = yaffs_AllocateChunk(dev, useReserve, &bi); ++ if (chunk < 0) { ++ /* no space */ ++ break; ++ } ++ ++ /* First check this chunk is erased, if it needs ++ * checking. The checking policy (unless forced ++ * always on) is as follows: ++ * ++ * Check the first page we try to write in a block. ++ * If the check passes then we don't need to check any ++ * more. If the check fails, we check again... ++ * If the block has been erased, we don't need to check. ++ * ++ * However, if the block has been prioritised for gc, ++ * then we think there might be something odd about ++ * this block and stop using it. ++ * ++ * Rationale: We should only ever see chunks that have ++ * not been erased if there was a partially written ++ * chunk due to power loss. This checking policy should ++ * catch that case with very few checks and thus save a ++ * lot of checks that are most likely not needed. ++ */ ++ if (bi->gcPrioritise) { ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ /* try another chunk */ ++ continue; ++ } ++ ++ /* let's give it a try */ ++ attempts++; ++ ++#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bi->skipErasedCheck = 0; ++#endif ++ if (!bi->skipErasedCheck) { ++ erasedOk = yaffs_CheckChunkErased(dev, chunk); ++ if (erasedOk != YAFFS_OK) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs chunk %d was not erased" ++ TENDSTR), chunk)); ++ ++ /* try another chunk */ ++ continue; ++ } ++ bi->skipErasedCheck = 1; ++ } ++ ++ writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, ++ data, tags); ++ if (writeOk != YAFFS_OK) { ++ yaffs_HandleWriteChunkError(dev, chunk, erasedOk); ++ /* try another chunk */ ++ continue; ++ } ++ ++ /* Copy the data into the robustification buffer */ ++ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); ++ ++ } while (writeOk != YAFFS_OK && ++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); ++ ++ if (!writeOk) ++ chunk = -1; ++ ++ if (attempts > 1) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs write required %d attempts" TENDSTR), ++ attempts)); ++ ++ dev->nRetriedWrites += (attempts - 1); ++ } ++ ++ return chunk; ++} ++ ++/* ++ * Block retiring for handling a broken block. ++ */ ++ ++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) ++{ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); ++ ++ yaffs_InvalidateCheckpoint(dev); ++ ++ if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { ++ if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR( ++ "yaffs: Failed to mark bad and erase block %d" ++ TENDSTR), blockInNAND)); ++ } else { ++ yaffs_ExtendedTags tags; ++ int chunkId = blockInNAND * dev->nChunksPerBlock; ++ ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ memset(buffer, 0xff, dev->nDataBytesPerChunk); ++ yaffs_InitialiseTags(&tags); ++ tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; ++ if (dev->writeChunkWithTagsToNAND(dev, chunkId - ++ dev->chunkOffset, buffer, &tags) != YAFFS_OK) ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " ++ TCONT("write bad block marker to block %d") ++ TENDSTR), blockInNAND)); ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ } ++ } ++ ++ bi->blockState = YAFFS_BLOCK_STATE_DEAD; ++ bi->gcPrioritise = 0; ++ bi->needsRetiring = 0; ++ ++ dev->nRetiredBlocks++; ++} ++ ++/* ++ * Functions for robustisizing TODO ++ * ++ */ ++ ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags) ++{ ++} ++ ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_ExtendedTags *tags) ++{ ++} ++ ++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) ++{ ++ if (!bi->gcPrioritise) { ++ bi->gcPrioritise = 1; ++ dev->hasPendingPrioritisedGCs = 1; ++ bi->chunkErrorStrikes++; ++ ++ if (bi->chunkErrorStrikes > 3) { ++ bi->needsRetiring = 1; /* Too many stikes, so retire this */ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); ++ ++ } ++ } ++} ++ ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, ++ int erasedOk) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); ++ ++ yaffs_HandleChunkError(dev, bi); ++ ++ if (erasedOk) { ++ /* Was an actual write failure, so mark the block for retirement */ ++ bi->needsRetiring = 1; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); ++ } ++ ++ /* Delete the chunk */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++} ++ ++ ++/*---------------- Name handling functions ------------*/ ++ ++static __u16 yaffs_CalcNameSum(const YCHAR *name) ++{ ++ __u16 sum = 0; ++ __u16 i = 1; ++ ++ const YUCHAR *bname = (const YUCHAR *) name; ++ if (bname) { ++ while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ sum += yaffs_toupper(*bname) * i; ++#else ++ sum += (*bname) * i; ++#endif ++ i++; ++ bname++; ++ } ++ } ++ return sum; ++} ++ ++static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) ++{ ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); ++ if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) ++ yaffs_strcpy(obj->shortName, name); ++ else ++ obj->shortName[0] = _Y('\0'); ++#endif ++ obj->sum = yaffs_CalcNameSum(name); ++} ++ ++/*-------------------- TNODES ------------------- ++ ++ * List of spare tnodes ++ * The list is hooked together using the first pointer ++ * in the tnode. ++ */ ++ ++/* yaffs_CreateTnodes creates a bunch more tnodes and ++ * adds them to the tnode free list. ++ * Don't use this function directly ++ */ ++ ++static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) ++{ ++ int i; ++ int tnodeSize; ++ yaffs_Tnode *newTnodes; ++ __u8 *mem; ++ yaffs_Tnode *curr; ++ yaffs_Tnode *next; ++ yaffs_TnodeList *tnl; ++ ++ if (nTnodes < 1) ++ return YAFFS_OK; ++ ++ /* Calculate the tnode size in bytes for variable width tnode support. ++ * Must be a multiple of 32-bits */ ++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ /* make these things */ ++ ++ newTnodes = YMALLOC(nTnodes * tnodeSize); ++ mem = (__u8 *)newTnodes; ++ ++ if (!newTnodes) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++#if 0 ++ for (i = 0; i < nTnodes - 1; i++) { ++ newTnodes[i].internal[0] = &newTnodes[i + 1]; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ } ++ ++ newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ dev->freeTnodes = newTnodes; ++#else ++ /* New hookup for wide tnodes */ ++ for (i = 0; i < nTnodes - 1; i++) { ++ curr = (yaffs_Tnode *) &mem[i * tnodeSize]; ++ next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; ++ curr->internal[0] = next; ++ } ++ ++ curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; ++ curr->internal[0] = dev->freeTnodes; ++ dev->freeTnodes = (yaffs_Tnode *)mem; ++ ++#endif ++ ++ ++ dev->nFreeTnodes += nTnodes; ++ dev->nTnodesCreated += nTnodes; ++ ++ /* Now add this bunch of tnodes to a list for freeing up. ++ * NB If we can't add this to the management list it isn't fatal ++ * but it just means we can't free this bunch of tnodes later. ++ */ ++ ++ tnl = YMALLOC(sizeof(yaffs_TnodeList)); ++ if (!tnl) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs: Could not add tnodes to management list" TENDSTR))); ++ return YAFFS_FAIL; ++ } else { ++ tnl->tnodes = newTnodes; ++ tnl->next = dev->allocatedTnodeList; ++ dev->allocatedTnodeList = tnl; ++ } ++ ++ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); ++ ++ return YAFFS_OK; ++} ++ ++/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ ++ ++static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev) ++{ ++ yaffs_Tnode *tn = NULL; ++ ++ /* If there are none left make more */ ++ if (!dev->freeTnodes) ++ yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); ++ ++ if (dev->freeTnodes) { ++ tn = dev->freeTnodes; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { ++ /* Hoosterman, this thing looks like it isn't in the list */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: Tnode list bug 1" TENDSTR))); ++ } ++#endif ++ dev->freeTnodes = dev->freeTnodes->internal[0]; ++ dev->nFreeTnodes--; ++ } ++ ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++ ++ return tn; ++} ++ ++static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) ++{ ++ yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ if (tn) ++ memset(tn, 0, tnodeSize); ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn) ++{ ++ if (tn) { ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { ++ /* Hoosterman, this thing looks like it is already in the list */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: Tnode list bug 2" TENDSTR))); ++ } ++ tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ tn->internal[0] = dev->freeTnodes; ++ dev->freeTnodes = tn; ++ dev->nFreeTnodes++; ++ } ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++} ++ ++static void yaffs_DeinitialiseTnodes(yaffs_Device *dev) ++{ ++ /* Free the list of allocated tnodes */ ++ yaffs_TnodeList *tmp; ++ ++ while (dev->allocatedTnodeList) { ++ tmp = dev->allocatedTnodeList->next; ++ ++ YFREE(dev->allocatedTnodeList->tnodes); ++ YFREE(dev->allocatedTnodeList); ++ dev->allocatedTnodeList = tmp; ++ ++ } ++ ++ dev->freeTnodes = NULL; ++ dev->nFreeTnodes = 0; ++} ++ ++static void yaffs_InitialiseTnodes(yaffs_Device *dev) ++{ ++ dev->allocatedTnodeList = NULL; ++ dev->freeTnodes = NULL; ++ dev->nFreeTnodes = 0; ++ dev->nTnodesCreated = 0; ++} ++ ++ ++void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, ++ unsigned val) ++{ ++ __u32 *map = (__u32 *)tn; ++ __u32 bitInMap; ++ __u32 bitInWord; ++ __u32 wordInMap; ++ __u32 mask; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ val >>= dev->chunkGroupBits; ++ ++ bitInMap = pos * dev->tnodeWidth; ++ wordInMap = bitInMap / 32; ++ bitInWord = bitInMap & (32 - 1); ++ ++ mask = dev->tnodeMask << bitInWord; ++ ++ map[wordInMap] &= ~mask; ++ map[wordInMap] |= (mask & (val << bitInWord)); ++ ++ if (dev->tnodeWidth > (32 - bitInWord)) { ++ bitInWord = (32 - bitInWord); ++ wordInMap++;; ++ mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); ++ map[wordInMap] &= ~mask; ++ map[wordInMap] |= (mask & (val >> bitInWord)); ++ } ++} ++ ++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, ++ unsigned pos) ++{ ++ __u32 *map = (__u32 *)tn; ++ __u32 bitInMap; ++ __u32 bitInWord; ++ __u32 wordInMap; ++ __u32 val; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ ++ bitInMap = pos * dev->tnodeWidth; ++ wordInMap = bitInMap / 32; ++ bitInWord = bitInMap & (32 - 1); ++ ++ val = map[wordInMap] >> bitInWord; ++ ++ if (dev->tnodeWidth > (32 - bitInWord)) { ++ bitInWord = (32 - bitInWord); ++ wordInMap++;; ++ val |= (map[wordInMap] << bitInWord); ++ } ++ ++ val &= dev->tnodeMask; ++ val <<= dev->chunkGroupBits; ++ ++ return val; ++} ++ ++/* ------------------- End of individual tnode manipulation -----------------*/ ++ ++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ ++ * The look up tree is represented by the top tnode and the number of topLevel ++ * in the tree. 0 means only the level 0 tnode is in the tree. ++ */ ++ ++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ ++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId) ++{ ++ yaffs_Tnode *tn = fStruct->top; ++ __u32 i; ++ int requiredTallness; ++ int level = fStruct->topLevel; ++ ++ /* Check sane level and chunk Id */ ++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunkId > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough topLevel) */ ++ ++ i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (i) { ++ i >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ if (requiredTallness > fStruct->topLevel) ++ return NULL; /* Not tall enough, so we can't find it */ ++ ++ /* Traverse down to level 0 */ ++ while (level > 0 && tn) { ++ tn = tn->internal[(chunkId >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (level - 1) * ++ YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK]; ++ level--; ++ } ++ ++ return tn; ++} ++ ++/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. ++ * This happens in two steps: ++ * 1. If the tree isn't tall enough, then make it taller. ++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. ++ * ++ * Used when modifying the tree. ++ * ++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will ++ * be plugged into the ttree. ++ */ ++ ++static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId, ++ yaffs_Tnode *passedTn) ++{ ++ int requiredTallness; ++ int i; ++ int l; ++ yaffs_Tnode *tn; ++ ++ __u32 x; ++ ++ ++ /* Check sane level and page Id */ ++ if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunkId > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough topLevel) */ ++ ++ x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (x) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ ++ if (requiredTallness > fStruct->topLevel) { ++ /* Not tall enough, gotta make the tree taller */ ++ for (i = fStruct->topLevel; i < requiredTallness; i++) { ++ ++ tn = yaffs_GetTnode(dev); ++ ++ if (tn) { ++ tn->internal[0] = fStruct->top; ++ fStruct->top = tn; ++ } else { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs: no more tnodes" TENDSTR))); ++ } ++ } ++ ++ fStruct->topLevel = requiredTallness; ++ } ++ ++ /* Traverse down to level 0, adding anything we need */ ++ ++ l = fStruct->topLevel; ++ tn = fStruct->top; ++ ++ if (l > 0) { ++ while (l > 0 && tn) { ++ x = (chunkId >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK; ++ ++ ++ if ((l > 1) && !tn->internal[x]) { ++ /* Add missing non-level-zero tnode */ ++ tn->internal[x] = yaffs_GetTnode(dev); ++ ++ } else if (l == 1) { ++ /* Looking from level 1 at level 0 */ ++ if (passedTn) { ++ /* If we already have one, then release it.*/ ++ if (tn->internal[x]) ++ yaffs_FreeTnode(dev, tn->internal[x]); ++ tn->internal[x] = passedTn; ++ ++ } else if (!tn->internal[x]) { ++ /* Don't have one, none passed in */ ++ tn->internal[x] = yaffs_GetTnode(dev); ++ } ++ } ++ ++ tn = tn->internal[x]; ++ l--; ++ } ++ } else { ++ /* top is level 0 */ ++ if (passedTn) { ++ memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); ++ yaffs_FreeTnode(dev, passedTn); ++ } ++ } ++ ++ return tn; ++} ++ ++static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, ++ yaffs_ExtendedTags *tags, int objectId, ++ int chunkInInode) ++{ ++ int j; ++ ++ for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { ++ if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock, ++ theChunk % dev->nChunksPerBlock)) { ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, ++ tags); ++ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { ++ /* found it; */ ++ return theChunk; ++ } ++ } ++ theChunk++; ++ } ++ return -1; ++} ++ ++ ++/* DeleteWorker scans backwards through the tnode tree and deletes all the ++ * chunks and tnodes in the file ++ * Returns 1 if the tree was deleted. ++ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. ++ */ ++ ++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, ++ int chunkOffset, int *limit) ++{ ++ int i; ++ int chunkInInode; ++ int theChunk; ++ yaffs_ExtendedTags tags; ++ int foundChunk; ++ yaffs_Device *dev = in->myDev; ++ ++ int allDone = 1; ++ ++ if (tn) { ++ if (level > 0) { ++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ if (limit && (*limit) < 0) { ++ allDone = 0; ++ } else { ++ allDone = ++ yaffs_DeleteWorker(in, ++ tn-> ++ internal ++ [i], ++ level - ++ 1, ++ (chunkOffset ++ << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i, ++ limit); ++ } ++ if (allDone) { ++ yaffs_FreeTnode(dev, ++ tn-> ++ internal[i]); ++ tn->internal[i] = NULL; ++ } ++ } ++ } ++ return (allDone) ? 1 : 0; ++ } else if (level == 0) { ++ int hitLimit = 0; ++ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; ++ i--) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk) { ++ ++ chunkInInode = (chunkOffset << ++ YAFFS_TNODES_LEVEL0_BITS) + i; ++ ++ foundChunk = ++ yaffs_FindChunkInGroup(dev, ++ theChunk, ++ &tags, ++ in->objectId, ++ chunkInInode); ++ ++ if (foundChunk > 0) { ++ yaffs_DeleteChunk(dev, ++ foundChunk, 1, ++ __LINE__); ++ in->nDataChunks--; ++ if (limit) { ++ *limit = *limit - 1; ++ if (*limit <= 0) ++ hitLimit = 1; ++ } ++ ++ } ++ ++ yaffs_PutLevel0Tnode(dev, tn, i, 0); ++ } ++ ++ } ++ return (i < 0) ? 1 : 0; ++ ++ } ++ ++ } ++ ++ return 1; ++ ++} ++ ++static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) ++{ ++ yaffs_BlockInfo *theBlock; ++ ++ T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); ++ ++ theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); ++ if (theBlock) { ++ theBlock->softDeletions++; ++ dev->nFreeChunks++; ++ } ++} ++ ++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. ++ * All soft deleting does is increment the block's softdelete count and pulls the chunk out ++ * of the tnode. ++ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. ++ */ ++ ++static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ int theChunk; ++ int allDone = 1; ++ yaffs_Device *dev = in->myDev; ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ allDone = ++ yaffs_SoftDeleteWorker(in, ++ tn-> ++ internal[i], ++ level - 1, ++ (chunkOffset ++ << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i); ++ if (allDone) { ++ yaffs_FreeTnode(dev, ++ tn-> ++ internal[i]); ++ tn->internal[i] = NULL; ++ } else { ++ /* Hoosterman... how could this happen? */ ++ } ++ } ++ } ++ return (allDone) ? 1 : 0; ++ } else if (level == 0) { ++ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk) { ++ /* Note this does not find the real chunk, only the chunk group. ++ * We make an assumption that a chunk group is not larger than ++ * a block. ++ */ ++ yaffs_SoftDeleteChunk(dev, theChunk); ++ yaffs_PutLevel0Tnode(dev, tn, i, 0); ++ } ++ ++ } ++ return 1; ++ ++ } ++ ++ } ++ ++ return 1; ++ ++} ++ ++static void yaffs_SoftDeleteFile(yaffs_Object *obj) ++{ ++ if (obj->deleted && ++ obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { ++ if (obj->nDataChunks <= 0) { ++ /* Empty file with no duplicate object headers, just delete it immediately */ ++ yaffs_FreeTnode(obj->myDev, ++ obj->variant.fileVariant.top); ++ obj->variant.fileVariant.top = NULL; ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: Deleting empty file %d" TENDSTR), ++ obj->objectId)); ++ yaffs_DoGenericObjectDeletion(obj); ++ } else { ++ yaffs_SoftDeleteWorker(obj, ++ obj->variant.fileVariant.top, ++ obj->variant.fileVariant. ++ topLevel, 0); ++ obj->softDeleted = 1; ++ } ++ } ++} ++ ++/* Pruning removes any part of the file structure tree that is beyond the ++ * bounds of the file (ie that does not point to chunks). ++ * ++ * A file should only get pruned when its size is reduced. ++ * ++ * Before pruning, the chunks must be pulled from the tree and the ++ * level 0 tnode entries must be zeroed out. ++ * Could also use this for file deletion, but that's probably better handled ++ * by a special case. ++ */ ++ ++static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, ++ __u32 level, int del0) ++{ ++ int i; ++ int hasData; ++ ++ if (tn) { ++ hasData = 0; ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i] && level > 0) { ++ tn->internal[i] = ++ yaffs_PruneWorker(dev, tn->internal[i], ++ level - 1, ++ (i == 0) ? del0 : 1); ++ } ++ ++ if (tn->internal[i]) ++ hasData++; ++ } ++ ++ if (hasData == 0 && del0) { ++ /* Free and return NULL */ ++ ++ yaffs_FreeTnode(dev, tn); ++ tn = NULL; ++ } ++ ++ } ++ ++ return tn; ++ ++} ++ ++static int yaffs_PruneFileStructure(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct) ++{ ++ int i; ++ int hasData; ++ int done = 0; ++ yaffs_Tnode *tn; ++ ++ if (fStruct->topLevel > 0) { ++ fStruct->top = ++ yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); ++ ++ /* Now we have a tree with all the non-zero branches NULL but the height ++ * is the same as it was. ++ * Let's see if we can trim internal tnodes to shorten the tree. ++ * We can do this if only the 0th element in the tnode is in use ++ * (ie all the non-zero are NULL) ++ */ ++ ++ while (fStruct->topLevel && !done) { ++ tn = fStruct->top; ++ ++ hasData = 0; ++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) ++ hasData++; ++ } ++ ++ if (!hasData) { ++ fStruct->top = tn->internal[0]; ++ fStruct->topLevel--; ++ yaffs_FreeTnode(dev, tn); ++ } else { ++ done = 1; ++ } ++ } ++ } ++ ++ return YAFFS_OK; ++} ++ ++/*-------------------- End of File Structure functions.-------------------*/ ++ ++/* yaffs_CreateFreeObjects creates a bunch more objects and ++ * adds them to the object free list. ++ */ ++static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) ++{ ++ int i; ++ yaffs_Object *newObjects; ++ yaffs_ObjectList *list; ++ ++ if (nObjects < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); ++ list = YMALLOC(sizeof(yaffs_ObjectList)); ++ ++ if (!newObjects || !list) { ++ if (newObjects) ++ YFREE(newObjects); ++ if (list) ++ YFREE(list); ++ T(YAFFS_TRACE_ALLOCATE, ++ (TSTR("yaffs: Could not allocate more objects" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++ for (i = 0; i < nObjects - 1; i++) { ++ newObjects[i].siblings.next = ++ (struct ylist_head *)(&newObjects[i + 1]); ++ } ++ ++ newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; ++ dev->freeObjects = newObjects; ++ dev->nFreeObjects += nObjects; ++ dev->nObjectsCreated += nObjects; ++ ++ /* Now add this bunch of Objects to a list for freeing up. */ ++ ++ list->objects = newObjects; ++ list->next = dev->allocatedObjectList; ++ dev->allocatedObjectList = list; ++ ++ return YAFFS_OK; ++} ++ ++ ++/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ ++static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) ++{ ++ yaffs_Object *tn = NULL; ++ ++#ifdef VALGRIND_TEST ++ tn = YMALLOC(sizeof(yaffs_Object)); ++#else ++ /* If there are none left make more */ ++ if (!dev->freeObjects) ++ yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); ++ ++ if (dev->freeObjects) { ++ tn = dev->freeObjects; ++ dev->freeObjects = ++ (yaffs_Object *) (dev->freeObjects->siblings.next); ++ dev->nFreeObjects--; ++ } ++#endif ++ if (tn) { ++ /* Now sweeten it up... */ ++ ++ memset(tn, 0, sizeof(yaffs_Object)); ++ tn->beingCreated = 1; ++ ++ tn->myDev = dev; ++ tn->hdrChunk = 0; ++ tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; ++ YINIT_LIST_HEAD(&(tn->hardLinks)); ++ YINIT_LIST_HEAD(&(tn->hashLink)); ++ YINIT_LIST_HEAD(&tn->siblings); ++ ++ ++ /* Now make the directory sane */ ++ if (dev->rootDir) { ++ tn->parent = dev->rootDir; ++ ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children); ++ } ++ ++ /* Add it to the lost and found directory. ++ * NB Can't put root or lostNFound in lostNFound so ++ * check if lostNFound exists first ++ */ ++ if (dev->lostNFoundDir) ++ yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); ++ ++ tn->beingCreated = 0; ++ } ++ ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++ ++ return tn; ++} ++ ++static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, ++ __u32 mode) ++{ ++ ++ yaffs_Object *obj = ++ yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (obj) { ++ obj->fake = 1; /* it is fake so it might have no NAND presence... */ ++ obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ ++ obj->unlinkAllowed = 0; /* ... or unlink it */ ++ obj->deleted = 0; ++ obj->unlinked = 0; ++ obj->yst_mode = mode; ++ obj->myDev = dev; ++ obj->hdrChunk = 0; /* Not a valid chunk. */ ++ } ++ ++ return obj; ++ ++} ++ ++static void yaffs_UnhashObject(yaffs_Object *tn) ++{ ++ int bucket; ++ yaffs_Device *dev = tn->myDev; ++ ++ /* If it is still linked into the bucket list, free from the list */ ++ if (!ylist_empty(&tn->hashLink)) { ++ ylist_del_init(&tn->hashLink); ++ bucket = yaffs_HashFunction(tn->objectId); ++ dev->objectBucket[bucket].count--; ++ } ++} ++ ++/* FreeObject frees up a Object and puts it back on the free list */ ++static void yaffs_FreeObject(yaffs_Object *tn) ++{ ++ yaffs_Device *dev = tn->myDev; ++ ++#ifdef __KERNEL__ ++ T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode)); ++#endif ++ ++ if (tn->parent) ++ YBUG(); ++ if (!ylist_empty(&tn->siblings)) ++ YBUG(); ++ ++ ++#ifdef __KERNEL__ ++ if (tn->myInode) { ++ /* We're still hooked up to a cached inode. ++ * Don't delete now, but mark for later deletion ++ */ ++ tn->deferedFree = 1; ++ return; ++ } ++#endif ++ ++ yaffs_UnhashObject(tn); ++ ++#ifdef VALGRIND_TEST ++ YFREE(tn); ++#else ++ /* Link into the free list. */ ++ tn->siblings.next = (struct ylist_head *)(dev->freeObjects); ++ dev->freeObjects = tn; ++ dev->nFreeObjects++; ++#endif ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++} ++ ++#ifdef __KERNEL__ ++ ++void yaffs_HandleDeferedFree(yaffs_Object *obj) ++{ ++ if (obj->deferedFree) ++ yaffs_FreeObject(obj); ++} ++ ++#endif ++ ++static void yaffs_DeinitialiseObjects(yaffs_Device *dev) ++{ ++ /* Free the list of allocated Objects */ ++ ++ yaffs_ObjectList *tmp; ++ ++ while (dev->allocatedObjectList) { ++ tmp = dev->allocatedObjectList->next; ++ YFREE(dev->allocatedObjectList->objects); ++ YFREE(dev->allocatedObjectList); ++ ++ dev->allocatedObjectList = tmp; ++ } ++ ++ dev->freeObjects = NULL; ++ dev->nFreeObjects = 0; ++} ++ ++static void yaffs_InitialiseObjects(yaffs_Device *dev) ++{ ++ int i; ++ ++ dev->allocatedObjectList = NULL; ++ dev->freeObjects = NULL; ++ dev->nFreeObjects = 0; ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ YINIT_LIST_HEAD(&dev->objectBucket[i].list); ++ dev->objectBucket[i].count = 0; ++ } ++} ++ ++static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) ++{ ++ static int x; ++ int i; ++ int l = 999; ++ int lowest = 999999; ++ ++ /* First let's see if we can find one that's empty. */ ++ ++ for (i = 0; i < 10 && lowest > 0; i++) { ++ x++; ++ x %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->objectBucket[x].count < lowest) { ++ lowest = dev->objectBucket[x].count; ++ l = x; ++ } ++ ++ } ++ ++ /* If we didn't find an empty list, then try ++ * looking a bit further for a short one ++ */ ++ ++ for (i = 0; i < 10 && lowest > 3; i++) { ++ x++; ++ x %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->objectBucket[x].count < lowest) { ++ lowest = dev->objectBucket[x].count; ++ l = x; ++ } ++ ++ } ++ ++ return l; ++} ++ ++static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) ++{ ++ int bucket = yaffs_FindNiceObjectBucket(dev); ++ ++ /* Now find an object value that has not already been taken ++ * by scanning the list. ++ */ ++ ++ int found = 0; ++ struct ylist_head *i; ++ ++ __u32 n = (__u32) bucket; ++ ++ /* yaffs_CheckObjectHashSanity(); */ ++ ++ while (!found) { ++ found = 1; ++ n += YAFFS_NOBJECT_BUCKETS; ++ if (1 || dev->objectBucket[bucket].count > 0) { ++ ylist_for_each(i, &dev->objectBucket[bucket].list) { ++ /* If there is already one in the list */ ++ if (i && ylist_entry(i, yaffs_Object, ++ hashLink)->objectId == n) { ++ found = 0; ++ } ++ } ++ } ++ } ++ ++ return n; ++} ++ ++static void yaffs_HashObject(yaffs_Object *in) ++{ ++ int bucket = yaffs_HashFunction(in->objectId); ++ yaffs_Device *dev = in->myDev; ++ ++ ylist_add(&in->hashLink, &dev->objectBucket[bucket].list); ++ dev->objectBucket[bucket].count++; ++} ++ ++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) ++{ ++ int bucket = yaffs_HashFunction(number); ++ struct ylist_head *i; ++ yaffs_Object *in; ++ ++ ylist_for_each(i, &dev->objectBucket[bucket].list) { ++ /* Look if it is in the list */ ++ if (i) { ++ in = ylist_entry(i, yaffs_Object, hashLink); ++ if (in->objectId == number) { ++#ifdef __KERNEL__ ++ /* Don't tell the VFS about this one if it is defered free */ ++ if (in->deferedFree) ++ return NULL; ++#endif ++ ++ return in; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, ++ yaffs_ObjectType type) ++{ ++ yaffs_Object *theObject; ++ yaffs_Tnode *tn = NULL; ++ ++ if (number < 0) ++ number = yaffs_CreateNewObjectNumber(dev); ++ ++ theObject = yaffs_AllocateEmptyObject(dev); ++ if (!theObject) ++ return NULL; ++ ++ if (type == YAFFS_OBJECT_TYPE_FILE) { ++ tn = yaffs_GetTnode(dev); ++ if (!tn) { ++ yaffs_FreeObject(theObject); ++ return NULL; ++ } ++ } ++ ++ if (theObject) { ++ theObject->fake = 0; ++ theObject->renameAllowed = 1; ++ theObject->unlinkAllowed = 1; ++ theObject->objectId = number; ++ yaffs_HashObject(theObject); ++ theObject->variantType = type; ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(theObject->win_atime); ++ theObject->win_ctime[0] = theObject->win_mtime[0] = ++ theObject->win_atime[0]; ++ theObject->win_ctime[1] = theObject->win_mtime[1] = ++ theObject->win_atime[1]; ++ ++#else ++ ++ theObject->yst_atime = theObject->yst_mtime = ++ theObject->yst_ctime = Y_CURRENT_TIME; ++#endif ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ theObject->variant.fileVariant.fileSize = 0; ++ theObject->variant.fileVariant.scannedFileSize = 0; ++ theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ ++ theObject->variant.fileVariant.topLevel = 0; ++ theObject->variant.fileVariant.top = tn; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ YINIT_LIST_HEAD(&theObject->variant.directoryVariant. ++ children); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* No action required */ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* todo this should not happen */ ++ break; ++ } ++ } ++ ++ return theObject; ++} ++ ++static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, ++ int number, ++ yaffs_ObjectType type) ++{ ++ yaffs_Object *theObject = NULL; ++ ++ if (number > 0) ++ theObject = yaffs_FindObjectByNumber(dev, number); ++ ++ if (!theObject) ++ theObject = yaffs_CreateNewObject(dev, number, type); ++ ++ return theObject; ++ ++} ++ ++ ++static YCHAR *yaffs_CloneString(const YCHAR *str) ++{ ++ YCHAR *newStr = NULL; ++ ++ if (str && *str) { ++ newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); ++ if (newStr) ++ yaffs_strcpy(newStr, str); ++ } ++ ++ return newStr; ++ ++} ++ ++/* ++ * Mknod (create) a new object. ++ * equivalentObject only has meaning for a hard link; ++ * aliasString only has meaning for a sumlink. ++ * rdev only has meaning for devices (a subset of special objects) ++ */ ++ ++static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, ++ yaffs_Object *parent, ++ const YCHAR *name, ++ __u32 mode, ++ __u32 uid, ++ __u32 gid, ++ yaffs_Object *equivalentObject, ++ const YCHAR *aliasString, __u32 rdev) ++{ ++ yaffs_Object *in; ++ YCHAR *str = NULL; ++ ++ yaffs_Device *dev = parent->myDev; ++ ++ /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ ++ if (yaffs_FindObjectByName(parent, name)) ++ return NULL; ++ ++ in = yaffs_CreateNewObject(dev, -1, type); ++ ++ if (!in) ++ return YAFFS_FAIL; ++ ++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ str = yaffs_CloneString(aliasString); ++ if (!str) { ++ yaffs_FreeObject(in); ++ return NULL; ++ } ++ } ++ ++ ++ ++ if (in) { ++ in->hdrChunk = 0; ++ in->valid = 1; ++ in->variantType = type; ++ ++ in->yst_mode = mode; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(in->win_atime); ++ in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; ++ in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; ++ ++#else ++ in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; ++ ++ in->yst_rdev = rdev; ++ in->yst_uid = uid; ++ in->yst_gid = gid; ++#endif ++ in->nDataChunks = 0; ++ ++ yaffs_SetObjectName(in, name); ++ in->dirty = 1; ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ in->myDev = parent->myDev; ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symLinkVariant.alias = str; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardLinkVariant.equivalentObject = ++ equivalentObject; ++ in->variant.hardLinkVariant.equivalentObjectId = ++ equivalentObject->objectId; ++ ylist_add(&in->hardLinks, &equivalentObject->hardLinks); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* do nothing */ ++ break; ++ } ++ ++ if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { ++ /* Could not create the object header, fail the creation */ ++ yaffs_DeleteObject(in); ++ in = NULL; ++ } ++ ++ } ++ ++ return in; ++} ++ ++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, ++ uid, gid, NULL, NULL, 0); ++} ++ ++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, ++ mode, uid, gid, NULL, NULL, 0); ++} ++ ++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, ++ uid, gid, NULL, NULL, rdev); ++} ++ ++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, ++ const YCHAR *alias) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, ++ uid, gid, NULL, alias, 0); ++} ++ ++/* yaffs_Link returns the object id of the equivalent object.*/ ++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, ++ yaffs_Object *equivalentObject) ++{ ++ /* Get the real object in case we were fed a hard link as an equivalent object */ ++ equivalentObject = yaffs_GetEquivalentObject(equivalentObject); ++ ++ if (yaffs_MknodObject ++ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, ++ equivalentObject, NULL, 0)) { ++ return equivalentObject; ++ } else { ++ return NULL; ++ } ++ ++} ++ ++static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, ++ const YCHAR *newName, int force, int shadows) ++{ ++ int unlinkOp; ++ int deleteOp; ++ ++ yaffs_Object *existingTarget; ++ ++ if (newDir == NULL) ++ newDir = obj->parent; /* use the old directory */ ++ ++ if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_ChangeObjectName: newDir is not a directory" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ ++ if (obj->myDev->isYaffs2) ++ unlinkOp = (newDir == obj->myDev->unlinkedDir); ++ else ++ unlinkOp = (newDir == obj->myDev->unlinkedDir ++ && obj->variantType == YAFFS_OBJECT_TYPE_FILE); ++ ++ deleteOp = (newDir == obj->myDev->deletedDir); ++ ++ existingTarget = yaffs_FindObjectByName(newDir, newName); ++ ++ /* If the object is a file going into the unlinked directory, ++ * then it is OK to just stuff it in since duplicate names are allowed. ++ * else only proceed if the new name does not exist and if we're putting ++ * it into a directory. ++ */ ++ if ((unlinkOp || ++ deleteOp || ++ force || ++ (shadows > 0) || ++ !existingTarget) && ++ newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_SetObjectName(obj, newName); ++ obj->dirty = 1; ++ ++ yaffs_AddObjectToDirectory(newDir, obj); ++ ++ if (unlinkOp) ++ obj->unlinked = 1; ++ ++ /* If it is a deletion then we mark it as a shrink for gc purposes. */ ++ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0) ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, ++ yaffs_Object *newDir, const YCHAR *newName) ++{ ++ yaffs_Object *obj = NULL; ++ yaffs_Object *existingTarget = NULL; ++ int force = 0; ++ ++ ++ if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) ++ YBUG(); ++ if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) ++ YBUG(); ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ /* Special case for case insemsitive systems (eg. WinCE). ++ * While look-up is case insensitive, the name isn't. ++ * Therefore we might want to change x.txt to X.txt ++ */ ++ if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) ++ force = 1; ++#endif ++ ++ else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) ++ /* ENAMETOOLONG */ ++ return YAFFS_FAIL; ++ ++ obj = yaffs_FindObjectByName(oldDir, oldName); ++ ++ if (obj && obj->renameAllowed) { ++ ++ /* Now do the handling for an existing target, if there is one */ ++ ++ existingTarget = yaffs_FindObjectByName(newDir, newName); ++ if (existingTarget && ++ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !ylist_empty(&existingTarget->variant.directoryVariant.children)) { ++ /* There is a target that is a non-empty directory, so we fail */ ++ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ ++ } else if (existingTarget && existingTarget != obj) { ++ /* Nuke the target first, using shadowing, ++ * but only if it isn't the same object ++ */ ++ yaffs_ChangeObjectName(obj, newDir, newName, force, ++ existingTarget->objectId); ++ yaffs_UnlinkObject(existingTarget); ++ } ++ ++ return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); ++ } ++ return YAFFS_FAIL; ++} ++ ++/*------------------------- Block Management and Page Allocation ----------------*/ ++ ++static int yaffs_InitialiseBlocks(yaffs_Device *dev) ++{ ++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; ++ ++ dev->blockInfo = NULL; ++ dev->chunkBits = NULL; ++ ++ dev->allocationBlock = -1; /* force it to get a new one */ ++ ++ /* If the first allocation strategy fails, thry the alternate one */ ++ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); ++ if (!dev->blockInfo) { ++ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); ++ dev->blockInfoAlt = 1; ++ } else ++ dev->blockInfoAlt = 0; ++ ++ if (dev->blockInfo) { ++ /* Set up dynamic blockinfo stuff. */ ++ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ ++ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); ++ if (!dev->chunkBits) { ++ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); ++ dev->chunkBitsAlt = 1; ++ } else ++ dev->chunkBitsAlt = 0; ++ } ++ ++ if (dev->blockInfo && dev->chunkBits) { ++ memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); ++ memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) ++{ ++ if (dev->blockInfoAlt && dev->blockInfo) ++ YFREE_ALT(dev->blockInfo); ++ else if (dev->blockInfo) ++ YFREE(dev->blockInfo); ++ ++ dev->blockInfoAlt = 0; ++ ++ dev->blockInfo = NULL; ++ ++ if (dev->chunkBitsAlt && dev->chunkBits) ++ YFREE_ALT(dev->chunkBits); ++ else if (dev->chunkBits) ++ YFREE(dev->chunkBits); ++ dev->chunkBitsAlt = 0; ++ dev->chunkBits = NULL; ++} ++ ++static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, ++ yaffs_BlockInfo *bi) ++{ ++ int i; ++ __u32 seq; ++ yaffs_BlockInfo *b; ++ ++ if (!dev->isYaffs2) ++ return 1; /* disqualification only applies to yaffs2. */ ++ ++ if (!bi->hasShrinkHeader) ++ return 1; /* can gc */ ++ ++ /* Find the oldest dirty sequence number if we don't know it and save it ++ * so we don't have to keep recomputing it. ++ */ ++ if (!dev->oldestDirtySequence) { ++ seq = dev->sequenceNumber; ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; ++ i++) { ++ b = yaffs_GetBlockInfo(dev, i); ++ if (b->blockState == YAFFS_BLOCK_STATE_FULL && ++ (b->pagesInUse - b->softDeletions) < ++ dev->nChunksPerBlock && b->sequenceNumber < seq) { ++ seq = b->sequenceNumber; ++ } ++ } ++ dev->oldestDirtySequence = seq; ++ } ++ ++ /* Can't do gc of this block if there are any blocks older than this one that have ++ * discarded pages. ++ */ ++ return (bi->sequenceNumber <= dev->oldestDirtySequence); ++} ++ ++/* FindDiretiestBlock is used to select the dirtiest block (or close enough) ++ * for garbage collection. ++ */ ++ ++static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, ++ int aggressive) ++{ ++ int b = dev->currentDirtyChecker; ++ ++ int i; ++ int iterations; ++ int dirtiest = -1; ++ int pagesInUse = 0; ++ int prioritised = 0; ++ yaffs_BlockInfo *bi; ++ int pendingPrioritisedExist = 0; ++ ++ /* First let's see if we need to grab a prioritised block */ ++ if (dev->hasPendingPrioritisedGCs) { ++ for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) { ++ ++ bi = yaffs_GetBlockInfo(dev, i); ++ /* yaffs_VerifyBlock(dev,bi,i); */ ++ ++ if (bi->gcPrioritise) { ++ pendingPrioritisedExist = 1; ++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL && ++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { ++ pagesInUse = (bi->pagesInUse - bi->softDeletions); ++ dirtiest = i; ++ prioritised = 1; ++ aggressive = 1; /* Fool the non-aggressive skip logiv below */ ++ } ++ } ++ } ++ ++ if (!pendingPrioritisedExist) /* None found, so we can clear this */ ++ dev->hasPendingPrioritisedGCs = 0; ++ } ++ ++ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and ++ * search harder. ++ * else (we're doing a leasurely gc), then we only bother to do this if the ++ * block has only a few pages in use. ++ */ ++ ++ dev->nonAggressiveSkip--; ++ ++ if (!aggressive && (dev->nonAggressiveSkip > 0)) ++ return -1; ++ ++ if (!prioritised) ++ pagesInUse = ++ (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; ++ ++ if (aggressive) ++ iterations = ++ dev->internalEndBlock - dev->internalStartBlock + 1; ++ else { ++ iterations = ++ dev->internalEndBlock - dev->internalStartBlock + 1; ++ iterations = iterations / 16; ++ if (iterations > 200) ++ iterations = 200; ++ } ++ ++ for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { ++ b++; ++ if (b < dev->internalStartBlock || b > dev->internalEndBlock) ++ b = dev->internalStartBlock; ++ ++ if (b < dev->internalStartBlock || b > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> Block %d is not valid" TENDSTR), b)); ++ YBUG(); ++ } ++ ++ bi = yaffs_GetBlockInfo(dev, b); ++ ++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL && ++ (bi->pagesInUse - bi->softDeletions) < pagesInUse && ++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { ++ dirtiest = b; ++ pagesInUse = (bi->pagesInUse - bi->softDeletions); ++ } ++ } ++ ++ dev->currentDirtyChecker = b; ++ ++ if (dirtiest > 0) { ++ T(YAFFS_TRACE_GC, ++ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, ++ dev->nChunksPerBlock - pagesInUse, prioritised)); ++ } ++ ++ dev->oldestDirtySequence = 0; ++ ++ if (dirtiest > 0) ++ dev->nonAggressiveSkip = 4; ++ ++ return dirtiest; ++} ++ ++static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) ++{ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); ++ ++ int erasedOk = 0; ++ ++ /* If the block is still healthy erase it and mark as clean. ++ * If the block has had a data failure, then retire it. ++ */ ++ ++ T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, ++ (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), ++ blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); ++ ++ bi->blockState = YAFFS_BLOCK_STATE_DIRTY; ++ ++ if (!bi->needsRetiring) { ++ yaffs_InvalidateCheckpoint(dev); ++ erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); ++ if (!erasedOk) { ++ dev->nErasureFailures++; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); ++ } ++ } ++ ++ if (erasedOk && ++ ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { ++ int i; ++ for (i = 0; i < dev->nChunksPerBlock; i++) { ++ if (!yaffs_CheckChunkErased ++ (dev, blockNo * dev->nChunksPerBlock + i)) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ (">>Block %d erasure supposedly OK, but chunk %d not erased" ++ TENDSTR), blockNo, i)); ++ } ++ } ++ } ++ ++ if (erasedOk) { ++ /* Clean it up... */ ++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ bi->hasShrinkHeader = 0; ++ bi->skipErasedCheck = 1; /* This is clean, so no need to check */ ++ bi->gcPrioritise = 0; ++ yaffs_ClearChunkBits(dev, blockNo); ++ ++ T(YAFFS_TRACE_ERASE, ++ (TSTR("Erased block %d" TENDSTR), blockNo)); ++ } else { ++ dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ ++ ++ yaffs_RetireBlock(dev, blockNo); ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Block %d retired" TENDSTR), blockNo)); ++ } ++} ++ ++static int yaffs_FindBlockForAllocation(yaffs_Device *dev) ++{ ++ int i; ++ ++ yaffs_BlockInfo *bi; ++ ++ if (dev->nErasedBlocks < 1) { ++ /* Hoosterman we've got a problem. ++ * Can't get space to gc ++ */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); ++ ++ return -1; ++ } ++ ++ /* Find an empty block. */ ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ dev->allocationBlockFinder++; ++ if (dev->allocationBlockFinder < dev->internalStartBlock ++ || dev->allocationBlockFinder > dev->internalEndBlock) { ++ dev->allocationBlockFinder = dev->internalStartBlock; ++ } ++ ++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); ++ ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { ++ bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->sequenceNumber++; ++ bi->sequenceNumber = dev->sequenceNumber; ++ dev->nErasedBlocks--; ++ T(YAFFS_TRACE_ALLOCATE, ++ (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), ++ dev->allocationBlockFinder, dev->sequenceNumber, ++ dev->nErasedBlocks)); ++ return dev->allocationBlockFinder; ++ } ++ } ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs tragedy: no more erased blocks, but there should have been %d" ++ TENDSTR), dev->nErasedBlocks)); ++ ++ return -1; ++} ++ ++ ++ ++static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) ++{ ++ if (!dev->nCheckpointBlocksRequired && ++ dev->isYaffs2) { ++ /* Not a valid value so recalculate */ ++ int nBytes = 0; ++ int nBlocks; ++ int devBlocks = (dev->endBlock - dev->startBlock + 1); ++ int tnodeSize; ++ ++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ nBytes += sizeof(yaffs_CheckpointValidity); ++ nBytes += sizeof(yaffs_CheckpointDevice); ++ nBytes += devBlocks * sizeof(yaffs_BlockInfo); ++ nBytes += devBlocks * dev->chunkBitmapStride; ++ nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects); ++ nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes); ++ nBytes += sizeof(yaffs_CheckpointValidity); ++ nBytes += sizeof(__u32); /* checksum*/ ++ ++ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ ++ ++ nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3; ++ ++ dev->nCheckpointBlocksRequired = nBlocks; ++ } ++ ++ return dev->nCheckpointBlocksRequired; ++} ++ ++/* ++ * Check if there's space to allocate... ++ * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? ++ */ ++static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) ++{ ++ int reservedChunks; ++ int reservedBlocks = dev->nReservedBlocks; ++ int checkpointBlocks; ++ ++ if (dev->isYaffs2) { ++ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - ++ dev->blocksInCheckpoint; ++ if (checkpointBlocks < 0) ++ checkpointBlocks = 0; ++ } else { ++ checkpointBlocks = 0; ++ } ++ ++ reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); ++ ++ return (dev->nFreeChunks > reservedChunks); ++} ++ ++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, ++ yaffs_BlockInfo **blockUsedPtr) ++{ ++ int retVal; ++ yaffs_BlockInfo *bi; ++ ++ if (dev->allocationBlock < 0) { ++ /* Get next block to allocate off */ ++ dev->allocationBlock = yaffs_FindBlockForAllocation(dev); ++ dev->allocationPage = 0; ++ } ++ ++ if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { ++ /* Not enough space to allocate unless we're allowed to use the reserve. */ ++ return -1; ++ } ++ ++ if (dev->nErasedBlocks < dev->nReservedBlocks ++ && dev->allocationPage == 0) { ++ T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); ++ } ++ ++ /* Next page please.... */ ++ if (dev->allocationBlock >= 0) { ++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); ++ ++ retVal = (dev->allocationBlock * dev->nChunksPerBlock) + ++ dev->allocationPage; ++ bi->pagesInUse++; ++ yaffs_SetChunkBit(dev, dev->allocationBlock, ++ dev->allocationPage); ++ ++ dev->allocationPage++; ++ ++ dev->nFreeChunks--; ++ ++ /* If the block is full set the state to full */ ++ if (dev->allocationPage >= dev->nChunksPerBlock) { ++ bi->blockState = YAFFS_BLOCK_STATE_FULL; ++ dev->allocationBlock = -1; ++ } ++ ++ if (blockUsedPtr) ++ *blockUsedPtr = bi; ++ ++ return retVal; ++ } ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); ++ ++ return -1; ++} ++ ++static int yaffs_GetErasedChunks(yaffs_Device *dev) ++{ ++ int n; ++ ++ n = dev->nErasedBlocks * dev->nChunksPerBlock; ++ ++ if (dev->allocationBlock > 0) ++ n += (dev->nChunksPerBlock - dev->allocationPage); ++ ++ return n; ++ ++} ++ ++static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, ++ int wholeBlock) ++{ ++ int oldChunk; ++ int newChunk; ++ int markNAND; ++ int retVal = YAFFS_OK; ++ int cleanups = 0; ++ int i; ++ int isCheckpointBlock; ++ int matchingChunk; ++ int maxCopies; ++ ++ int chunksBefore = yaffs_GetErasedChunks(dev); ++ int chunksAfter; ++ ++ yaffs_ExtendedTags tags; ++ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); ++ ++ yaffs_Object *object; ++ ++ isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); ++ ++ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; ++ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), ++ block, ++ bi->pagesInUse, ++ bi->hasShrinkHeader, ++ wholeBlock)); ++ ++ /*yaffs_VerifyFreeChunks(dev); */ ++ ++ bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ ++ ++ /* Take off the number of soft deleted entries because ++ * they're going to get really deleted during GC. ++ */ ++ dev->nFreeChunks -= bi->softDeletions; ++ ++ dev->isDoingGC = 1; ++ ++ if (isCheckpointBlock || ++ !yaffs_StillSomeChunkBits(dev, block)) { ++ T(YAFFS_TRACE_TRACING, ++ (TSTR ++ ("Collecting block %d that has no chunks in use" TENDSTR), ++ block)); ++ yaffs_BlockBecameDirty(dev, block); ++ } else { ++ ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ yaffs_VerifyBlock(dev, bi, block); ++ ++ maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; ++ oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; ++ ++ for (/* init already done */; ++ retVal == YAFFS_OK && ++ dev->gcChunk < dev->nChunksPerBlock && ++ (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) && ++ maxCopies > 0; ++ dev->gcChunk++, oldChunk++) { ++ if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) { ++ ++ /* This page is in use and might need to be copied off */ ++ ++ maxCopies--; ++ ++ markNAND = 1; ++ ++ yaffs_InitialiseTags(&tags); ++ ++ yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, ++ buffer, &tags); ++ ++ object = ++ yaffs_FindObjectByNumber(dev, ++ tags.objectId); ++ ++ T(YAFFS_TRACE_GC_DETAIL, ++ (TSTR ++ ("Collecting chunk in block %d, %d %d %d " TENDSTR), ++ dev->gcChunk, tags.objectId, tags.chunkId, ++ tags.byteCount)); ++ ++ if (object && !yaffs_SkipVerification(dev)) { ++ if (tags.chunkId == 0) ++ matchingChunk = object->hdrChunk; ++ else if (object->softDeleted) ++ matchingChunk = oldChunk; /* Defeat the test */ ++ else ++ matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL); ++ ++ if (oldChunk != matchingChunk) ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), ++ oldChunk, matchingChunk, tags.objectId, tags.chunkId)); ++ ++ } ++ ++ if (!object) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("page %d in gc has no object: %d %d %d " ++ TENDSTR), oldChunk, ++ tags.objectId, tags.chunkId, tags.byteCount)); ++ } ++ ++ if (object && ++ object->deleted && ++ object->softDeleted && ++ tags.chunkId != 0) { ++ /* Data chunk in a soft deleted file, throw it away ++ * It's a soft deleted data chunk, ++ * No need to copy this, just forget about it and ++ * fix up the object. ++ */ ++ ++ object->nDataChunks--; ++ ++ if (object->nDataChunks <= 0) { ++ /* remeber to clean up the object */ ++ dev->gcCleanupList[cleanups] = ++ tags.objectId; ++ cleanups++; ++ } ++ markNAND = 0; ++ } else if (0) { ++ /* Todo object && object->deleted && object->nDataChunks == 0 */ ++ /* Deleted object header with no data chunks. ++ * Can be discarded and the file deleted. ++ */ ++ object->hdrChunk = 0; ++ yaffs_FreeTnode(object->myDev, ++ object->variant. ++ fileVariant.top); ++ object->variant.fileVariant.top = NULL; ++ yaffs_DoGenericObjectDeletion(object); ++ ++ } else if (object) { ++ /* It's either a data chunk in a live file or ++ * an ObjectHeader, so we're interested in it. ++ * NB Need to keep the ObjectHeaders of deleted files ++ * until the whole file has been deleted off ++ */ ++ tags.serialNumber++; ++ ++ dev->nGCCopies++; ++ ++ if (tags.chunkId == 0) { ++ /* It is an object Id, ++ * We need to nuke the shrinkheader flags first ++ * We no longer want the shrinkHeader flag since its work is done ++ * and if it is left in place it will mess up scanning. ++ */ ++ ++ yaffs_ObjectHeader *oh; ++ oh = (yaffs_ObjectHeader *)buffer; ++ oh->isShrink = 0; ++ tags.extraIsShrinkHeader = 0; ++ ++ yaffs_VerifyObjectHeader(object, oh, &tags, 1); ++ } ++ ++ newChunk = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); ++ ++ if (newChunk < 0) { ++ retVal = YAFFS_FAIL; ++ } else { ++ ++ /* Ok, now fix up the Tnodes etc. */ ++ ++ if (tags.chunkId == 0) { ++ /* It's a header */ ++ object->hdrChunk = newChunk; ++ object->serial = tags.serialNumber; ++ } else { ++ /* It's a data chunk */ ++ yaffs_PutChunkIntoFile ++ (object, ++ tags.chunkId, ++ newChunk, 0); ++ } ++ } ++ } ++ ++ if (retVal == YAFFS_OK) ++ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); ++ ++ } ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ ++ ++ /* Do any required cleanups */ ++ for (i = 0; i < cleanups; i++) { ++ /* Time to delete the file too */ ++ object = ++ yaffs_FindObjectByNumber(dev, ++ dev->gcCleanupList[i]); ++ if (object) { ++ yaffs_FreeTnode(dev, ++ object->variant.fileVariant. ++ top); ++ object->variant.fileVariant.top = NULL; ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: About to finally delete object %d" ++ TENDSTR), object->objectId)); ++ yaffs_DoGenericObjectDeletion(object); ++ object->myDev->nDeletedFiles--; ++ } ++ ++ } ++ ++ } ++ ++ yaffs_VerifyCollectedBlock(dev, bi, block); ++ ++ chunksAfter = yaffs_GetErasedChunks(dev); ++ if (chunksBefore >= chunksAfter) { ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("gc did not increase free chunks before %d after %d" ++ TENDSTR), chunksBefore, chunksAfter)); ++ } ++ ++ /* If the gc completed then clear the current gcBlock so that we find another. */ ++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->gcBlock = -1; ++ dev->gcChunk = 0; ++ } ++ ++ dev->isDoingGC = 0; ++ ++ return retVal; ++} ++ ++/* New garbage collector ++ * If we're very low on erased blocks then we do aggressive garbage collection ++ * otherwise we do "leasurely" garbage collection. ++ * Aggressive gc looks further (whole array) and will accept less dirty blocks. ++ * Passive gc only inspects smaller areas and will only accept more dirty blocks. ++ * ++ * The idea is to help clear out space in a more spread-out manner. ++ * Dunno if it really does anything useful. ++ */ ++static int yaffs_CheckGarbageCollection(yaffs_Device *dev) ++{ ++ int block; ++ int aggressive; ++ int gcOk = YAFFS_OK; ++ int maxTries = 0; ++ ++ int checkpointBlockAdjust; ++ ++ if (dev->isDoingGC) { ++ /* Bail out so we don't get recursive gc */ ++ return YAFFS_OK; ++ } ++ ++ /* This loop should pass the first time. ++ * We'll only see looping here if the erase of the collected block fails. ++ */ ++ ++ do { ++ maxTries++; ++ ++ checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; ++ if (checkpointBlockAdjust < 0) ++ checkpointBlockAdjust = 0; ++ ++ if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { ++ /* We need a block soon...*/ ++ aggressive = 1; ++ } else { ++ /* We're in no hurry */ ++ aggressive = 0; ++ } ++ ++ if (dev->gcBlock <= 0) { ++ dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); ++ dev->gcChunk = 0; ++ } ++ ++ block = dev->gcBlock; ++ ++ if (block > 0) { ++ dev->garbageCollections++; ++ if (!aggressive) ++ dev->passiveGarbageCollections++; ++ ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), ++ dev->nErasedBlocks, aggressive)); ++ ++ gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); ++ } ++ ++ if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" ++ TENDSTR), dev->nErasedBlocks, maxTries, block)); ++ } ++ } while ((dev->nErasedBlocks < dev->nReservedBlocks) && ++ (block > 0) && ++ (maxTries < 2)); ++ ++ return aggressive ? gcOk : YAFFS_OK; ++} ++ ++/*------------------------- TAGS --------------------------------*/ ++ ++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, ++ int chunkInObject) ++{ ++ return (tags->chunkId == chunkInObject && ++ tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0; ++ ++} ++ ++ ++/*-------------------- Data file manipulation -----------------*/ ++ ++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags) ++{ ++ /*Get the Tnode, then get the level 0 offset chunk offset */ ++ yaffs_Tnode *tn; ++ int theChunk = -1; ++ yaffs_ExtendedTags localTags; ++ int retVal = -1; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &localTags; ++ } ++ ++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); ++ ++ if (tn) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ retVal = ++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, ++ chunkInInode); ++ } ++ return retVal; ++} ++ ++static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags) ++{ ++ /* Get the Tnode, then get the level 0 offset chunk offset */ ++ yaffs_Tnode *tn; ++ int theChunk = -1; ++ yaffs_ExtendedTags localTags; ++ ++ yaffs_Device *dev = in->myDev; ++ int retVal = -1; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &localTags; ++ } ++ ++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); ++ ++ if (tn) { ++ ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ retVal = ++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, ++ chunkInInode); ++ ++ /* Delete the entry in the filestructure (if found) */ ++ if (retVal != -1) ++ yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); ++ } ++ ++ return retVal; ++} ++ ++#ifdef YAFFS_PARANOID ++ ++static int yaffs_CheckFileSanity(yaffs_Object *in) ++{ ++ int chunk; ++ int nChunks; ++ int fSize; ++ int failed = 0; ++ int objId; ++ yaffs_Tnode *tn; ++ yaffs_Tags localTags; ++ yaffs_Tags *tags = &localTags; ++ int theChunk; ++ int chunkDeleted; ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ objId = in->objectId; ++ fSize = in->variant.fileVariant.fileSize; ++ nChunks = ++ (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; ++ ++ for (chunk = 1; chunk <= nChunks; chunk++) { ++ tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, ++ chunk); ++ ++ if (tn) { ++ ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); ++ ++ if (yaffs_CheckChunkBits ++ (dev, theChunk / dev->nChunksPerBlock, ++ theChunk % dev->nChunksPerBlock)) { ++ ++ yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, ++ tags, ++ &chunkDeleted); ++ if (yaffs_TagsMatch ++ (tags, in->objectId, chunk, chunkDeleted)) { ++ /* found it; */ ++ ++ } ++ } else { ++ ++ failed = 1; ++ } ++ ++ } else { ++ /* T(("No level 0 found for %d\n", chunk)); */ ++ } ++ } ++ ++ return failed ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++#endif ++ ++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, ++ int chunkInNAND, int inScan) ++{ ++ /* NB inScan is zero unless scanning. ++ * For forward scanning, inScan is > 0; ++ * for backward scanning inScan is < 0 ++ */ ++ ++ yaffs_Tnode *tn; ++ yaffs_Device *dev = in->myDev; ++ int existingChunk; ++ yaffs_ExtendedTags existingTags; ++ yaffs_ExtendedTags newTags; ++ unsigned existingSerial, newSerial; ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { ++ /* Just ignore an attempt at putting a chunk into a non-file during scanning ++ * If it is not during Scanning then something went wrong! ++ */ ++ if (!inScan) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy:attempt to put data chunk into a non-file" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ ++ tn = yaffs_AddOrFindLevel0Tnode(dev, ++ &in->variant.fileVariant, ++ chunkInInode, ++ NULL); ++ if (!tn) ++ return YAFFS_FAIL; ++ ++ existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ if (inScan != 0) { ++ /* If we're scanning then we need to test for duplicates ++ * NB This does not need to be efficient since it should only ever ++ * happen when the power fails during a write, then only one ++ * chunk should ever be affected. ++ * ++ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO ++ * Update: For backward scanning we don't need to re-read tags so this is quite cheap. ++ */ ++ ++ if (existingChunk > 0) { ++ /* NB Right now existing chunk will not be real chunkId if the device >= 32MB ++ * thus we have to do a FindChunkInFile to get the real chunk id. ++ * ++ * We have a duplicate now we need to decide which one to use: ++ * ++ * Backwards scanning YAFFS2: The old one is what we use, dump the new one. ++ * Forward scanning YAFFS2: The new one is what we use, dump the old one. ++ * YAFFS1: Get both sets of tags and compare serial numbers. ++ */ ++ ++ if (inScan > 0) { ++ /* Only do this for forward scanning */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, ++ chunkInNAND, ++ NULL, &newTags); ++ ++ /* Do a proper find */ ++ existingChunk = ++ yaffs_FindChunkInFile(in, chunkInInode, ++ &existingTags); ++ } ++ ++ if (existingChunk <= 0) { ++ /*Hoosterman - how did this happen? */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: existing chunk < 0 in scan" ++ TENDSTR))); ++ ++ } ++ ++ /* NB The deleted flags should be false, otherwise the chunks will ++ * not be loaded during a scan ++ */ ++ ++ if (inScan > 0) { ++ newSerial = newTags.serialNumber; ++ existingSerial = existingTags.serialNumber; ++ } ++ ++ if ((inScan > 0) && ++ (in->myDev->isYaffs2 || ++ existingChunk <= 0 || ++ ((existingSerial + 1) & 3) == newSerial)) { ++ /* Forward scanning. ++ * Use new ++ * Delete the old one and drop through to update the tnode ++ */ ++ yaffs_DeleteChunk(dev, existingChunk, 1, ++ __LINE__); ++ } else { ++ /* Backward scanning or we want to use the existing one ++ * Use existing. ++ * Delete the new one and return early so that the tnode isn't changed ++ */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, ++ __LINE__); ++ return YAFFS_OK; ++ } ++ } ++ ++ } ++ ++ if (existingChunk == 0) ++ in->nDataChunks++; ++ ++ yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode, ++ __u8 *buffer) ++{ ++ int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); ++ ++ if (chunkInNAND >= 0) ++ return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, ++ buffer, NULL); ++ else { ++ T(YAFFS_TRACE_NANDACCESS, ++ (TSTR("Chunk %d not found zero instead" TENDSTR), ++ chunkInNAND)); ++ /* get sane (zero) data if you read a hole */ ++ memset(buffer, 0, in->myDev->nDataBytesPerChunk); ++ return 0; ++ } ++ ++} ++ ++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) ++{ ++ int block; ++ int page; ++ yaffs_ExtendedTags tags; ++ yaffs_BlockInfo *bi; ++ ++ if (chunkId <= 0) ++ return; ++ ++ dev->nDeletions++; ++ block = chunkId / dev->nChunksPerBlock; ++ page = chunkId % dev->nChunksPerBlock; ++ ++ ++ if (!yaffs_CheckChunkBit(dev, block, page)) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Deleting invalid chunk %d"TENDSTR), ++ chunkId)); ++ ++ bi = yaffs_GetBlockInfo(dev, block); ++ ++ T(YAFFS_TRACE_DELETION, ++ (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); ++ ++ if (markNAND && ++ bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { ++ ++ yaffs_InitialiseTags(&tags); ++ ++ tags.chunkDeleted = 1; ++ ++ yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags); ++ yaffs_HandleUpdateChunk(dev, chunkId, &tags); ++ } else { ++ dev->nUnmarkedDeletions++; ++ } ++ ++ /* Pull out of the management area. ++ * If the whole block became dirty, this will kick off an erasure. ++ */ ++ if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || ++ bi->blockState == YAFFS_BLOCK_STATE_FULL || ++ bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->nFreeChunks++; ++ ++ yaffs_ClearChunkBit(dev, block, page); ++ ++ bi->pagesInUse--; ++ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && ++ bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ yaffs_BlockBecameDirty(dev, block); ++ } ++ ++ } ++ ++} ++ ++static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, ++ const __u8 *buffer, int nBytes, ++ int useReserve) ++{ ++ /* Find old chunk Need to do this to get serial number ++ * Write new one and patch into tree. ++ * Invalidate old tags. ++ */ ++ ++ int prevChunkId; ++ yaffs_ExtendedTags prevTags; ++ ++ int newChunkId; ++ yaffs_ExtendedTags newTags; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ yaffs_CheckGarbageCollection(dev); ++ ++ /* Get the previous chunk at this location in the file if it exists */ ++ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); ++ ++ /* Set up new tags */ ++ yaffs_InitialiseTags(&newTags); ++ ++ newTags.chunkId = chunkInInode; ++ newTags.objectId = in->objectId; ++ newTags.serialNumber = ++ (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; ++ newTags.byteCount = nBytes; ++ ++ if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); ++ YBUG(); ++ } ++ ++ newChunkId = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, ++ useReserve); ++ ++ if (newChunkId >= 0) { ++ yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); ++ ++ if (prevChunkId >= 0) ++ yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); ++ ++ yaffs_CheckFileSanity(in); ++ } ++ return newChunkId; ++ ++} ++ ++/* UpdateObjectHeader updates the header on NAND for an object. ++ * If name is not NULL, then that new name is used. ++ */ ++int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, ++ int isShrink, int shadows) ++{ ++ ++ yaffs_BlockInfo *bi; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ int prevChunkId; ++ int retVal = 0; ++ int result = 0; ++ ++ int newChunkId; ++ yaffs_ExtendedTags newTags; ++ yaffs_ExtendedTags oldTags; ++ ++ __u8 *buffer = NULL; ++ YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ yaffs_ObjectHeader *oh = NULL; ++ ++ yaffs_strcpy(oldName, _Y("silly old name")); ++ ++ ++ if (!in->fake || ++ in == dev->rootDir || /* The rootDir should also be saved */ ++ force) { ++ ++ yaffs_CheckGarbageCollection(dev); ++ yaffs_CheckObjectDetailsLoaded(in); ++ ++ buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); ++ oh = (yaffs_ObjectHeader *) buffer; ++ ++ prevChunkId = in->hdrChunk; ++ ++ if (prevChunkId > 0) { ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, ++ buffer, &oldTags); ++ ++ yaffs_VerifyObjectHeader(in, oh, &oldTags, 0); ++ ++ memcpy(oldName, oh->name, sizeof(oh->name)); ++ } ++ ++ memset(buffer, 0xFF, dev->nDataBytesPerChunk); ++ ++ oh->type = in->variantType; ++ oh->yst_mode = in->yst_mode; ++ oh->shadowsObject = oh->inbandShadowsObject = shadows; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ oh->win_atime[0] = in->win_atime[0]; ++ oh->win_ctime[0] = in->win_ctime[0]; ++ oh->win_mtime[0] = in->win_mtime[0]; ++ oh->win_atime[1] = in->win_atime[1]; ++ oh->win_ctime[1] = in->win_ctime[1]; ++ oh->win_mtime[1] = in->win_mtime[1]; ++#else ++ oh->yst_uid = in->yst_uid; ++ oh->yst_gid = in->yst_gid; ++ oh->yst_atime = in->yst_atime; ++ oh->yst_mtime = in->yst_mtime; ++ oh->yst_ctime = in->yst_ctime; ++ oh->yst_rdev = in->yst_rdev; ++#endif ++ if (in->parent) ++ oh->parentObjectId = in->parent->objectId; ++ else ++ oh->parentObjectId = 0; ++ ++ if (name && *name) { ++ memset(oh->name, 0, sizeof(oh->name)); ++ yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); ++ } else if (prevChunkId >= 0) ++ memcpy(oh->name, oldName, sizeof(oh->name)); ++ else ++ memset(oh->name, 0, sizeof(oh->name)); ++ ++ oh->isShrink = isShrink; ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Should not happen */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ oh->fileSize = ++ (oh->parentObjectId == YAFFS_OBJECTID_DELETED ++ || oh->parentObjectId == ++ YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. ++ fileVariant.fileSize; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ oh->equivalentObjectId = ++ in->variant.hardLinkVariant.equivalentObjectId; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_strncpy(oh->alias, ++ in->variant.symLinkVariant.alias, ++ YAFFS_MAX_ALIAS_LENGTH); ++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; ++ break; ++ } ++ ++ /* Tags */ ++ yaffs_InitialiseTags(&newTags); ++ in->serial++; ++ newTags.chunkId = 0; ++ newTags.objectId = in->objectId; ++ newTags.serialNumber = in->serial; ++ ++ /* Add extra info for file header */ ++ ++ newTags.extraHeaderInfoAvailable = 1; ++ newTags.extraParentObjectId = oh->parentObjectId; ++ newTags.extraFileLength = oh->fileSize; ++ newTags.extraIsShrinkHeader = oh->isShrink; ++ newTags.extraEquivalentObjectId = oh->equivalentObjectId; ++ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; ++ newTags.extraObjectType = in->variantType; ++ ++ yaffs_VerifyObjectHeader(in, oh, &newTags, 1); ++ ++ /* Create new chunk in NAND */ ++ newChunkId = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, ++ (prevChunkId >= 0) ? 1 : 0); ++ ++ if (newChunkId >= 0) { ++ ++ in->hdrChunk = newChunkId; ++ ++ if (prevChunkId >= 0) { ++ yaffs_DeleteChunk(dev, prevChunkId, 1, ++ __LINE__); ++ } ++ ++ if (!yaffs_ObjectHasCachedWriteData(in)) ++ in->dirty = 0; ++ ++ /* If this was a shrink, then mark the block that the chunk lives on */ ++ if (isShrink) { ++ bi = yaffs_GetBlockInfo(in->myDev, ++ newChunkId / in->myDev->nChunksPerBlock); ++ bi->hasShrinkHeader = 1; ++ } ++ ++ } ++ ++ retVal = newChunkId; ++ ++ } ++ ++ if (buffer) ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ ++ return retVal; ++} ++ ++/*------------------------ Short Operations Cache ---------------------------------------- ++ * In many situations where there is no high level buffering (eg WinCE) a lot of ++ * reads might be short sequential reads, and a lot of writes may be short ++ * sequential writes. eg. scanning/writing a jpeg file. ++ * In these cases, a short read/write cache can provide a huge perfomance benefit ++ * with dumb-as-a-rock code. ++ * In Linux, the page cache provides read buffering aand the short op cache provides write ++ * buffering. ++ * ++ * There are a limited number (~10) of cache chunks per device so that we don't ++ * need a very intelligent search. ++ */ ++ ++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int i; ++ yaffs_ChunkCache *cache; ++ int nCaches = obj->myDev->nShortOpCaches; ++ ++ for (i = 0; i < nCaches; i++) { ++ cache = &dev->srCache[i]; ++ if (cache->object == obj && ++ cache->dirty) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int lowest = -99; /* Stop compiler whining. */ ++ int i; ++ yaffs_ChunkCache *cache; ++ int chunkWritten = 0; ++ int nCaches = obj->myDev->nShortOpCaches; ++ ++ if (nCaches > 0) { ++ do { ++ cache = NULL; ++ ++ /* Find the dirty cache for this object with the lowest chunk id. */ ++ for (i = 0; i < nCaches; i++) { ++ if (dev->srCache[i].object == obj && ++ dev->srCache[i].dirty) { ++ if (!cache ++ || dev->srCache[i].chunkId < ++ lowest) { ++ cache = &dev->srCache[i]; ++ lowest = cache->chunkId; ++ } ++ } ++ } ++ ++ if (cache && !cache->locked) { ++ /* Write it out and free it up */ ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(cache->object, ++ cache->chunkId, ++ cache->data, ++ cache->nBytes, ++ 1); ++ cache->dirty = 0; ++ cache->object = NULL; ++ } ++ ++ } while (cache && chunkWritten > 0); ++ ++ if (cache) { ++ /* Hoosterman, disk full while writing cache out. */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); ++ ++ } ++ } ++ ++} ++ ++/*yaffs_FlushEntireDeviceCache(dev) ++ * ++ * ++ */ ++ ++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ int nCaches = dev->nShortOpCaches; ++ int i; ++ ++ /* Find a dirty object in the cache and flush it... ++ * until there are no further dirty objects. ++ */ ++ do { ++ obj = NULL; ++ for (i = 0; i < nCaches && !obj; i++) { ++ if (dev->srCache[i].object && ++ dev->srCache[i].dirty) ++ obj = dev->srCache[i].object; ++ ++ } ++ if (obj) ++ yaffs_FlushFilesChunkCache(obj); ++ ++ } while (obj); ++ ++} ++ ++ ++/* Grab us a cache chunk for use. ++ * First look for an empty one. ++ * Then look for the least recently used non-dirty one. ++ * Then look for the least recently used dirty one...., flush and look again. ++ */ ++static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) ++{ ++ int i; ++ ++ if (dev->nShortOpCaches > 0) { ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (!dev->srCache[i].object) ++ return &dev->srCache[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) ++{ ++ yaffs_ChunkCache *cache; ++ yaffs_Object *theObj; ++ int usage; ++ int i; ++ int pushout; ++ ++ if (dev->nShortOpCaches > 0) { ++ /* Try find a non-dirty one... */ ++ ++ cache = yaffs_GrabChunkCacheWorker(dev); ++ ++ if (!cache) { ++ /* They were all dirty, find the last recently used object and flush ++ * its cache, then find again. ++ * NB what's here is not very accurate, we actually flush the object ++ * the last recently used page. ++ */ ++ ++ /* With locking we can't assume we can use entry zero */ ++ ++ theObj = NULL; ++ usage = -1; ++ cache = NULL; ++ pushout = -1; ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object && ++ !dev->srCache[i].locked && ++ (dev->srCache[i].lastUse < usage || !cache)) { ++ usage = dev->srCache[i].lastUse; ++ theObj = dev->srCache[i].object; ++ cache = &dev->srCache[i]; ++ pushout = i; ++ } ++ } ++ ++ if (!cache || cache->dirty) { ++ /* Flush and try again */ ++ yaffs_FlushFilesChunkCache(theObj); ++ cache = yaffs_GrabChunkCacheWorker(dev); ++ } ++ ++ } ++ return cache; ++ } else ++ return NULL; ++ ++} ++ ++/* Find a cached chunk */ ++static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, ++ int chunkId) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int i; ++ if (dev->nShortOpCaches > 0) { ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object == obj && ++ dev->srCache[i].chunkId == chunkId) { ++ dev->cacheHits++; ++ ++ return &dev->srCache[i]; ++ } ++ } ++ } ++ return NULL; ++} ++ ++/* Mark the chunk for the least recently used algorithym */ ++static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, ++ int isAWrite) ++{ ++ ++ if (dev->nShortOpCaches > 0) { ++ if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { ++ /* Reset the cache usages */ ++ int i; ++ for (i = 1; i < dev->nShortOpCaches; i++) ++ dev->srCache[i].lastUse = 0; ++ ++ dev->srLastUse = 0; ++ } ++ ++ dev->srLastUse++; ++ ++ cache->lastUse = dev->srLastUse; ++ ++ if (isAWrite) ++ cache->dirty = 1; ++ } ++} ++ ++/* Invalidate a single cache page. ++ * Do this when a whole page gets written, ++ * ie the short cache for this page is no longer valid. ++ */ ++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) ++{ ++ if (object->myDev->nShortOpCaches > 0) { ++ yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); ++ ++ if (cache) ++ cache->object = NULL; ++ } ++} ++ ++/* Invalidate all the cache pages associated with this object ++ * Do this whenever ther file is deleted or resized. ++ */ ++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) ++{ ++ int i; ++ yaffs_Device *dev = in->myDev; ++ ++ if (dev->nShortOpCaches > 0) { ++ /* Invalidate it. */ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object == in) ++ dev->srCache[i].object = NULL; ++ } ++ } ++} ++ ++/*--------------------- Checkpointing --------------------*/ ++ ++ ++static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head) ++{ ++ yaffs_CheckpointValidity cp; ++ ++ memset(&cp, 0, sizeof(cp)); ++ ++ cp.structType = sizeof(cp); ++ cp.magic = YAFFS_MAGIC; ++ cp.version = YAFFS_CHECKPOINT_VERSION; ++ cp.head = (head) ? 1 : 0; ++ ++ return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ? ++ 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) ++{ ++ yaffs_CheckpointValidity cp; ++ int ok; ++ ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ if (ok) ++ ok = (cp.structType == sizeof(cp)) && ++ (cp.magic == YAFFS_MAGIC) && ++ (cp.version == YAFFS_CHECKPOINT_VERSION) && ++ (cp.head == ((head) ? 1 : 0)); ++ return ok ? 1 : 0; ++} ++ ++static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, ++ yaffs_Device *dev) ++{ ++ cp->nErasedBlocks = dev->nErasedBlocks; ++ cp->allocationBlock = dev->allocationBlock; ++ cp->allocationPage = dev->allocationPage; ++ cp->nFreeChunks = dev->nFreeChunks; ++ ++ cp->nDeletedFiles = dev->nDeletedFiles; ++ cp->nUnlinkedFiles = dev->nUnlinkedFiles; ++ cp->nBackgroundDeletions = dev->nBackgroundDeletions; ++ cp->sequenceNumber = dev->sequenceNumber; ++ cp->oldestDirtySequence = dev->oldestDirtySequence; ++ ++} ++ ++static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, ++ yaffs_CheckpointDevice *cp) ++{ ++ dev->nErasedBlocks = cp->nErasedBlocks; ++ dev->allocationBlock = cp->allocationBlock; ++ dev->allocationPage = cp->allocationPage; ++ dev->nFreeChunks = cp->nFreeChunks; ++ ++ dev->nDeletedFiles = cp->nDeletedFiles; ++ dev->nUnlinkedFiles = cp->nUnlinkedFiles; ++ dev->nBackgroundDeletions = cp->nBackgroundDeletions; ++ dev->sequenceNumber = cp->sequenceNumber; ++ dev->oldestDirtySequence = cp->oldestDirtySequence; ++} ++ ++ ++static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) ++{ ++ yaffs_CheckpointDevice cp; ++ __u32 nBytes; ++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); ++ ++ int ok; ++ ++ /* Write device runtime values*/ ++ yaffs_DeviceToCheckpointDevice(&cp, dev); ++ cp.structType = sizeof(cp); ++ ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ /* Write block info */ ++ if (ok) { ++ nBytes = nBlocks * sizeof(yaffs_BlockInfo); ++ ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes); ++ } ++ ++ /* Write chunk bits */ ++ if (ok) { ++ nBytes = nBlocks * dev->chunkBitmapStride; ++ ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes); ++ } ++ return ok ? 1 : 0; ++ ++} ++ ++static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) ++{ ++ yaffs_CheckpointDevice cp; ++ __u32 nBytes; ++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); ++ ++ int ok; ++ ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ ++ if (cp.structType != sizeof(cp)) ++ return 0; ++ ++ ++ yaffs_CheckpointDeviceToDevice(dev, &cp); ++ ++ nBytes = nBlocks * sizeof(yaffs_BlockInfo); ++ ++ ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes); ++ ++ if (!ok) ++ return 0; ++ nBytes = nBlocks * dev->chunkBitmapStride; ++ ++ ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes); ++ ++ return ok ? 1 : 0; ++} ++ ++static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, ++ yaffs_Object *obj) ++{ ++ ++ cp->objectId = obj->objectId; ++ cp->parentId = (obj->parent) ? obj->parent->objectId : 0; ++ cp->hdrChunk = obj->hdrChunk; ++ cp->variantType = obj->variantType; ++ cp->deleted = obj->deleted; ++ cp->softDeleted = obj->softDeleted; ++ cp->unlinked = obj->unlinked; ++ cp->fake = obj->fake; ++ cp->renameAllowed = obj->renameAllowed; ++ cp->unlinkAllowed = obj->unlinkAllowed; ++ cp->serial = obj->serial; ++ cp->nDataChunks = obj->nDataChunks; ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; ++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) ++ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; ++} ++ ++static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp) ++{ ++ ++ yaffs_Object *parent; ++ ++ if (obj->variantType != cp->variantType) { ++ T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " ++ TCONT("chunk %d does not match existing object type %d") ++ TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, ++ obj->variantType)); ++ return 0; ++ } ++ ++ obj->objectId = cp->objectId; ++ ++ if (cp->parentId) ++ parent = yaffs_FindOrCreateObjectByNumber( ++ obj->myDev, ++ cp->parentId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ else ++ parent = NULL; ++ ++ if (parent) { ++ if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" ++ TCONT(" chunk %d Parent type, %d, not directory") ++ TENDSTR), ++ cp->objectId, cp->parentId, cp->variantType, ++ cp->hdrChunk, parent->variantType)); ++ return 0; ++ } ++ yaffs_AddObjectToDirectory(parent, obj); ++ } ++ ++ obj->hdrChunk = cp->hdrChunk; ++ obj->variantType = cp->variantType; ++ obj->deleted = cp->deleted; ++ obj->softDeleted = cp->softDeleted; ++ obj->unlinked = cp->unlinked; ++ obj->fake = cp->fake; ++ obj->renameAllowed = cp->renameAllowed; ++ obj->unlinkAllowed = cp->unlinkAllowed; ++ obj->serial = cp->serial; ++ obj->nDataChunks = cp->nDataChunks; ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; ++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) ++ obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; ++ ++ if (obj->hdrChunk > 0) ++ obj->lazyLoaded = 1; ++ return 1; ++} ++ ++ ++ ++static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ yaffs_Device *dev = in->myDev; ++ int ok = 1; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (tn->internal[i]) { ++ ok = yaffs_CheckpointTnodeWorker(in, ++ tn->internal[i], ++ level - 1, ++ (chunkOffset<variantType == YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs_CheckpointTnodeWorker(obj, ++ obj->variant.fileVariant.top, ++ obj->variant.fileVariant.topLevel, ++ 0); ++ if (ok) ++ ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) == ++ sizeof(endMarker)); ++ } ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) ++{ ++ __u32 baseChunk; ++ int ok = 1; ++ yaffs_Device *dev = obj->myDev; ++ yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; ++ yaffs_Tnode *tn; ++ int nread = 0; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); ++ ++ while (ok && (~baseChunk)) { ++ nread++; ++ /* Read level 0 tnode */ ++ ++ ++ tn = yaffs_GetTnodeRaw(dev); ++ if (tn) ++ ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize); ++ else ++ ok = 0; ++ ++ if (tn && ok) ++ ok = yaffs_AddOrFindLevel0Tnode(dev, ++ fileStructPtr, ++ baseChunk, ++ tn) ? 1 : 0; ++ ++ if (ok) ++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); ++ ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, ( ++ TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), ++ nread, baseChunk, ok)); ++ ++ return ok ? 1 : 0; ++} ++ ++ ++static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ yaffs_CheckpointObject cp; ++ int i; ++ int ok = 1; ++ struct ylist_head *lh; ++ ++ ++ /* Iterate through the objects in each hash entry, ++ * dumping them to the checkpointing stream. ++ */ ++ ++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { ++ ylist_for_each(lh, &dev->objectBucket[i].list) { ++ if (lh) { ++ obj = ylist_entry(lh, yaffs_Object, hashLink); ++ if (!obj->deferedFree) { ++ yaffs_ObjectToCheckpointObject(&cp, obj); ++ cp.structType = sizeof(cp); ++ ++ T(YAFFS_TRACE_CHECKPOINT, ( ++ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), ++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj)); ++ ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ ok = yaffs_WriteCheckpointTnodes(obj); ++ } ++ } ++ } ++ } ++ ++ /* Dump end of list */ ++ memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject)); ++ cp.structType = sizeof(cp); ++ ++ if (ok) ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ yaffs_CheckpointObject cp; ++ int ok = 1; ++ int done = 0; ++ yaffs_Object *hardList = NULL; ++ ++ while (ok && !done) { ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (cp.structType != sizeof(cp)) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), ++ cp.structType, sizeof(cp), ok)); ++ ok = 0; ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), ++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk)); ++ ++ if (ok && cp.objectId == ~0) ++ done = 1; ++ else if (ok) { ++ obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType); ++ if (obj) { ++ ok = yaffs_CheckpointObjectToObject(obj, &cp); ++ if (!ok) ++ break; ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs_ReadCheckpointTnodes(obj); ++ } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj->hardLinks.next = ++ (struct ylist_head *) hardList; ++ hardList = obj; ++ } ++ } else ++ ok = 0; ++ } ++ } ++ ++ if (ok) ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_WriteCheckpointSum(yaffs_Device *dev) ++{ ++ __u32 checkpointSum; ++ int ok; ++ ++ yaffs_GetCheckpointSum(dev, &checkpointSum); ++ ++ ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum)); ++ ++ if (!ok) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs_ReadCheckpointSum(yaffs_Device *dev) ++{ ++ __u32 checkpointSum0; ++ __u32 checkpointSum1; ++ int ok; ++ ++ yaffs_GetCheckpointSum(dev, &checkpointSum0); ++ ++ ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1)); ++ ++ if (!ok) ++ return 0; ++ ++ if (checkpointSum0 != checkpointSum1) ++ return 0; ++ ++ return 1; ++} ++ ++ ++static int yaffs_WriteCheckpointData(yaffs_Device *dev) ++{ ++ int ok = 1; ++ ++ if (dev->skipCheckpointWrite || !dev->isYaffs2) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs_CheckpointOpen(dev, 1); ++ ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); ++ ok = yaffs_WriteCheckpointValidityMarker(dev, 1); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); ++ ok = yaffs_WriteCheckpointDevice(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); ++ ok = yaffs_WriteCheckpointObjects(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); ++ ok = yaffs_WriteCheckpointValidityMarker(dev, 0); ++ } ++ ++ if (ok) ++ ok = yaffs_WriteCheckpointSum(dev); ++ ++ if (!yaffs_CheckpointClose(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->isCheckpointed = 1; ++ else ++ dev->isCheckpointed = 0; ++ ++ return dev->isCheckpointed; ++} ++ ++static int yaffs_ReadCheckpointData(yaffs_Device *dev) ++{ ++ int ok = 1; ++ ++ if (dev->skipCheckpointRead || !dev->isYaffs2) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs_CheckpointOpen(dev, 0); /* open for read */ ++ ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); ++ ok = yaffs_ReadCheckpointValidityMarker(dev, 1); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); ++ ok = yaffs_ReadCheckpointDevice(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); ++ ok = yaffs_ReadCheckpointObjects(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); ++ ok = yaffs_ReadCheckpointValidityMarker(dev, 0); ++ } ++ ++ if (ok) { ++ ok = yaffs_ReadCheckpointSum(dev); ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); ++ } ++ ++ if (!yaffs_CheckpointClose(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->isCheckpointed = 1; ++ else ++ dev->isCheckpointed = 0; ++ ++ return ok ? 1 : 0; ++ ++} ++ ++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) ++{ ++ if (dev->isCheckpointed || ++ dev->blocksInCheckpoint > 0) { ++ dev->isCheckpointed = 0; ++ yaffs_CheckpointInvalidateStream(dev); ++ if (dev->superBlock && dev->markSuperBlockDirty) ++ dev->markSuperBlockDirty(dev->superBlock); ++ } ++} ++ ++ ++int yaffs_CheckpointSave(yaffs_Device *dev) ++{ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ yaffs_VerifyObjects(dev); ++ yaffs_VerifyBlocks(dev); ++ yaffs_VerifyFreeChunks(dev); ++ ++ if (!dev->isCheckpointed) { ++ yaffs_InvalidateCheckpoint(dev); ++ yaffs_WriteCheckpointData(dev); ++ } ++ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ return dev->isCheckpointed; ++} ++ ++int yaffs_CheckpointRestore(yaffs_Device *dev) ++{ ++ int retval; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ retval = yaffs_ReadCheckpointData(dev); ++ ++ if (dev->isCheckpointed) { ++ yaffs_VerifyObjects(dev); ++ yaffs_VerifyBlocks(dev); ++ yaffs_VerifyFreeChunks(dev); ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ return retval; ++} ++ ++/*--------------------- File read/write ------------------------ ++ * Read and write have very similar structures. ++ * In general the read/write has three parts to it ++ * An incomplete chunk to start with (if the read/write is not chunk-aligned) ++ * Some complete chunks ++ * An incomplete chunk to end off with ++ * ++ * Curve-balls: the first chunk might also be the last chunk. ++ */ ++ ++int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, ++ int nBytes) ++{ ++ ++ int chunk; ++ __u32 start; ++ int nToCopy; ++ int n = nBytes; ++ int nDone = 0; ++ yaffs_ChunkCache *cache; ++ ++ yaffs_Device *dev; ++ ++ dev = in->myDev; ++ ++ while (n > 0) { ++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */ ++ /* start = offset % dev->nDataBytesPerChunk; */ ++ yaffs_AddrToChunk(dev, offset, &chunk, &start); ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ if ((start + n) < dev->nDataBytesPerChunk) ++ nToCopy = n; ++ else ++ nToCopy = dev->nDataBytesPerChunk - start; ++ ++ cache = yaffs_FindChunkCache(in, chunk); ++ ++ /* If the chunk is already in the cache or it is less than a whole chunk ++ * or we're using inband tags then use the cache (if there is caching) ++ * else bypass the cache. ++ */ ++ if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { ++ if (dev->nShortOpCaches > 0) { ++ ++ /* If we can't find the data in the cache, then load it up. */ ++ ++ if (!cache) { ++ cache = yaffs_GrabChunkCache(in->myDev); ++ cache->object = in; ++ cache->chunkId = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ cache-> ++ data); ++ cache->nBytes = 0; ++ } ++ ++ yaffs_UseChunkCache(dev, cache, 0); ++ ++ cache->locked = 1; ++ ++ ++ memcpy(buffer, &cache->data[start], nToCopy); ++ ++ cache->locked = 0; ++ } else { ++ /* Read into the local buffer then copy..*/ ++ ++ __u8 *localBuffer = ++ yaffs_GetTempBuffer(dev, __LINE__); ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ localBuffer); ++ ++ memcpy(buffer, &localBuffer[start], nToCopy); ++ ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, ++ __LINE__); ++ } ++ ++ } else { ++ ++ /* A full chunk. Read directly into the supplied buffer. */ ++ yaffs_ReadChunkDataFromObject(in, chunk, buffer); ++ ++ } ++ ++ n -= nToCopy; ++ offset += nToCopy; ++ buffer += nToCopy; ++ nDone += nToCopy; ++ ++ } ++ ++ return nDone; ++} ++ ++int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, ++ int nBytes, int writeThrough) ++{ ++ ++ int chunk; ++ __u32 start; ++ int nToCopy; ++ int n = nBytes; ++ int nDone = 0; ++ int nToWriteBack; ++ int startOfWrite = offset; ++ int chunkWritten = 0; ++ __u32 nBytesRead; ++ __u32 chunkStart; ++ ++ yaffs_Device *dev; ++ ++ dev = in->myDev; ++ ++ while (n > 0 && chunkWritten >= 0) { ++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */ ++ /* start = offset % dev->nDataBytesPerChunk; */ ++ yaffs_AddrToChunk(dev, offset, &chunk, &start); ++ ++ if (chunk * dev->nDataBytesPerChunk + start != offset || ++ start >= dev->nDataBytesPerChunk) { ++ T(YAFFS_TRACE_ERROR, ( ++ TSTR("AddrToChunk of offset %d gives chunk %d start %d" ++ TENDSTR), ++ (int)offset, chunk, start)); ++ } ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ ++ if ((start + n) < dev->nDataBytesPerChunk) { ++ nToCopy = n; ++ ++ /* Now folks, to calculate how many bytes to write back.... ++ * If we're overwriting and not writing to then end of file then ++ * we need to write back as much as was there before. ++ */ ++ ++ chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk); ++ ++ if (chunkStart > in->variant.fileVariant.fileSize) ++ nBytesRead = 0; /* Past end of file */ ++ else ++ nBytesRead = in->variant.fileVariant.fileSize - chunkStart; ++ ++ if (nBytesRead > dev->nDataBytesPerChunk) ++ nBytesRead = dev->nDataBytesPerChunk; ++ ++ nToWriteBack = ++ (nBytesRead > ++ (start + n)) ? nBytesRead : (start + n); ++ ++ if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk) ++ YBUG(); ++ ++ } else { ++ nToCopy = dev->nDataBytesPerChunk - start; ++ nToWriteBack = dev->nDataBytesPerChunk; ++ } ++ ++ if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { ++ /* An incomplete start or end chunk (or maybe both start and end chunk), ++ * or we're using inband tags, so we want to use the cache buffers. ++ */ ++ if (dev->nShortOpCaches > 0) { ++ yaffs_ChunkCache *cache; ++ /* If we can't find the data in the cache, then load the cache */ ++ cache = yaffs_FindChunkCache(in, chunk); ++ ++ if (!cache ++ && yaffs_CheckSpaceForAllocation(in-> ++ myDev)) { ++ cache = yaffs_GrabChunkCache(in->myDev); ++ cache->object = in; ++ cache->chunkId = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ cache-> ++ data); ++ } else if (cache && ++ !cache->dirty && ++ !yaffs_CheckSpaceForAllocation(in->myDev)) { ++ /* Drop the cache if it was a read cache item and ++ * no space check has been made for it. ++ */ ++ cache = NULL; ++ } ++ ++ if (cache) { ++ yaffs_UseChunkCache(dev, cache, 1); ++ cache->locked = 1; ++ ++ ++ memcpy(&cache->data[start], buffer, ++ nToCopy); ++ ++ ++ cache->locked = 0; ++ cache->nBytes = nToWriteBack; ++ ++ if (writeThrough) { ++ chunkWritten = ++ yaffs_WriteChunkDataToObject ++ (cache->object, ++ cache->chunkId, ++ cache->data, cache->nBytes, ++ 1); ++ cache->dirty = 0; ++ } ++ ++ } else { ++ chunkWritten = -1; /* fail the write */ ++ } ++ } else { ++ /* An incomplete start or end chunk (or maybe both start and end chunk) ++ * Read into the local buffer then copy, then copy over and write back. ++ */ ++ ++ __u8 *localBuffer = ++ yaffs_GetTempBuffer(dev, __LINE__); ++ ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ localBuffer); ++ ++ ++ ++ memcpy(&localBuffer[start], buffer, nToCopy); ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(in, chunk, ++ localBuffer, ++ nToWriteBack, ++ 0); ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, ++ __LINE__); ++ ++ } ++ ++ } else { ++ /* A full chunk. Write directly from the supplied buffer. */ ++ ++ ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(in, chunk, buffer, ++ dev->nDataBytesPerChunk, ++ 0); ++ ++ /* Since we've overwritten the cached data, we better invalidate it. */ ++ yaffs_InvalidateChunkCache(in, chunk); ++ } ++ ++ if (chunkWritten >= 0) { ++ n -= nToCopy; ++ offset += nToCopy; ++ buffer += nToCopy; ++ nDone += nToCopy; ++ } ++ ++ } ++ ++ /* Update file object */ ++ ++ if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) ++ in->variant.fileVariant.fileSize = (startOfWrite + nDone); ++ ++ in->dirty = 1; ++ ++ return nDone; ++} ++ ++ ++/* ---------------------- File resizing stuff ------------------ */ ++ ++static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) ++{ ++ ++ yaffs_Device *dev = in->myDev; ++ int oldFileSize = in->variant.fileVariant.fileSize; ++ ++ int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk; ++ ++ int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) / ++ dev->nDataBytesPerChunk; ++ int i; ++ int chunkId; ++ ++ /* Delete backwards so that we don't end up with holes if ++ * power is lost part-way through the operation. ++ */ ++ for (i = lastDel; i >= startDel; i--) { ++ /* NB this could be optimised somewhat, ++ * eg. could retrieve the tags and write them without ++ * using yaffs_DeleteChunk ++ */ ++ ++ chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); ++ if (chunkId > 0) { ++ if (chunkId < ++ (dev->internalStartBlock * dev->nChunksPerBlock) ++ || chunkId >= ++ ((dev->internalEndBlock + ++ 1) * dev->nChunksPerBlock)) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Found daft chunkId %d for %d" TENDSTR), ++ chunkId, i)); ++ } else { ++ in->nDataChunks--; ++ yaffs_DeleteChunk(dev, chunkId, 1, __LINE__); ++ } ++ } ++ } ++ ++} ++ ++int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) ++{ ++ ++ int oldFileSize = in->variant.fileVariant.fileSize; ++ __u32 newSizeOfPartialChunk; ++ int newFullChunks; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); ++ ++ yaffs_FlushFilesChunkCache(in); ++ yaffs_InvalidateWholeChunkCache(in); ++ ++ yaffs_CheckGarbageCollection(dev); ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ if (newSize == oldFileSize) ++ return YAFFS_OK; ++ ++ if (newSize < oldFileSize) { ++ ++ yaffs_PruneResizedChunks(in, newSize); ++ ++ if (newSizeOfPartialChunk != 0) { ++ int lastChunk = 1 + newFullChunks; ++ ++ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ /* Got to read and rewrite the last chunk with its new size and zero pad */ ++ yaffs_ReadChunkDataFromObject(in, lastChunk, ++ localBuffer); ++ ++ memset(localBuffer + newSizeOfPartialChunk, 0, ++ dev->nDataBytesPerChunk - newSizeOfPartialChunk); ++ ++ yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, ++ newSizeOfPartialChunk, 1); ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); ++ } ++ ++ in->variant.fileVariant.fileSize = newSize; ++ ++ yaffs_PruneFileStructure(dev, &in->variant.fileVariant); ++ } else { ++ /* newsSize > oldFileSize */ ++ in->variant.fileVariant.fileSize = newSize; ++ } ++ ++ ++ /* Write a new object header. ++ * show we've shrunk the file, if need be ++ * Do this only if the file is not in the deleted directories. ++ */ ++ if (in->parent && ++ in->parent->objectId != YAFFS_OBJECTID_UNLINKED && ++ in->parent->objectId != YAFFS_OBJECTID_DELETED) ++ yaffs_UpdateObjectHeader(in, NULL, 0, ++ (newSize < oldFileSize) ? 1 : 0, 0); ++ ++ return YAFFS_OK; ++} ++ ++loff_t yaffs_GetFileSize(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return obj->variant.fileVariant.fileSize; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_strlen(obj->variant.symLinkVariant.alias); ++ default: ++ return 0; ++ } ++} ++ ++ ++ ++int yaffs_FlushFile(yaffs_Object *in, int updateTime) ++{ ++ int retVal; ++ if (in->dirty) { ++ yaffs_FlushFilesChunkCache(in); ++ if (updateTime) { ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(in->win_mtime); ++#else ++ ++ in->yst_mtime = Y_CURRENT_TIME; ++ ++#endif ++ } ++ ++ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= ++ 0) ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ retVal = YAFFS_OK; ++ } ++ ++ return retVal; ++ ++} ++ ++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) ++{ ++ ++ /* First off, invalidate the file's data in the cache, without flushing. */ ++ yaffs_InvalidateWholeChunkCache(in); ++ ++ if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { ++ /* Move to the unlinked directory so we have a record that it was deleted. */ ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0); ++ ++ } ++ ++ yaffs_RemoveObjectFromDirectory(in); ++ yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__); ++ in->hdrChunk = 0; ++ ++ yaffs_FreeObject(in); ++ return YAFFS_OK; ++ ++} ++ ++/* yaffs_DeleteFile deletes the whole file data ++ * and the inode associated with the file. ++ * It does not delete the links associated with the file. ++ */ ++static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) ++{ ++ ++ int retVal; ++ int immediateDeletion = 0; ++ ++#ifdef __KERNEL__ ++ if (!in->myInode) ++ immediateDeletion = 1; ++#else ++ if (in->inUse <= 0) ++ immediateDeletion = 1; ++#endif ++ ++ if (immediateDeletion) { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, ++ _Y("deleted"), 0, 0); ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: immediate deletion of file %d" TENDSTR), ++ in->objectId)); ++ in->deleted = 1; ++ in->myDev->nDeletedFiles++; ++ if (1 || in->myDev->isYaffs2) ++ yaffs_ResizeFile(in, 0); ++ yaffs_SoftDeleteFile(in); ++ } else { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, ++ _Y("unlinked"), 0, 0); ++ } ++ ++ ++ return retVal; ++} ++ ++int yaffs_DeleteFile(yaffs_Object *in) ++{ ++ int retVal = YAFFS_OK; ++ int deleted = in->deleted; ++ ++ yaffs_ResizeFile(in, 0); ++ ++ if (in->nDataChunks > 0) { ++ /* Use soft deletion if there is data in the file. ++ * That won't be the case if it has been resized to zero. ++ */ ++ if (!in->unlinked) ++ retVal = yaffs_UnlinkFileIfNeeded(in); ++ ++ if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { ++ in->deleted = 1; ++ deleted = 1; ++ in->myDev->nDeletedFiles++; ++ yaffs_SoftDeleteFile(in); ++ } ++ return deleted ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ /* The file has no data chunks so we toss it immediately */ ++ yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); ++ in->variant.fileVariant.top = NULL; ++ yaffs_DoGenericObjectDeletion(in); ++ ++ return YAFFS_OK; ++ } ++} ++ ++static int yaffs_DeleteDirectory(yaffs_Object *in) ++{ ++ /* First check that the directory is empty. */ ++ if (ylist_empty(&in->variant.directoryVariant.children)) ++ return yaffs_DoGenericObjectDeletion(in); ++ ++ return YAFFS_FAIL; ++ ++} ++ ++static int yaffs_DeleteSymLink(yaffs_Object *in) ++{ ++ YFREE(in->variant.symLinkVariant.alias); ++ ++ return yaffs_DoGenericObjectDeletion(in); ++} ++ ++static int yaffs_DeleteHardLink(yaffs_Object *in) ++{ ++ /* remove this hardlink from the list assocaited with the equivalent ++ * object ++ */ ++ ylist_del_init(&in->hardLinks); ++ return yaffs_DoGenericObjectDeletion(in); ++} ++ ++int yaffs_DeleteObject(yaffs_Object *obj) ++{ ++int retVal = -1; ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ retVal = yaffs_DeleteFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return yaffs_DeleteDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ retVal = yaffs_DeleteSymLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ retVal = yaffs_DeleteHardLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ retVal = yaffs_DoGenericObjectDeletion(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ retVal = 0; ++ break; /* should not happen. */ ++ } ++ ++ return retVal; ++} ++ ++static int yaffs_UnlinkWorker(yaffs_Object *obj) ++{ ++ ++ int immediateDeletion = 0; ++ ++#ifdef __KERNEL__ ++ if (!obj->myInode) ++ immediateDeletion = 1; ++#else ++ if (obj->inUse <= 0) ++ immediateDeletion = 1; ++#endif ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ return yaffs_DeleteHardLink(obj); ++ } else if (!ylist_empty(&obj->hardLinks)) { ++ /* Curve ball: We're unlinking an object that has a hardlink. ++ * ++ * This problem arises because we are not strictly following ++ * The Linux link/inode model. ++ * ++ * We can't really delete the object. ++ * Instead, we do the following: ++ * - Select a hardlink. ++ * - Unhook it from the hard links ++ * - Unhook it from its parent directory (so that the rename can work) ++ * - Rename the object to the hardlink's name. ++ * - Delete the hardlink ++ */ ++ ++ yaffs_Object *hl; ++ int retVal; ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); ++ ++ ylist_del_init(&hl->hardLinks); ++ ylist_del_init(&hl->siblings); ++ ++ yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); ++ ++ retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); ++ ++ if (retVal == YAFFS_OK) ++ retVal = yaffs_DoGenericObjectDeletion(hl); ++ ++ return retVal; ++ ++ } else if (immediateDeletion) { ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return yaffs_DeleteFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return yaffs_DeleteDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_DeleteSymLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ return yaffs_DoGenericObjectDeletion(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ return YAFFS_FAIL; ++ } ++ } else ++ return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir, ++ _Y("unlinked"), 0, 0); ++} ++ ++ ++static int yaffs_UnlinkObject(yaffs_Object *obj) ++{ ++ ++ if (obj && obj->unlinkAllowed) ++ return yaffs_UnlinkWorker(obj); ++ ++ return YAFFS_FAIL; ++ ++} ++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) ++{ ++ yaffs_Object *obj; ++ ++ obj = yaffs_FindObjectByName(dir, name); ++ return yaffs_UnlinkObject(obj); ++} ++ ++/*----------------------- Initialisation Scanning ---------------------- */ ++ ++static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, ++ int backwardScanning) ++{ ++ yaffs_Object *obj; ++ ++ if (!backwardScanning) { ++ /* Handle YAFFS1 forward scanning case ++ * For YAFFS1 we always do the deletion ++ */ ++ ++ } else { ++ /* Handle YAFFS2 case (backward scanning) ++ * If the shadowed object exists then ignore. ++ */ ++ if (yaffs_FindObjectByNumber(dev, objId)) ++ return; ++ } ++ ++ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. ++ * We put it in unlinked dir to be cleaned up after the scanning ++ */ ++ obj = ++ yaffs_FindOrCreateObjectByNumber(dev, objId, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!obj) ++ return; ++ yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); ++ obj->variant.fileVariant.shrinkSize = 0; ++ obj->valid = 1; /* So that we don't read any other info for this file */ ++ ++} ++ ++typedef struct { ++ int seq; ++ int block; ++} yaffs_BlockIndex; ++ ++ ++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) ++{ ++ yaffs_Object *hl; ++ yaffs_Object *in; ++ ++ while (hardList) { ++ hl = hardList; ++ hardList = (yaffs_Object *) (hardList->hardLinks.next); ++ ++ in = yaffs_FindObjectByNumber(dev, ++ hl->variant.hardLinkVariant. ++ equivalentObjectId); ++ ++ if (in) { ++ /* Add the hardlink pointers */ ++ hl->variant.hardLinkVariant.equivalentObject = in; ++ ylist_add(&hl->hardLinks, &in->hardLinks); ++ } else { ++ /* Todo Need to report/handle this better. ++ * Got a problem... hardlink to a non-existant object ++ */ ++ hl->variant.hardLinkVariant.equivalentObject = NULL; ++ YINIT_LIST_HEAD(&hl->hardLinks); ++ ++ } ++ } ++} ++ ++ ++ ++ ++ ++static int ybicmp(const void *a, const void *b) ++{ ++ register int aseq = ((yaffs_BlockIndex *)a)->seq; ++ register int bseq = ((yaffs_BlockIndex *)b)->seq; ++ register int ablock = ((yaffs_BlockIndex *)a)->block; ++ register int bblock = ((yaffs_BlockIndex *)b)->block; ++ if (aseq == bseq) ++ return ablock - bblock; ++ else ++ return aseq - bseq; ++} ++ ++ ++struct yaffs_ShadowFixerStruct { ++ int objectId; ++ int shadowedId; ++ struct yaffs_ShadowFixerStruct *next; ++}; ++ ++ ++static void yaffs_StripDeletedObjects(yaffs_Device *dev) ++{ ++ /* ++ * Sort out state of unlinked and deleted objects after scanning. ++ */ ++ struct ylist_head *i; ++ struct ylist_head *n; ++ yaffs_Object *l; ++ ++ /* Soft delete all the unlinked files */ ++ ylist_for_each_safe(i, n, ++ &dev->unlinkedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DeleteObject(l); ++ } ++ } ++ ++ ylist_for_each_safe(i, n, ++ &dev->deletedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DeleteObject(l); ++ } ++ } ++ ++} ++ ++static int yaffs_Scan(yaffs_Device *dev) ++{ ++ yaffs_ExtendedTags tags; ++ int blk; ++ int blockIterator; ++ int startIterator; ++ int endIterator; ++ int result; ++ ++ int chunk; ++ int c; ++ int deleted; ++ yaffs_BlockState state; ++ yaffs_Object *hardList = NULL; ++ yaffs_BlockInfo *bi; ++ __u32 sequenceNumber; ++ yaffs_ObjectHeader *oh; ++ yaffs_Object *in; ++ yaffs_Object *parent; ++ ++ int alloc_failed = 0; ++ ++ struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; ++ ++ ++ __u8 *chunkData; ++ ++ ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), ++ dev->internalStartBlock, dev->internalEndBlock)); ++ ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ /* Scan all the blocks to determine their state */ ++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { ++ bi = yaffs_GetBlockInfo(dev, blk); ++ yaffs_ClearChunkBits(dev, blk); ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ ++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); ++ ++ bi->blockState = state; ++ bi->sequenceNumber = sequenceNumber; ++ ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, ++ state, sequenceNumber)); ++ ++ if (state == YAFFS_BLOCK_STATE_DEAD) { ++ T(YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("block %d is bad" TENDSTR), blk)); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block empty " TENDSTR))); ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } ++ } ++ ++ startIterator = dev->internalStartBlock; ++ endIterator = dev->internalEndBlock; ++ ++ /* For each block.... */ ++ for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; ++ blockIterator++) { ++ ++ YYIELD(); ++ ++ YYIELD(); ++ ++ blk = blockIterator; ++ ++ bi = yaffs_GetBlockInfo(dev, blk); ++ state = bi->blockState; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning....*/ ++ for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && ++ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { ++ /* Read the tags and decide what to do */ ++ chunk = blk * dev->nChunksPerBlock + c; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, ++ &tags); ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { ++ /* YAFFS1 only... ++ * A deleted chunk ++ */ ++ deleted++; ++ dev->nFreeChunks++; ++ /*T((" %d %d deleted\n",blk,c)); */ ++ } else if (!tags.chunkUsed) { ++ /* An unassigned chunk in the block ++ * This means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (c == 0) { ++ /* We're looking at the first chunk in the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ } else { ++ /* this is the block being allocated from */ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ (" Allocating from %d %d" TENDSTR), ++ blk, c)); ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->allocationBlock = blk; ++ dev->allocationPage = c; ++ dev->allocationBlockFinder = blk; ++ /* Set it to here to encourage the allocator to go forth from here. */ ++ ++ } ++ ++ dev->nFreeChunks += (dev->nChunksPerBlock - c); ++ } else if (tags.chunkId > 0) { ++ /* chunkId > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ YAFFS_OBJECT_TYPE_FILE); ++ /* PutChunkIntoFile checks for a clash (two data chunks with ++ * the same chunkId). ++ */ ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in) { ++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) ++ alloc_failed = 1; ++ } ++ ++ endpos = ++ (tags.chunkId - 1) * dev->nDataBytesPerChunk + ++ tags.byteCount; ++ if (in && ++ in->variantType == YAFFS_OBJECT_TYPE_FILE ++ && in->variant.fileVariant.scannedFileSize < ++ endpos) { ++ in->variant.fileVariant. ++ scannedFileSize = endpos; ++ if (!dev->useHeaderFileSize) { ++ in->variant.fileVariant. ++ fileSize = ++ in->variant.fileVariant. ++ scannedFileSize; ++ } ++ ++ } ++ /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ ++ } else { ++ /* chunkId == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make the object ++ */ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, ++ chunkData, ++ NULL); ++ ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ in = yaffs_FindObjectByNumber(dev, ++ tags.objectId); ++ if (in && in->variantType != oh->type) { ++ /* This should not happen, but somehow ++ * Wev'e ended up with an objectId that has been reused but not yet ++ * deleted, and worse still it has changed type. Delete the old object. ++ */ ++ ++ yaffs_DeleteObject(in); ++ ++ in = 0; ++ } ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ oh->type); ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in && oh->shadowsObject > 0) { ++ ++ struct yaffs_ShadowFixerStruct *fixer; ++ fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct)); ++ if (fixer) { ++ fixer->next = shadowFixerList; ++ shadowFixerList = fixer; ++ fixer->objectId = tags.objectId; ++ fixer->shadowedId = oh->shadowsObject; ++ } ++ ++ } ++ ++ if (in && in->valid) { ++ /* We have already filled this one. We have a duplicate and need to resolve it. */ ++ ++ unsigned existingSerial = in->serial; ++ unsigned newSerial = tags.serialNumber; ++ ++ if (((existingSerial + 1) & 3) == newSerial) { ++ /* Use new one - destroy the exisiting one */ ++ yaffs_DeleteChunk(dev, ++ in->hdrChunk, ++ 1, __LINE__); ++ in->valid = 0; ++ } else { ++ /* Use existing - destroy this one. */ ++ yaffs_DeleteChunk(dev, chunk, 1, ++ __LINE__); ++ } ++ } ++ ++ if (in && !in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle with directory structure */ ++ in->valid = 1; ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; ++ ++ } else if (in && !in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; ++ ++ yaffs_SetObjectName(in, oh->name); ++ in->dirty = 0; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, oh->parentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (!parent) ++ alloc_failed = 1; ++ if (parent && parent->variantType == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (!parent || parent->variantType != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * We're trying to use a non-directory as a directory ++ */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ TENDSTR))); ++ parent = dev->lostNFoundDir; ++ } ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ if (0 && (parent == dev->deletedDir || ++ parent == dev->unlinkedDir)) { ++ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ ++ dev->nDeletedFiles++; ++ } ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent object is scanned ++ * we put them all in a list. ++ * After scanning is complete, we should have all the objects, so we run through this ++ * list and fix up all the chains. ++ */ ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (dev->useHeaderFileSize) ++ ++ in->variant.fileVariant. ++ fileSize = ++ oh->fileSize; ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardLinkVariant. ++ equivalentObjectId = ++ oh->equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) ++ hardList; ++ hardList = in; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; ++ break; ++ } ++ ++/* ++ if (parent == dev->deletedDir) { ++ yaffs_DestroyObject(in); ++ bi->hasShrinkHeader = 1; ++ } ++*/ ++ } ++ } ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ /* If we got this far while scanning, then the block is fully allocated.*/ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ bi->blockState = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_BlockBecameDirty(dev, blk); ++ } ++ ++ } ++ ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ /* Fix up any shadowed objects */ ++ { ++ struct yaffs_ShadowFixerStruct *fixer; ++ yaffs_Object *obj; ++ ++ while (shadowFixerList) { ++ fixer = shadowFixerList; ++ shadowFixerList = fixer->next; ++ /* Complete the rename transaction by deleting the shadowed object ++ * then setting the object header to unshadowed. ++ */ ++ obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId); ++ if (obj) ++ yaffs_DeleteObject(obj); ++ ++ obj = yaffs_FindObjectByNumber(dev, fixer->objectId); ++ ++ if (obj) ++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); ++ ++ YFREE(fixer); ++ } ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); ++ ++ ++ return YAFFS_OK; ++} ++ ++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) ++{ ++ __u8 *chunkData; ++ yaffs_ObjectHeader *oh; ++ yaffs_Device *dev; ++ yaffs_ExtendedTags tags; ++ int result; ++ int alloc_failed = 0; ++ ++ if (!in) ++ return; ++ ++ dev = in->myDev; ++ ++#if 0 ++ T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR), ++ in->objectId, ++ in->lazyLoaded ? "not yet" : "already")); ++#endif ++ ++ if (in->lazyLoaded && in->hdrChunk > 0) { ++ in->lazyLoaded = 0; ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags); ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++ ++#endif ++ yaffs_SetObjectName(in, oh->name); ++ ++ if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; /* Not returned to caller */ ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ } ++} ++ ++static int yaffs_ScanBackwards(yaffs_Device *dev) ++{ ++ yaffs_ExtendedTags tags; ++ int blk; ++ int blockIterator; ++ int startIterator; ++ int endIterator; ++ int nBlocksToScan = 0; ++ ++ int chunk; ++ int result; ++ int c; ++ int deleted; ++ yaffs_BlockState state; ++ yaffs_Object *hardList = NULL; ++ yaffs_BlockInfo *bi; ++ __u32 sequenceNumber; ++ yaffs_ObjectHeader *oh; ++ yaffs_Object *in; ++ yaffs_Object *parent; ++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; ++ int itsUnlinked; ++ __u8 *chunkData; ++ ++ int fileSize; ++ int isShrink; ++ int foundChunksInBlock; ++ int equivalentObjectId; ++ int alloc_failed = 0; ++ ++ ++ yaffs_BlockIndex *blockIndex = NULL; ++ int altBlockIndex = 0; ++ ++ if (!dev->isYaffs2) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." ++ TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); ++ ++ ++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); ++ ++ if (!blockIndex) { ++ blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); ++ altBlockIndex = 1; ++ } ++ ++ if (!blockIndex) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ dev->blocksInCheckpoint = 0; ++ ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ /* Scan all the blocks to determine their state */ ++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { ++ bi = yaffs_GetBlockInfo(dev, blk); ++ yaffs_ClearChunkBits(dev, blk); ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ ++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); ++ ++ bi->blockState = state; ++ bi->sequenceNumber = sequenceNumber; ++ ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, ++ state, sequenceNumber)); ++ ++ ++ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ dev->blocksInCheckpoint++; ++ ++ } else if (state == YAFFS_BLOCK_STATE_DEAD) { ++ T(YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("block %d is bad" TENDSTR), blk)); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block empty " TENDSTR))); ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ ++ /* Determine the highest sequence number */ ++ if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && ++ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { ++ ++ blockIndex[nBlocksToScan].seq = sequenceNumber; ++ blockIndex[nBlocksToScan].block = blk; ++ ++ nBlocksToScan++; ++ ++ if (sequenceNumber >= dev->sequenceNumber) ++ dev->sequenceNumber = sequenceNumber; ++ } else { ++ /* TODO: Nasty sequence number! */ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ ("Block scanning block %d has bad sequence number %d" ++ TENDSTR), blk, sequenceNumber)); ++ ++ } ++ } ++ } ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); ++ ++ ++ ++ YYIELD(); ++ ++ /* Sort the blocks */ ++#ifndef CONFIG_YAFFS_USE_OWN_SORT ++ { ++ /* Use qsort now. */ ++ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); ++ } ++#else ++ { ++ /* Dungy old bubble sort... */ ++ ++ yaffs_BlockIndex temp; ++ int i; ++ int j; ++ ++ for (i = 0; i < nBlocksToScan; i++) ++ for (j = i + 1; j < nBlocksToScan; j++) ++ if (blockIndex[i].seq > blockIndex[j].seq) { ++ temp = blockIndex[j]; ++ blockIndex[j] = blockIndex[i]; ++ blockIndex[i] = temp; ++ } ++ } ++#endif ++ ++ YYIELD(); ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); ++ ++ /* Now scan the blocks looking at the data. */ ++ startIterator = 0; ++ endIterator = nBlocksToScan - 1; ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); ++ ++ /* For each block.... backwards */ ++ for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; ++ blockIterator--) { ++ /* Cooperative multitasking! This loop can run for so ++ long that watchdog timers expire. */ ++ YYIELD(); ++ ++ /* get the block to scan in the correct order */ ++ blk = blockIndex[blockIterator].block; ++ ++ bi = yaffs_GetBlockInfo(dev, blk); ++ ++ ++ state = bi->blockState; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning.... */ ++ foundChunksInBlock = 0; ++ for (c = dev->nChunksPerBlock - 1; ++ !alloc_failed && c >= 0 && ++ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { ++ /* Scan backwards... ++ * Read the tags and decide what to do ++ */ ++ ++ chunk = blk * dev->nChunksPerBlock + c; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, ++ &tags); ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (!tags.chunkUsed) { ++ /* An unassigned chunk in the block. ++ * If there are used chunks after this one, then ++ * it is a chunk that was skipped due to failing the erased ++ * check. Just skip it so that it can be deleted. ++ * But, more typically, We get here when this is an unallocated ++ * chunk and his means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (foundChunksInBlock) { ++ /* This is a chunk that was skipped due to failing the erased check */ ++ } else if (c == 0) { ++ /* We're looking at the first chunk in the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ } else { ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ if (dev->sequenceNumber == bi->sequenceNumber) { ++ /* this is the block being allocated from */ ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ (" Allocating from %d %d" ++ TENDSTR), blk, c)); ++ ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->allocationBlock = blk; ++ dev->allocationPage = c; ++ dev->allocationBlockFinder = blk; ++ } else { ++ /* This is a partially written block that is not ++ * the current allocation block. This block must have ++ * had a write failure, so set up for retirement. ++ */ ++ ++ /* bi->needsRetiring = 1; ??? TODO */ ++ bi->gcPrioritise = 1; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Partially written block %d detected" TENDSTR), ++ blk)); ++ } ++ } ++ } ++ ++ dev->nFreeChunks++; ++ ++ } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), ++ blk, c)); ++ ++ dev->nFreeChunks++; ++ ++ } else if (tags.chunkId > 0) { ++ /* chunkId > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ __u32 chunkBase = ++ (tags.chunkId - 1) * dev->nDataBytesPerChunk; ++ ++ foundChunksInBlock = 1; ++ ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!in) { ++ /* Out of memory */ ++ alloc_failed = 1; ++ } ++ ++ if (in && ++ in->variantType == YAFFS_OBJECT_TYPE_FILE ++ && chunkBase < ++ in->variant.fileVariant.shrinkSize) { ++ /* This has not been invalidated by a resize */ ++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, ++ chunk, -1)) { ++ alloc_failed = 1; ++ } ++ ++ /* File size is calculated by looking at the data chunks if we have not ++ * seen an object header yet. Stop this practice once we find an object header. ++ */ ++ endpos = ++ (tags.chunkId - ++ 1) * dev->nDataBytesPerChunk + ++ tags.byteCount; ++ ++ if (!in->valid && /* have not got an object header yet */ ++ in->variant.fileVariant. ++ scannedFileSize < endpos) { ++ in->variant.fileVariant. ++ scannedFileSize = endpos; ++ in->variant.fileVariant. ++ fileSize = ++ in->variant.fileVariant. ++ scannedFileSize; ++ } ++ ++ } else if (in) { ++ /* This chunk has been invalidated by a resize, so delete */ ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ ++ } ++ } else { ++ /* chunkId == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make the object ++ */ ++ foundChunksInBlock = 1; ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ oh = NULL; ++ in = NULL; ++ ++ if (tags.extraHeaderInfoAvailable) { ++ in = yaffs_FindOrCreateObjectByNumber ++ (dev, tags.objectId, ++ tags.extraObjectType); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ if (!in || ++#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD ++ !in->valid || ++#endif ++ tags.extraShadows || ++ (!in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) { ++ ++ /* If we don't have valid info then we need to read the chunk ++ * TODO In future we can probably defer reading the chunk and ++ * living with invalid data until needed. ++ */ ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, ++ chunk, ++ chunkData, ++ NULL); ++ ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ if (dev->inbandTags) { ++ /* Fix up the header if they got corrupted by inband tags */ ++ oh->shadowsObject = oh->inbandShadowsObject; ++ oh->isShrink = oh->inbandIsShrink; ++ } ++ ++ if (!in) { ++ in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ } ++ ++ if (!in) { ++ /* TODO Hoosterman we have a problem! */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" ++ TENDSTR), tags.objectId, chunk)); ++ continue; ++ } ++ ++ if (in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate that will be discarded, but ++ * we first have to suck out resize info if it is a file. ++ */ ++ ++ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && ++ ((oh && ++ oh->type == YAFFS_OBJECT_TYPE_FILE) || ++ (tags.extraHeaderInfoAvailable && ++ tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) { ++ __u32 thisSize = ++ (oh) ? oh->fileSize : tags. ++ extraFileLength; ++ __u32 parentObjectId = ++ (oh) ? oh-> ++ parentObjectId : tags. ++ extraParentObjectId; ++ ++ ++ isShrink = ++ (oh) ? oh->isShrink : tags. ++ extraIsShrinkHeader; ++ ++ /* If it is deleted (unlinked at start also means deleted) ++ * we treat the file size as being zeroed at this point. ++ */ ++ if (parentObjectId == ++ YAFFS_OBJECTID_DELETED ++ || parentObjectId == ++ YAFFS_OBJECTID_UNLINKED) { ++ thisSize = 0; ++ isShrink = 1; ++ } ++ ++ if (isShrink && ++ in->variant.fileVariant. ++ shrinkSize > thisSize) { ++ in->variant.fileVariant. ++ shrinkSize = ++ thisSize; ++ } ++ ++ if (isShrink) ++ bi->hasShrinkHeader = 1; ++ ++ } ++ /* Use existing - destroy this one. */ ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ ++ } ++ ++ if (!in->valid && in->variantType != ++ (oh ? oh->type : tags.extraObjectType)) ++ T(YAFFS_TRACE_ERROR, ( ++ TSTR("yaffs tragedy: Bad object type, " ++ TCONT("%d != %d, for object %d at chunk ") ++ TCONT("%d during scan") ++ TENDSTR), oh ? ++ oh->type : tags.extraObjectType, ++ in->variantType, tags.objectId, ++ chunk)); ++ ++ if (!in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == ++ YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle with directory structure */ ++ in->valid = 1; ++ ++ if (oh) { ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++ ++#endif ++ } else { ++ in->variantType = tags.extraObjectType; ++ in->lazyLoaded = 1; ++ } ++ ++ in->hdrChunk = chunk; ++ ++ } else if (!in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->hdrChunk = chunk; ++ ++ if (oh) { ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ ++ if (oh->shadowsObject > 0) ++ yaffs_HandleShadowedObject(dev, ++ oh-> ++ shadowsObject, ++ 1); ++ ++ ++ yaffs_SetObjectName(in, oh->name); ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, oh->parentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ ++ fileSize = oh->fileSize; ++ isShrink = oh->isShrink; ++ equivalentObjectId = oh->equivalentObjectId; ++ ++ } else { ++ in->variantType = tags.extraObjectType; ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, tags.extraParentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ fileSize = tags.extraFileLength; ++ isShrink = tags.extraIsShrinkHeader; ++ equivalentObjectId = tags.extraEquivalentObjectId; ++ in->lazyLoaded = 1; ++ ++ } ++ in->dirty = 0; ++ ++ if (!parent) ++ alloc_failed = 1; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ if (parent && parent->variantType == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (!parent || parent->variantType != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * We're trying to use a non-directory as a directory ++ */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ TENDSTR))); ++ parent = dev->lostNFoundDir; ++ } ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ itsUnlinked = (parent == dev->deletedDir) || ++ (parent == dev->unlinkedDir); ++ ++ if (isShrink) { ++ /* Mark the block as having a shrinkHeader */ ++ bi->hasShrinkHeader = 1; ++ } ++ ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent object is scanned ++ * we put them all in a list. ++ * After scanning is complete, we should have all the objects, so we run ++ * through this list and fix up all the chains. ++ */ ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ ++ if (in->variant.fileVariant. ++ scannedFileSize < fileSize) { ++ /* This covers the case where the file size is greater ++ * than where the data is ++ * This will happen if the file is resized to be larger ++ * than its current data extents. ++ */ ++ in->variant.fileVariant.fileSize = fileSize; ++ in->variant.fileVariant.scannedFileSize = ++ in->variant.fileVariant.fileSize; ++ } ++ ++ if (isShrink && ++ in->variant.fileVariant.shrinkSize > fileSize) { ++ in->variant.fileVariant.shrinkSize = fileSize; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ if (!itsUnlinked) { ++ in->variant.hardLinkVariant.equivalentObjectId = ++ equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) hardList; ++ hardList = in; ++ } ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (oh) { ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; ++ } ++ break; ++ } ++ ++ } ++ ++ } ++ ++ } /* End of scanning for each chunk */ ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ /* If we got this far while scanning, then the block is fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ bi->blockState = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_BlockBecameDirty(dev, blk); ++ } ++ ++ } ++ ++ if (altBlockIndex) ++ YFREE_ALT(blockIndex); ++ else ++ YFREE(blockIndex); ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); ++ ++ return YAFFS_OK; ++} ++ ++/*------------------------------ Directory Functions ----------------------------- */ ++ ++static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) ++{ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ int count = 0; ++ ++ if (!obj) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); ++ YBUG(); ++ return; ++ } ++ ++ if (yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ if (!obj->parent) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); ++ YBUG(); ++ return; ++ } ++ ++ if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ yaffs_VerifyObject(listObj); ++ if (obj == listObj) ++ count++; ++ } ++ } ++ ++ if (count != 1) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); ++ YBUG(); ++ } ++} ++ ++static void yaffs_VerifyDirectory(yaffs_Object *directory) ++{ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ if (!directory) { ++ YBUG(); ++ return; ++ } ++ ++ if (yaffs_SkipFullVerification(directory->myDev)) ++ return; ++ ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType)); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &directory->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ if (listObj->parent != directory) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); ++ YBUG(); ++ } ++ yaffs_VerifyObjectInDirectory(listObj); ++ } ++ } ++} ++ ++ ++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ yaffs_Object *parent; ++ ++ yaffs_VerifyObjectInDirectory(obj); ++ parent = obj->parent; ++ ++ yaffs_VerifyDirectory(parent); ++ ++ if (dev && dev->removeObjectCallback) ++ dev->removeObjectCallback(obj); ++ ++ ++ ylist_del_init(&obj->siblings); ++ obj->parent = NULL; ++ ++ yaffs_VerifyDirectory(parent); ++} ++ ++ ++static void yaffs_AddObjectToDirectory(yaffs_Object *directory, ++ yaffs_Object *obj) ++{ ++ if (!directory) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: Trying to add an object to a null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return; ++ } ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: Trying to add an object to a non-directory" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ if (obj->siblings.prev == NULL) { ++ /* Not initialised */ ++ YBUG(); ++ } ++ ++ ++ yaffs_VerifyDirectory(directory); ++ ++ yaffs_RemoveObjectFromDirectory(obj); ++ ++ ++ /* Now add it */ ++ ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); ++ obj->parent = directory; ++ ++ if (directory == obj->myDev->unlinkedDir ++ || directory == obj->myDev->deletedDir) { ++ obj->unlinked = 1; ++ obj->myDev->nUnlinkedFiles++; ++ obj->renameAllowed = 0; ++ } ++ ++ yaffs_VerifyDirectory(directory); ++ yaffs_VerifyObjectInDirectory(obj); ++} ++ ++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory, ++ const YCHAR *name) ++{ ++ int sum; ++ ++ struct ylist_head *i; ++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ yaffs_Object *l; ++ ++ if (!name) ++ return NULL; ++ ++ if (!directory) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return NULL; ++ } ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); ++ YBUG(); ++ } ++ ++ sum = yaffs_CalcNameSum(name); ++ ++ ylist_for_each(i, &directory->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ ++ if (l->parent != directory) ++ YBUG(); ++ ++ yaffs_CheckObjectDetailsLoaded(l); ++ ++ /* Special case for lost-n-found */ ++ if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { ++ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) ++ return l; ++ } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) { ++ /* LostnFound chunk called Objxxx ++ * Do a real check ++ */ ++ yaffs_GetObjectName(l, buffer, ++ YAFFS_MAX_NAME_LENGTH); ++ if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0) ++ return l; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++#if 0 ++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, ++ int (*fn) (yaffs_Object *)) ++{ ++ struct ylist_head *i; ++ yaffs_Object *l; ++ ++ if (!theDir) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return YAFFS_FAIL; ++ } ++ if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); ++ YBUG(); ++ return YAFFS_FAIL; ++ } ++ ++ ylist_for_each(i, &theDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ if (l && !fn(l)) ++ return YAFFS_FAIL; ++ } ++ } ++ ++ return YAFFS_OK; ++ ++} ++#endif ++ ++/* GetEquivalentObject dereferences any hard links to get to the ++ * actual object. ++ */ ++ ++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) ++{ ++ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ /* We want the object id of the equivalent object, not this one */ ++ obj = obj->variant.hardLinkVariant.equivalentObject; ++ yaffs_CheckObjectDetailsLoaded(obj); ++ } ++ return obj; ++} ++ ++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) ++{ ++ memset(name, 0, buffSize * sizeof(YCHAR)); ++ ++ yaffs_CheckObjectDetailsLoaded(obj); ++ ++ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { ++ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); ++ } else if (obj->hdrChunk <= 0) { ++ YCHAR locName[20]; ++ YCHAR numString[20]; ++ YCHAR *x = &numString[19]; ++ unsigned v = obj->objectId; ++ numString[19] = 0; ++ while (v > 0) { ++ x--; ++ *x = '0' + (v % 10); ++ v /= 10; ++ } ++ /* make up a name */ ++ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); ++ yaffs_strcat(locName, x); ++ yaffs_strncpy(name, locName, buffSize - 1); ++ ++ } ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ else if (obj->shortName[0]) ++ yaffs_strcpy(name, obj->shortName); ++#endif ++ else { ++ int result; ++ __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); ++ ++ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer; ++ ++ memset(buffer, 0, obj->myDev->nDataBytesPerChunk); ++ ++ if (obj->hdrChunk > 0) { ++ result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, ++ obj->hdrChunk, buffer, ++ NULL); ++ } ++ yaffs_strncpy(name, oh->name, buffSize - 1); ++ ++ yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); ++ } ++ ++ return yaffs_strlen(name); ++} ++ ++int yaffs_GetObjectFileLength(yaffs_Object *obj) ++{ ++ /* Dereference any hard linking */ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ return obj->variant.fileVariant.fileSize; ++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_strlen(obj->variant.symLinkVariant.alias); ++ else { ++ /* Only a directory should drop through to here */ ++ return obj->myDev->nDataBytesPerChunk; ++ } ++} ++ ++int yaffs_GetObjectLinkCount(yaffs_Object *obj) ++{ ++ int count = 0; ++ struct ylist_head *i; ++ ++ if (!obj->unlinked) ++ count++; /* the object itself */ ++ ++ ylist_for_each(i, &obj->hardLinks) ++ count++; /* add the hard links; */ ++ ++ return count; ++} ++ ++int yaffs_GetObjectInode(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ return obj->objectId; ++} ++ ++unsigned yaffs_GetObjectType(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return DT_DIR; ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return DT_LNK; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ if (S_ISFIFO(obj->yst_mode)) ++ return DT_FIFO; ++ if (S_ISCHR(obj->yst_mode)) ++ return DT_CHR; ++ if (S_ISBLK(obj->yst_mode)) ++ return DT_BLK; ++ if (S_ISSOCK(obj->yst_mode)) ++ return DT_SOCK; ++ default: ++ return DT_REG; ++ break; ++ } ++} ++ ++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_CloneString(obj->variant.symLinkVariant.alias); ++ else ++ return yaffs_CloneString(_Y("")); ++} ++ ++#ifndef CONFIG_YAFFS_WINCE ++ ++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) ++{ ++ unsigned int valid = attr->ia_valid; ++ ++ if (valid & ATTR_MODE) ++ obj->yst_mode = attr->ia_mode; ++ if (valid & ATTR_UID) ++ obj->yst_uid = attr->ia_uid; ++ if (valid & ATTR_GID) ++ obj->yst_gid = attr->ia_gid; ++ ++ if (valid & ATTR_ATIME) ++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); ++ if (valid & ATTR_CTIME) ++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); ++ if (valid & ATTR_MTIME) ++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); ++ ++ if (valid & ATTR_SIZE) ++ yaffs_ResizeFile(obj, attr->ia_size); ++ ++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); ++ ++ return YAFFS_OK; ++ ++} ++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) ++{ ++ unsigned int valid = 0; ++ ++ attr->ia_mode = obj->yst_mode; ++ valid |= ATTR_MODE; ++ attr->ia_uid = obj->yst_uid; ++ valid |= ATTR_UID; ++ attr->ia_gid = obj->yst_gid; ++ valid |= ATTR_GID; ++ ++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; ++ valid |= ATTR_ATIME; ++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; ++ valid |= ATTR_CTIME; ++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; ++ valid |= ATTR_MTIME; ++ ++ attr->ia_size = yaffs_GetFileSize(obj); ++ valid |= ATTR_SIZE; ++ ++ attr->ia_valid = valid; ++ ++ return YAFFS_OK; ++} ++ ++#endif ++ ++#if 0 ++int yaffs_DumpObject(yaffs_Object *obj) ++{ ++ YCHAR name[257]; ++ ++ yaffs_GetObjectName(obj, name, 256); ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" ++ " chunk %d type %d size %d\n" ++ TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, ++ obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk, ++ yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); ++ ++ return YAFFS_OK; ++} ++#endif ++ ++/*---------------------------- Initialisation code -------------------------------------- */ ++ ++static int yaffs_CheckDevFunctions(const yaffs_Device *dev) ++{ ++ ++ /* Common functions, gotta have */ ++ if (!dev->eraseBlockInNAND || !dev->initialiseNAND) ++ return 0; ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ ++ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ ++ if (dev->writeChunkWithTagsToNAND && ++ dev->readChunkWithTagsFromNAND && ++ !dev->writeChunkToNAND && ++ !dev->readChunkFromNAND && ++ dev->markNANDBlockBad && dev->queryNANDBlock) ++ return 1; ++#endif ++ ++ /* Can use the "spare" style interface for yaffs1 */ ++ if (!dev->isYaffs2 && ++ !dev->writeChunkWithTagsToNAND && ++ !dev->readChunkWithTagsFromNAND && ++ dev->writeChunkToNAND && ++ dev->readChunkFromNAND && ++ !dev->markNANDBlockBad && !dev->queryNANDBlock) ++ return 1; ++ ++ return 0; /* bad */ ++} ++ ++ ++static int yaffs_CreateInitialDirectories(yaffs_Device *dev) ++{ ++ /* Initialise the unlinked, deleted, root and lost and found directories */ ++ ++ dev->lostNFoundDir = dev->rootDir = NULL; ++ dev->unlinkedDir = dev->deletedDir = NULL; ++ ++ dev->unlinkedDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); ++ ++ dev->deletedDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); ++ ++ dev->rootDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT, ++ YAFFS_ROOT_MODE | S_IFDIR); ++ dev->lostNFoundDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, ++ YAFFS_LOSTNFOUND_MODE | S_IFDIR); ++ ++ if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) { ++ yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_GutsInitialise(yaffs_Device *dev) ++{ ++ int init_failed = 0; ++ unsigned x; ++ int bits; ++ ++ T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR))); ++ ++ /* Check stuff that must be set */ ++ ++ if (!dev) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ dev->internalStartBlock = dev->startBlock; ++ dev->internalEndBlock = dev->endBlock; ++ dev->blockOffset = 0; ++ dev->chunkOffset = 0; ++ dev->nFreeChunks = 0; ++ ++ dev->gcBlock = -1; ++ ++ if (dev->startBlock == 0) { ++ dev->internalStartBlock = dev->startBlock + 1; ++ dev->internalEndBlock = dev->endBlock + 1; ++ dev->blockOffset = 1; ++ dev->chunkOffset = dev->nChunksPerBlock; ++ } ++ ++ /* Check geometry parameters. */ ++ ++ if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || ++ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || ++ (dev->inbandTags && !dev->isYaffs2) || ++ dev->nChunksPerBlock < 2 || ++ dev->nReservedBlocks < 2 || ++ dev->internalStartBlock <= 0 || ++ dev->internalEndBlock <= 0 || ++ dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d " ++ TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); ++ return YAFFS_FAIL; ++ } ++ ++ if (yaffs_InitialiseNAND(dev) != YAFFS_OK) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Sort out space for inband tags, if required */ ++ if (dev->inbandTags) ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); ++ else ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk; ++ ++ /* Got the right mix of functions? */ ++ if (!yaffs_CheckDevFunctions(dev)) { ++ /* Function missing */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs: device function(s) missing or wrong\n" TENDSTR))); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* This is really a compilation check. */ ++ if (!yaffs_CheckStructures()) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs_CheckStructures failed\n" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ if (dev->isMounted) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: device already mounted\n" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Finished with most checks. One or two more checks happen later on too. */ ++ ++ dev->isMounted = 1; ++ ++ /* OK now calculate a few things for the device */ ++ ++ /* ++ * Calculate all the chunk size manipulation numbers: ++ */ ++ x = dev->nDataBytesPerChunk; ++ /* We always use dev->chunkShift and dev->chunkDiv */ ++ dev->chunkShift = Shifts(x); ++ x >>= dev->chunkShift; ++ dev->chunkDiv = x; ++ /* We only use chunk mask if chunkDiv is 1 */ ++ dev->chunkMask = (1<chunkShift) - 1; ++ ++ /* ++ * Calculate chunkGroupBits. ++ * We need to find the next power of 2 > than internalEndBlock ++ */ ++ ++ x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); ++ ++ bits = ShiftsGE(x); ++ ++ /* Set up tnode width if wide tnodes are enabled. */ ++ if (!dev->wideTnodesDisabled) { ++ /* bits must be even so that we end up with 32-bit words */ ++ if (bits & 1) ++ bits++; ++ if (bits < 16) ++ dev->tnodeWidth = 16; ++ else ++ dev->tnodeWidth = bits; ++ } else ++ dev->tnodeWidth = 16; ++ ++ dev->tnodeMask = (1<tnodeWidth)-1; ++ ++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), ++ * so if the bitwidth of the ++ * chunk range we're using is greater than 16 we need ++ * to figure out chunk shift and chunkGroupSize ++ */ ++ ++ if (bits <= dev->tnodeWidth) ++ dev->chunkGroupBits = 0; ++ else ++ dev->chunkGroupBits = bits - dev->tnodeWidth; ++ ++ ++ dev->chunkGroupSize = 1 << dev->chunkGroupBits; ++ ++ if (dev->nChunksPerBlock < dev->chunkGroupSize) { ++ /* We have a problem because the soft delete won't work if ++ * the chunk group size > chunks per block. ++ * This can be remedied by using larger "virtual blocks". ++ */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: chunk group too large\n" TENDSTR))); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* OK, we've finished verifying the device, lets continue with initialisation */ ++ ++ /* More device initialisation */ ++ dev->garbageCollections = 0; ++ dev->passiveGarbageCollections = 0; ++ dev->currentDirtyChecker = 0; ++ dev->bufferedBlock = -1; ++ dev->doingBufferedBlockRewrite = 0; ++ dev->nDeletedFiles = 0; ++ dev->nBackgroundDeletions = 0; ++ dev->nUnlinkedFiles = 0; ++ dev->eccFixed = 0; ++ dev->eccUnfixed = 0; ++ dev->tagsEccFixed = 0; ++ dev->tagsEccUnfixed = 0; ++ dev->nErasureFailures = 0; ++ dev->nErasedBlocks = 0; ++ dev->isDoingGC = 0; ++ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ ++ ++ /* Initialise temporary buffers and caches. */ ++ if (!yaffs_InitialiseTempBuffers(dev)) ++ init_failed = 1; ++ ++ dev->srCache = NULL; ++ dev->gcCleanupList = NULL; ++ ++ ++ if (!init_failed && ++ dev->nShortOpCaches > 0) { ++ int i; ++ void *buf; ++ int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); ++ ++ if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) ++ dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; ++ ++ dev->srCache = YMALLOC(srCacheBytes); ++ ++ buf = (__u8 *) dev->srCache; ++ ++ if (dev->srCache) ++ memset(dev->srCache, 0, srCacheBytes); ++ ++ for (i = 0; i < dev->nShortOpCaches && buf; i++) { ++ dev->srCache[i].object = NULL; ++ dev->srCache[i].lastUse = 0; ++ dev->srCache[i].dirty = 0; ++ dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); ++ } ++ if (!buf) ++ init_failed = 1; ++ ++ dev->srLastUse = 0; ++ } ++ ++ dev->cacheHits = 0; ++ ++ if (!init_failed) { ++ dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); ++ if (!dev->gcCleanupList) ++ init_failed = 1; ++ } ++ ++ if (dev->isYaffs2) ++ dev->useHeaderFileSize = 1; ++ ++ if (!init_failed && !yaffs_InitialiseBlocks(dev)) ++ init_failed = 1; ++ ++ yaffs_InitialiseTnodes(dev); ++ yaffs_InitialiseObjects(dev); ++ ++ if (!init_failed && !yaffs_CreateInitialDirectories(dev)) ++ init_failed = 1; ++ ++ ++ if (!init_failed) { ++ /* Now scan the flash. */ ++ if (dev->isYaffs2) { ++ if (yaffs_CheckpointRestore(dev)) { ++ yaffs_CheckObjectDetailsLoaded(dev->rootDir); ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: restored from checkpoint" TENDSTR))); ++ } else { ++ ++ /* Clean up the mess caused by an aborted checkpoint load ++ * and scan backwards. ++ */ ++ yaffs_DeinitialiseBlocks(dev); ++ yaffs_DeinitialiseTnodes(dev); ++ yaffs_DeinitialiseObjects(dev); ++ ++ ++ dev->nErasedBlocks = 0; ++ dev->nFreeChunks = 0; ++ dev->allocationBlock = -1; ++ dev->allocationPage = -1; ++ dev->nDeletedFiles = 0; ++ dev->nUnlinkedFiles = 0; ++ dev->nBackgroundDeletions = 0; ++ dev->oldestDirtySequence = 0; ++ ++ if (!init_failed && !yaffs_InitialiseBlocks(dev)) ++ init_failed = 1; ++ ++ yaffs_InitialiseTnodes(dev); ++ yaffs_InitialiseObjects(dev); ++ ++ if (!init_failed && !yaffs_CreateInitialDirectories(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && !yaffs_ScanBackwards(dev)) ++ init_failed = 1; ++ } ++ } else if (!yaffs_Scan(dev)) ++ init_failed = 1; ++ ++ yaffs_StripDeletedObjects(dev); ++ } ++ ++ if (init_failed) { ++ /* Clean up the mess */ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); ++ ++ yaffs_Deinitialise(dev); ++ return YAFFS_FAIL; ++ } ++ ++ /* Zero out stats */ ++ dev->nPageReads = 0; ++ dev->nPageWrites = 0; ++ dev->nBlockErasures = 0; ++ dev->nGCCopies = 0; ++ dev->nRetriedWrites = 0; ++ ++ dev->nRetiredBlocks = 0; ++ ++ yaffs_VerifyFreeChunks(dev); ++ yaffs_VerifyBlocks(dev); ++ ++ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); ++ return YAFFS_OK; ++ ++} ++ ++void yaffs_Deinitialise(yaffs_Device *dev) ++{ ++ if (dev->isMounted) { ++ int i; ++ ++ yaffs_DeinitialiseBlocks(dev); ++ yaffs_DeinitialiseTnodes(dev); ++ yaffs_DeinitialiseObjects(dev); ++ if (dev->nShortOpCaches > 0 && ++ dev->srCache) { ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].data) ++ YFREE(dev->srCache[i].data); ++ dev->srCache[i].data = NULL; ++ } ++ ++ YFREE(dev->srCache); ++ dev->srCache = NULL; ++ } ++ ++ YFREE(dev->gcCleanupList); ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) ++ YFREE(dev->tempBuffer[i].buffer); ++ ++ dev->isMounted = 0; ++ ++ if (dev->deinitialiseNAND) ++ dev->deinitialiseNAND(dev); ++ } ++} ++ ++static int yaffs_CountFreeChunks(yaffs_Device *dev) ++{ ++ int nFree; ++ int b; ++ ++ yaffs_BlockInfo *blk; ++ ++ for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; ++ b++) { ++ blk = yaffs_GetBlockInfo(dev, b); ++ ++ switch (blk->blockState) { ++ case YAFFS_BLOCK_STATE_EMPTY: ++ case YAFFS_BLOCK_STATE_ALLOCATING: ++ case YAFFS_BLOCK_STATE_COLLECTING: ++ case YAFFS_BLOCK_STATE_FULL: ++ nFree += ++ (dev->nChunksPerBlock - blk->pagesInUse + ++ blk->softDeletions); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return nFree; ++} ++ ++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) ++{ ++ /* This is what we report to the outside world */ ++ ++ int nFree; ++ int nDirtyCacheChunks; ++ int blocksForCheckpoint; ++ int i; ++ ++#if 1 ++ nFree = dev->nFreeChunks; ++#else ++ nFree = yaffs_CountFreeChunks(dev); ++#endif ++ ++ nFree += dev->nDeletedFiles; ++ ++ /* Now count the number of dirty chunks in the cache and subtract those */ ++ ++ for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].dirty) ++ nDirtyCacheChunks++; ++ } ++ ++ nFree -= nDirtyCacheChunks; ++ ++ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); ++ ++ /* Now we figure out how much to reserve for the checkpoint and report that... */ ++ blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; ++ if (blocksForCheckpoint < 0) ++ blocksForCheckpoint = 0; ++ ++ nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); ++ ++ if (nFree < 0) ++ nFree = 0; ++ ++ return nFree; ++ ++} ++ ++static int yaffs_freeVerificationFailures; ++ ++static void yaffs_VerifyFreeChunks(yaffs_Device *dev) ++{ ++ int counted; ++ int difference; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ counted = yaffs_CountFreeChunks(dev); ++ ++ difference = dev->nFreeChunks - counted; ++ ++ if (difference) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Freechunks verification failure %d %d %d" TENDSTR), ++ dev->nFreeChunks, counted, difference)); ++ yaffs_freeVerificationFailures++; ++ } ++} ++ ++/*---------------------------------------- YAFFS test code ----------------------*/ ++ ++#define yaffs_CheckStruct(structure, syze, name) \ ++ do { \ ++ if (sizeof(structure) != syze) { \ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ ++ name, syze, sizeof(structure))); \ ++ return YAFFS_FAIL; \ ++ } \ ++ } while (0) ++ ++static int yaffs_CheckStructures(void) ++{ ++/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ ++/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ ++/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ ++#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); ++#endif ++#ifndef CONFIG_YAFFS_WINCE ++ yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); ++#endif ++ return YAFFS_OK; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h linux-2.6.30/fs/yaffs2/yaffs_guts.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_guts.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,904 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GUTS_H__ ++#define __YAFFS_GUTS_H__ ++ ++#include "devextras.h" ++#include "yportenv.h" ++ ++#define YAFFS_OK 1 ++#define YAFFS_FAIL 0 ++ ++/* Give us a Y=0x59, ++ * Give us an A=0x41, ++ * Give us an FF=0xFF ++ * Give us an S=0x53 ++ * And what have we got... ++ */ ++#define YAFFS_MAGIC 0x5941FF53 ++ ++#define YAFFS_NTNODES_LEVEL0 16 ++#define YAFFS_TNODES_LEVEL0_BITS 4 ++#define YAFFS_TNODES_LEVEL0_MASK 0xf ++ ++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) ++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) ++#define YAFFS_TNODES_INTERNAL_MASK 0x7 ++#define YAFFS_TNODES_MAX_LEVEL 6 ++ ++#ifndef CONFIG_YAFFS_NO_YAFFS1 ++#define YAFFS_BYTES_PER_SPARE 16 ++#define YAFFS_BYTES_PER_CHUNK 512 ++#define YAFFS_CHUNK_SIZE_SHIFT 9 ++#define YAFFS_CHUNKS_PER_BLOCK 32 ++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) ++#endif ++ ++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 ++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 ++ ++#define YAFFS_MAX_CHUNK_ID 0x000FFFFF ++ ++#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF ++ ++#define YAFFS_ALLOCATION_NOBJECTS 100 ++#define YAFFS_ALLOCATION_NTNODES 100 ++#define YAFFS_ALLOCATION_NLINKS 100 ++ ++#define YAFFS_NOBJECT_BUCKETS 256 ++ ++ ++#define YAFFS_OBJECT_SPACE 0x40000 ++ ++#define YAFFS_CHECKPOINT_VERSION 3 ++ ++#ifdef CONFIG_YAFFS_UNICODE ++#define YAFFS_MAX_NAME_LENGTH 127 ++#define YAFFS_MAX_ALIAS_LENGTH 79 ++#else ++#define YAFFS_MAX_NAME_LENGTH 255 ++#define YAFFS_MAX_ALIAS_LENGTH 159 ++#endif ++ ++#define YAFFS_SHORT_NAME_LENGTH 15 ++ ++/* Some special object ids for pseudo objects */ ++#define YAFFS_OBJECTID_ROOT 1 ++#define YAFFS_OBJECTID_LOSTNFOUND 2 ++#define YAFFS_OBJECTID_UNLINKED 3 ++#define YAFFS_OBJECTID_DELETED 4 ++ ++/* Sseudo object ids for checkpointing */ ++#define YAFFS_OBJECTID_SB_HEADER 0x10 ++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 ++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 ++ ++/* */ ++ ++#define YAFFS_MAX_SHORT_OP_CACHES 20 ++ ++#define YAFFS_N_TEMP_BUFFERS 6 ++ ++/* We limit the number attempts at sucessfully saving a chunk of data. ++ * Small-page devices have 32 pages per block; large-page devices have 64. ++ * Default to something in the order of 5 to 10 blocks worth of chunks. ++ */ ++#define YAFFS_WR_ATTEMPTS (5*64) ++ ++/* Sequence numbers are used in YAFFS2 to determine block allocation order. ++ * The range is limited slightly to help distinguish bad numbers from good. ++ * This also allows us to perhaps in the future use special numbers for ++ * special purposes. ++ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, ++ * and is a larger number than the lifetime of a 2GB device. ++ */ ++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 ++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 ++ ++/* Special sequence number for bad block that failed to be marked bad */ ++#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000 ++ ++/* ChunkCache is used for short read/write operations.*/ ++typedef struct { ++ struct yaffs_ObjectStruct *object; ++ int chunkId; ++ int lastUse; ++ int dirty; ++ int nBytes; /* Only valid if the cache is dirty */ ++ int locked; /* Can't push out or flush while locked. */ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ __u8 *data; ++#else ++ __u8 data[YAFFS_BYTES_PER_CHUNK]; ++#endif ++} yaffs_ChunkCache; ++ ++ ++ ++/* Tags structures in RAM ++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise ++ * the structure size will get blown out. ++ */ ++ ++#ifndef CONFIG_YAFFS_NO_YAFFS1 ++typedef struct { ++ unsigned chunkId:20; ++ unsigned serialNumber:2; ++ unsigned byteCountLSB:10; ++ unsigned objectId:18; ++ unsigned ecc:12; ++ unsigned byteCountMSB:2; ++} yaffs_Tags; ++ ++typedef union { ++ yaffs_Tags asTags; ++ __u8 asBytes[8]; ++} yaffs_TagsUnion; ++ ++#endif ++ ++/* Stuff used for extended tags in YAFFS2 */ ++ ++typedef enum { ++ YAFFS_ECC_RESULT_UNKNOWN, ++ YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_ECC_RESULT_FIXED, ++ YAFFS_ECC_RESULT_UNFIXED ++} yaffs_ECCResult; ++ ++typedef enum { ++ YAFFS_OBJECT_TYPE_UNKNOWN, ++ YAFFS_OBJECT_TYPE_FILE, ++ YAFFS_OBJECT_TYPE_SYMLINK, ++ YAFFS_OBJECT_TYPE_DIRECTORY, ++ YAFFS_OBJECT_TYPE_HARDLINK, ++ YAFFS_OBJECT_TYPE_SPECIAL ++} yaffs_ObjectType; ++ ++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL ++ ++typedef struct { ++ ++ unsigned validMarker0; ++ unsigned chunkUsed; /* Status of the chunk: used or unused */ ++ unsigned objectId; /* If 0 then this is not part of an object (unused) */ ++ unsigned chunkId; /* If 0 then this is a header, else a data chunk */ ++ unsigned byteCount; /* Only valid for data chunks */ ++ ++ /* The following stuff only has meaning when we read */ ++ yaffs_ECCResult eccResult; ++ unsigned blockBad; ++ ++ /* YAFFS 1 stuff */ ++ unsigned chunkDeleted; /* The chunk is marked deleted */ ++ unsigned serialNumber; /* Yaffs1 2-bit serial number */ ++ ++ /* YAFFS2 stuff */ ++ unsigned sequenceNumber; /* The sequence number of this block */ ++ ++ /* Extra info if this is an object header (YAFFS2 only) */ ++ ++ unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */ ++ unsigned extraParentObjectId; /* The parent object */ ++ unsigned extraIsShrinkHeader; /* Is it a shrink header? */ ++ unsigned extraShadows; /* Does this shadow another object? */ ++ ++ yaffs_ObjectType extraObjectType; /* What object type? */ ++ ++ unsigned extraFileLength; /* Length if it is a file */ ++ unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */ ++ ++ unsigned validMarker1; ++ ++} yaffs_ExtendedTags; ++ ++/* Spare structure for YAFFS1 */ ++typedef struct { ++ __u8 tagByte0; ++ __u8 tagByte1; ++ __u8 tagByte2; ++ __u8 tagByte3; ++ __u8 pageStatus; /* set to 0 to delete the chunk */ ++ __u8 blockStatus; ++ __u8 tagByte4; ++ __u8 tagByte5; ++ __u8 ecc1[3]; ++ __u8 tagByte6; ++ __u8 tagByte7; ++ __u8 ecc2[3]; ++} yaffs_Spare; ++ ++/*Special structure for passing through to mtd */ ++struct yaffs_NANDSpare { ++ yaffs_Spare spare; ++ int eccres1; ++ int eccres2; ++}; ++ ++/* Block data in RAM */ ++ ++typedef enum { ++ YAFFS_BLOCK_STATE_UNKNOWN = 0, ++ ++ YAFFS_BLOCK_STATE_SCANNING, ++ YAFFS_BLOCK_STATE_NEEDS_SCANNING, ++ /* The block might have something on it (ie it is allocating or full, perhaps empty) ++ * but it needs to be scanned to determine its true state. ++ * This state is only valid during yaffs_Scan. ++ * NB We tolerate empty because the pre-scanner might be incapable of deciding ++ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number ++ */ ++ ++ YAFFS_BLOCK_STATE_EMPTY, ++ /* This block is empty */ ++ ++ YAFFS_BLOCK_STATE_ALLOCATING, ++ /* This block is partially allocated. ++ * At least one page holds valid data. ++ * This is the one currently being used for page ++ * allocation. Should never be more than one of these ++ */ ++ ++ YAFFS_BLOCK_STATE_FULL, ++ /* All the pages in this block have been allocated. ++ */ ++ ++ YAFFS_BLOCK_STATE_DIRTY, ++ /* All pages have been allocated and deleted. ++ * Erase me, reuse me. ++ */ ++ ++ YAFFS_BLOCK_STATE_CHECKPOINT, ++ /* This block is assigned to holding checkpoint data. ++ */ ++ ++ YAFFS_BLOCK_STATE_COLLECTING, ++ /* This block is being garbage collected */ ++ ++ YAFFS_BLOCK_STATE_DEAD ++ /* This block has failed and is not in use */ ++} yaffs_BlockState; ++ ++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) ++ ++ ++typedef struct { ++ ++ int softDeletions:10; /* number of soft deleted pages */ ++ int pagesInUse:10; /* number of pages in use */ ++ unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ ++ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ ++ /* and retire the block. */ ++ __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */ ++ __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block. ++ It should be prioritised for GC */ ++ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */ ++ __u32 sequenceNumber; /* block sequence number for yaffs2 */ ++#endif ++ ++} yaffs_BlockInfo; ++ ++/* -------------------------- Object structure -------------------------------*/ ++/* This is the object structure as stored on NAND */ ++ ++typedef struct { ++ yaffs_ObjectType type; ++ ++ /* Apply to everything */ ++ int parentObjectId; ++ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ /* The following apply to directories, files, symlinks - not hard links */ ++ __u32 yst_mode; /* protection */ ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 notForWinCE[5]; ++#else ++ __u32 yst_uid; ++ __u32 yst_gid; ++ __u32 yst_atime; ++ __u32 yst_mtime; ++ __u32 yst_ctime; ++#endif ++ ++ /* File size applies to files only */ ++ int fileSize; ++ ++ /* Equivalent object id applies to hard links only. */ ++ int equivalentObjectId; ++ ++ /* Alias is for symlinks only. */ ++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; ++ ++ __u32 yst_rdev; /* device stuff for block and char devices (major/min) */ ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 win_ctime[2]; ++ __u32 win_atime[2]; ++ __u32 win_mtime[2]; ++#else ++ __u32 roomToGrow[6]; ++ ++#endif ++ __u32 inbandShadowsObject; ++ __u32 inbandIsShrink; ++ ++ __u32 reservedSpace[2]; ++ int shadowsObject; /* This object header shadows the specified object if > 0 */ ++ ++ /* isShrink applies to object headers written when we shrink the file (ie resize) */ ++ __u32 isShrink; ++ ++} yaffs_ObjectHeader; ++ ++/*--------------------------- Tnode -------------------------- */ ++ ++union yaffs_Tnode_union { ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; ++#else ++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; ++#endif ++/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ ++ ++}; ++ ++typedef union yaffs_Tnode_union yaffs_Tnode; ++ ++struct yaffs_TnodeList_struct { ++ struct yaffs_TnodeList_struct *next; ++ yaffs_Tnode *tnodes; ++}; ++ ++typedef struct yaffs_TnodeList_struct yaffs_TnodeList; ++ ++/*------------------------ Object -----------------------------*/ ++/* An object can be one of: ++ * - a directory (no data, has children links ++ * - a regular file (data.... not prunes :->). ++ * - a symlink [symbolic link] (the alias). ++ * - a hard link ++ */ ++ ++typedef struct { ++ __u32 fileSize; ++ __u32 scannedFileSize; ++ __u32 shrinkSize; ++ int topLevel; ++ yaffs_Tnode *top; ++} yaffs_FileStructure; ++ ++typedef struct { ++ struct ylist_head children; /* list of child links */ ++} yaffs_DirectoryStructure; ++ ++typedef struct { ++ YCHAR *alias; ++} yaffs_SymLinkStructure; ++ ++typedef struct { ++ struct yaffs_ObjectStruct *equivalentObject; ++ __u32 equivalentObjectId; ++} yaffs_HardLinkStructure; ++ ++typedef union { ++ yaffs_FileStructure fileVariant; ++ yaffs_DirectoryStructure directoryVariant; ++ yaffs_SymLinkStructure symLinkVariant; ++ yaffs_HardLinkStructure hardLinkVariant; ++} yaffs_ObjectVariant; ++ ++struct yaffs_ObjectStruct { ++ __u8 deleted:1; /* This should only apply to unlinked files. */ ++ __u8 softDeleted:1; /* it has also been soft deleted */ ++ __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/ ++ __u8 fake:1; /* A fake object has no presence on NAND. */ ++ __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ ++ __u8 unlinkAllowed:1; ++ __u8 dirty:1; /* the object needs to be written to flash */ ++ __u8 valid:1; /* When the file system is being loaded up, this ++ * object might be created before the data ++ * is available (ie. file data records appear before the header). ++ */ ++ __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */ ++ ++ __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is ++ * still in the inode cache. Free of object is defered. ++ * until the inode is released. ++ */ ++ __u8 beingCreated:1; /* This object is still being created so skip some checks. */ ++ ++ __u8 serial; /* serial number of chunk in NAND. Cached here */ ++ __u16 sum; /* sum of the name to speed searching */ ++ ++ struct yaffs_DeviceStruct *myDev; /* The device I'm on */ ++ ++ struct ylist_head hashLink; /* list of objects in this hash bucket */ ++ ++ struct ylist_head hardLinks; /* all the equivalent hard linked objects */ ++ ++ /* directory structure stuff */ ++ /* also used for linking up the free list */ ++ struct yaffs_ObjectStruct *parent; ++ struct ylist_head siblings; ++ ++ /* Where's my object header in NAND? */ ++ int hdrChunk; ++ ++ int nDataChunks; /* Number of data chunks attached to the file. */ ++ ++ __u32 objectId; /* the object id value */ ++ ++ __u32 yst_mode; ++ ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; ++#endif ++ ++#ifndef __KERNEL__ ++ __u32 inUse; ++#endif ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 win_ctime[2]; ++ __u32 win_mtime[2]; ++ __u32 win_atime[2]; ++#else ++ __u32 yst_uid; ++ __u32 yst_gid; ++ __u32 yst_atime; ++ __u32 yst_mtime; ++ __u32 yst_ctime; ++#endif ++ ++ __u32 yst_rdev; ++ ++#ifdef __KERNEL__ ++ struct inode *myInode; ++ ++#endif ++ ++ yaffs_ObjectType variantType; ++ ++ yaffs_ObjectVariant variant; ++ ++}; ++ ++typedef struct yaffs_ObjectStruct yaffs_Object; ++ ++struct yaffs_ObjectList_struct { ++ yaffs_Object *objects; ++ struct yaffs_ObjectList_struct *next; ++}; ++ ++typedef struct yaffs_ObjectList_struct yaffs_ObjectList; ++ ++typedef struct { ++ struct ylist_head list; ++ int count; ++} yaffs_ObjectBucket; ++ ++ ++/* yaffs_CheckpointObject holds the definition of an object as dumped ++ * by checkpointing. ++ */ ++ ++typedef struct { ++ int structType; ++ __u32 objectId; ++ __u32 parentId; ++ int hdrChunk; ++ yaffs_ObjectType variantType:3; ++ __u8 deleted:1; ++ __u8 softDeleted:1; ++ __u8 unlinked:1; ++ __u8 fake:1; ++ __u8 renameAllowed:1; ++ __u8 unlinkAllowed:1; ++ __u8 serial; ++ ++ int nDataChunks; ++ __u32 fileSizeOrEquivalentObjectId; ++} yaffs_CheckpointObject; ++ ++/*--------------------- Temporary buffers ---------------- ++ * ++ * These are chunk-sized working buffers. Each device has a few ++ */ ++ ++typedef struct { ++ __u8 *buffer; ++ int line; /* track from whence this buffer was allocated */ ++ int maxLine; ++} yaffs_TempBuffer; ++ ++/*----------------- Device ---------------------------------*/ ++ ++struct yaffs_DeviceStruct { ++ struct ylist_head devList; ++ const char *name; ++ ++ /* Entry parameters set up way early. Yaffs sets up the rest.*/ ++ int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ ++ int nChunksPerBlock; /* does not need to be a power of 2 */ ++ int spareBytesPerChunk; /* spare area size */ ++ int startBlock; /* Start block we're allowed to use */ ++ int endBlock; /* End block we're allowed to use */ ++ int nReservedBlocks; /* We want this tuneable so that we can reduce */ ++ /* reserved blocks on NOR and RAM. */ ++ ++ ++ /* Stuff used by the shared space checkpointing mechanism */ ++ /* If this value is zero, then this mechanism is disabled */ ++ ++/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */ ++ ++ ++ int nShortOpCaches; /* If <= 0, then short op caching is disabled, else ++ * the number of short op caches (don't use too many) ++ */ ++ ++ int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ ++ ++ int useNANDECC; /* Flag to decide whether or not to use NANDECC */ ++ ++ void *genericDevice; /* Pointer to device context ++ * On an mtd this holds the mtd pointer. ++ */ ++ void *superBlock; ++ ++ /* NAND access functions (Must be set before calling YAFFS)*/ ++ ++ int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_Spare *spare); ++ int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare); ++ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++ int (*initialiseNAND) (struct yaffs_DeviceStruct *dev); ++ int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev); ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++ int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_ExtendedTags *tags); ++ int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo); ++ int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++#endif ++ ++ int isYaffs2; ++ ++ /* The removeObjectCallback function must be supplied by OS flavours that ++ * need it. The Linux kernel does not use this, but yaffs direct does use ++ * it to implement the faster readdir ++ */ ++ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); ++ ++ /* Callback to mark the superblock dirsty */ ++ void (*markSuperBlockDirty)(void *superblock); ++ ++ int wideTnodesDisabled; /* Set to disable wide tnodes */ ++ ++ YCHAR *pathDividers; /* String of legal path dividers */ ++ ++ ++ /* End of stuff that must be set before initialisation. */ ++ ++ /* Checkpoint control. Can be set before or after initialisation */ ++ __u8 skipCheckpointRead; ++ __u8 skipCheckpointWrite; ++ ++ /* Runtime parameters. Set up by YAFFS. */ ++ ++ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ ++ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ ++ ++ /* Stuff to support wide tnodes */ ++ __u32 tnodeWidth; ++ __u32 tnodeMask; ++ ++ /* Stuff for figuring out file offset to chunk conversions */ ++ __u32 chunkShift; /* Shift value */ ++ __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */ ++ __u32 chunkMask; /* Mask to use for power-of-2 case */ ++ ++ /* Stuff to handle inband tags */ ++ int inbandTags; ++ __u32 totalBytesPerChunk; ++ ++#ifdef __KERNEL__ ++ ++ struct semaphore sem; /* Semaphore for waiting on erasure.*/ ++ struct semaphore grossLock; /* Gross locking semaphore */ ++ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer ++ * at compile time so we have to allocate it. ++ */ ++ void (*putSuperFunc) (struct super_block *sb); ++#endif ++ ++ int isMounted; ++ ++ int isCheckpointed; ++ ++ ++ /* Stuff to support block offsetting to support start block zero */ ++ int internalStartBlock; ++ int internalEndBlock; ++ int blockOffset; ++ int chunkOffset; ++ ++ ++ /* Runtime checkpointing stuff */ ++ int checkpointPageSequence; /* running sequence number of checkpoint pages */ ++ int checkpointByteCount; ++ int checkpointByteOffset; ++ __u8 *checkpointBuffer; ++ int checkpointOpenForWrite; ++ int blocksInCheckpoint; ++ int checkpointCurrentChunk; ++ int checkpointCurrentBlock; ++ int checkpointNextBlock; ++ int *checkpointBlockList; ++ int checkpointMaxBlocks; ++ __u32 checkpointSum; ++ __u32 checkpointXor; ++ ++ int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */ ++ ++ /* Block Info */ ++ yaffs_BlockInfo *blockInfo; ++ __u8 *chunkBits; /* bitmap of chunks in use */ ++ unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ ++ unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ ++ int chunkBitmapStride; /* Number of bytes of chunkBits per block. ++ * Must be consistent with nChunksPerBlock. ++ */ ++ ++ int nErasedBlocks; ++ int allocationBlock; /* Current block being allocated off */ ++ __u32 allocationPage; ++ int allocationBlockFinder; /* Used to search for next allocation block */ ++ ++ /* Runtime state */ ++ int nTnodesCreated; ++ yaffs_Tnode *freeTnodes; ++ int nFreeTnodes; ++ yaffs_TnodeList *allocatedTnodeList; ++ ++ int isDoingGC; ++ int gcBlock; ++ int gcChunk; ++ ++ int nObjectsCreated; ++ yaffs_Object *freeObjects; ++ int nFreeObjects; ++ ++ int nHardLinks; ++ ++ yaffs_ObjectList *allocatedObjectList; ++ ++ yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; ++ ++ int nFreeChunks; ++ ++ int currentDirtyChecker; /* Used to find current dirtiest block */ ++ ++ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ ++ int nonAggressiveSkip; /* GC state/mode */ ++ ++ /* Statistcs */ ++ int nPageWrites; ++ int nPageReads; ++ int nBlockErasures; ++ int nErasureFailures; ++ int nGCCopies; ++ int garbageCollections; ++ int passiveGarbageCollections; ++ int nRetriedWrites; ++ int nRetiredBlocks; ++ int eccFixed; ++ int eccUnfixed; ++ int tagsEccFixed; ++ int tagsEccUnfixed; ++ int nDeletions; ++ int nUnmarkedDeletions; ++ ++ int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ ++ ++ /* Special directories */ ++ yaffs_Object *rootDir; ++ yaffs_Object *lostNFoundDir; ++ ++ /* Buffer areas for storing data to recover from write failures TODO ++ * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; ++ * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; ++ */ ++ ++ int bufferedBlock; /* Which block is buffered here? */ ++ int doingBufferedBlockRewrite; ++ ++ yaffs_ChunkCache *srCache; ++ int srLastUse; ++ ++ int cacheHits; ++ ++ /* Stuff for background deletion and unlinked files.*/ ++ yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ ++ yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ ++ yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/ ++ int nDeletedFiles; /* Count of files awaiting deletion;*/ ++ int nUnlinkedFiles; /* Count of unlinked files. */ ++ int nBackgroundDeletions; /* Count of background deletions. */ ++ ++ ++ /* Temporary buffer management */ ++ yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; ++ int maxTemp; ++ int tempInUse; ++ int unmanagedTempAllocations; ++ int unmanagedTempDeallocations; ++ ++ /* yaffs2 runtime stuff */ ++ unsigned sequenceNumber; /* Sequence number of currently allocating block */ ++ unsigned oldestDirtySequence; ++ ++}; ++ ++typedef struct yaffs_DeviceStruct yaffs_Device; ++ ++/* The static layout of block usage etc is stored in the super block header */ ++typedef struct { ++ int StructType; ++ int version; ++ int checkpointStartBlock; ++ int checkpointEndBlock; ++ int startBlock; ++ int endBlock; ++ int rfu[100]; ++} yaffs_SuperBlockHeader; ++ ++/* The CheckpointDevice structure holds the device information that changes at runtime and ++ * must be preserved over unmount/mount cycles. ++ */ ++typedef struct { ++ int structType; ++ int nErasedBlocks; ++ int allocationBlock; /* Current block being allocated off */ ++ __u32 allocationPage; ++ int nFreeChunks; ++ ++ int nDeletedFiles; /* Count of files awaiting deletion;*/ ++ int nUnlinkedFiles; /* Count of unlinked files. */ ++ int nBackgroundDeletions; /* Count of background deletions. */ ++ ++ /* yaffs2 runtime stuff */ ++ unsigned sequenceNumber; /* Sequence number of currently allocating block */ ++ unsigned oldestDirtySequence; ++ ++} yaffs_CheckpointDevice; ++ ++ ++typedef struct { ++ int structType; ++ __u32 magic; ++ __u32 version; ++ __u32 head; ++} yaffs_CheckpointValidity; ++ ++ ++/*----------------------- YAFFS Functions -----------------------*/ ++ ++int yaffs_GutsInitialise(yaffs_Device *dev); ++void yaffs_Deinitialise(yaffs_Device *dev); ++ ++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev); ++ ++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, ++ yaffs_Object *newDir, const YCHAR *newName); ++ ++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name); ++int yaffs_DeleteObject(yaffs_Object *obj); ++ ++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize); ++int yaffs_GetObjectFileLength(yaffs_Object *obj); ++int yaffs_GetObjectInode(yaffs_Object *obj); ++unsigned yaffs_GetObjectType(yaffs_Object *obj); ++int yaffs_GetObjectLinkCount(yaffs_Object *obj); ++ ++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr); ++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr); ++ ++/* File operations */ ++int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset, ++ int nBytes); ++int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset, ++ int nBytes, int writeThrough); ++int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize); ++ ++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid); ++int yaffs_FlushFile(yaffs_Object *obj, int updateTime); ++ ++/* Flushing and checkpointing */ ++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); ++ ++int yaffs_CheckpointSave(yaffs_Device *dev); ++int yaffs_CheckpointRestore(yaffs_Device *dev); ++ ++/* Directory operations */ ++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid); ++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name); ++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, ++ int (*fn) (yaffs_Object *)); ++ ++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number); ++ ++/* Link operations */ ++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, ++ yaffs_Object *equivalentObject); ++ ++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj); ++ ++/* Symlink operations */ ++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, ++ const YCHAR *alias); ++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); ++ ++/* Special inodes (fifos, sockets and devices) */ ++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev); ++ ++/* Special directories */ ++yaffs_Object *yaffs_Root(yaffs_Device *dev); ++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); ++ ++#ifdef CONFIG_YAFFS_WINCE ++/* CONFIG_YAFFS_WINCE special stuff */ ++void yfsd_WinFileTimeNow(__u32 target[2]); ++#endif ++ ++#ifdef __KERNEL__ ++ ++void yaffs_HandleDeferedFree(yaffs_Object *obj); ++#endif ++ ++/* Debug dump */ ++int yaffs_DumpObject(yaffs_Object *obj); ++ ++void yaffs_GutsTest(yaffs_Device *dev); ++ ++/* A few useful functions */ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); ++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn); ++int yaffs_CheckFF(__u8 *buffer, int nBytes); ++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); ++ ++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo); ++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h linux-2.6.30/fs/yaffs2/yaffsinterface.h +--- linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffsinterface.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFSINTERFACE_H__ ++#define __YAFFSINTERFACE_H__ ++ ++int yaffs_Initialise(unsigned nBlocks); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,365 @@ ++/* ++ * YAFFS: Yet another FFS. A NAND-flash specific file system. ++ * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. ++ * ++ * Copyright (C) 2002 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * This module provides the interface between yaffs_nand.c and the ++ * MTD API. This version is used when the MTD interface supports the ++ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, ++ * and we have small-page NAND device. ++ * ++ * These functions are invoked via function pointers in yaffs_nand.c. ++ * This replaces functionality provided by functions in yaffs_mtdif.c ++ * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are ++ * called in yaffs_mtdif.c when the function pointers are NULL. ++ * We assume the MTD layer is performing ECC (useNANDECC is true). ++ */ ++ ++#include "yportenv.h" ++#include "yaffs_guts.h" ++#include "yaffs_packedtags1.h" ++#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */ ++ ++#include "linux/kernel.h" ++#include "linux/version.h" ++#include "linux/types.h" ++#include "linux/mtd/mtd.h" ++ ++/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ ++const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $"; ++ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++# define YTAG1_SIZE 8 ++#else ++# define YTAG1_SIZE 9 ++#endif ++ ++#if 0 ++/* Use the following nand_ecclayout with MTD when using ++ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. ++ * If you have existing Yaffs images and the byte order differs from this, ++ * adjust 'oobfree' to match your existing Yaffs data. ++ * ++ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the ++ * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to ++ * the 9th byte. ++ * ++ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 ++ * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P ++ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus ++ * byte and B is the small-page bad-block indicator byte. ++ */ ++static struct nand_ecclayout nand_oob_16 = { ++ .eccbytes = 6, ++ .eccpos = { 8, 9, 10, 13, 14, 15 }, ++ .oobavail = 9, ++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } ++}; ++#endif ++ ++/* Write a chunk (page) of data to NAND. ++ * ++ * Caller always provides ExtendedTags data which are converted to a more ++ * compact (packed) form for storage in NAND. A mini-ECC runs over the ++ * contents of the tags meta-data; used to valid the tags when read. ++ * ++ * - Pack ExtendedTags to PackedTags1 form ++ * - Compute mini-ECC for PackedTags1 ++ * - Write data and packed tags to NAND. ++ * ++ * Note: Due to the use of the PackedTags1 meta-data which does not include ++ * a full sequence number (as found in the larger PackedTags2 form) it is ++ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as ++ * discarded and dirty. This is not ideal: newer NAND parts are supposed ++ * to be written just once. When Yaffs performs this operation, this ++ * function is called with a NULL data pointer -- calling MTD write_oob ++ * without data is valid usage (2.6.17). ++ * ++ * Any underlying MTD error results in YAFFS_FAIL. ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkBytes = dev->nDataBytesPerChunk; ++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; ++ struct mtd_oob_ops ops; ++ yaffs_PackedTags1 pt1; ++ int retval; ++ ++ /* we assume that PackedTags1 and yaffs_Tags are compatible */ ++ compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); ++ compile_time_assertion(sizeof(yaffs_Tags) == 8); ++ ++ dev->nPageWrites++; ++ ++ yaffs_PackTags1(&pt1, etags); ++ yaffs_CalcTagsECC((yaffs_Tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * etags, one with chunkDeleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++ if (etags->chunkDeleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++#else ++ ((__u8 *)&pt1)[8] = 0xff; ++ if (etags->chunkDeleted) { ++ memset(&pt1, 0xff, 8); ++ /* zero pageStatus byte to indicate deleted */ ++ ((__u8 *)&pt1)[8] = 0; ++ } ++#endif ++ ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OOB_AUTO; ++ ops.len = (data) ? chunkBytes : 0; ++ ops.ooblen = YTAG1_SIZE; ++ ops.datbuf = (__u8 *)data; ++ ops.oobbuf = (__u8 *)&pt1; ++ ++ retval = mtd->write_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "write_oob failed, chunk %d, mtd error %d\n", ++ chunkInNAND, retval); ++ } ++ return retval ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++/* Return with empty ExtendedTags but add eccResult. ++ */ ++static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) ++{ ++ if (etags) { ++ memset(etags, 0, sizeof(*etags)); ++ etags->eccResult = eccResult; ++ } ++ return retval; ++} ++ ++/* Read a chunk (page) from NAND. ++ * ++ * Caller expects ExtendedTags data to be usable even on error; that is, ++ * all members except eccResult and blockBad are zeroed. ++ * ++ * - Check ECC results for data (if applicable) ++ * - Check for blank/erased block (return empty ExtendedTags if blank) ++ * - Check the PackedTags1 mini-ECC (correct if necessary/possible) ++ * - Convert PackedTags1 to ExtendedTags ++ * - Update eccResult and blockBad members to refect state. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkBytes = dev->nDataBytesPerChunk; ++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; ++ int eccres = YAFFS_ECC_RESULT_NO_ERROR; ++ struct mtd_oob_ops ops; ++ yaffs_PackedTags1 pt1; ++ int retval; ++ int deleted; ++ ++ dev->nPageReads++; ++ ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OOB_AUTO; ++ ops.len = (data) ? chunkBytes : 0; ++ ops.ooblen = YTAG1_SIZE; ++ ops.datbuf = data; ++ ops.oobbuf = (__u8 *)&pt1; ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) ++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; ++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. ++ */ ++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen; ++#endif ++ /* Read page and oob using MTD. ++ * Check status and determine ECC result. ++ */ ++ retval = mtd->read_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "read_oob failed, chunk %d, mtd error %d\n", ++ chunkInNAND, retval); ++ } ++ ++ switch (retval) { ++ case 0: ++ /* no error */ ++ break; ++ ++ case -EUCLEAN: ++ /* MTD's ECC fixed the data */ ++ eccres = YAFFS_ECC_RESULT_FIXED; ++ dev->eccFixed++; ++ break; ++ ++ case -EBADMSG: ++ /* MTD's ECC could not fix the data */ ++ dev->eccUnfixed++; ++ /* fall into... */ ++ default: ++ rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ etags->blockBad = (mtd->block_isbad)(mtd, addr); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. ++ */ ++ if (yaffs_CheckFF((__u8 *)&pt1, 8)) { ++ /* when blank, upper layers want eccResult to be <= NO_ERROR */ ++ return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); ++ } ++ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++#else ++ deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); ++#endif ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. ++ */ ++ retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->tagsEccFixed++; ++ if (eccres == YAFFS_ECC_RESULT_NO_ERROR) ++ eccres = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->tagsEccUnfixed++; ++ return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] ++ */ ++ pt1.shouldBeFF = 0xFFFFFFFF; ++ yaffs_UnpackTags1(etags, &pt1); ++ etags->eccResult = eccres; ++ ++ /* Set deleted state */ ++ etags->chunkDeleted = deleted; ++ return YAFFS_OK; ++} ++ ++/* Mark a block bad. ++ * ++ * This is a persistant state. ++ * Use of this function should be rare. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); ++ ++ retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++/* Check any MTD prerequists. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++static int nandmtd1_TestPrerequists(struct mtd_info *mtd) ++{ ++ /* 2.6.18 has mtd->ecclayout->oobavail */ ++ /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ ++ int oobavail = mtd->ecclayout->oobavail; ++ ++ if (oobavail < YTAG1_SIZE) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "mtd device has only %d bytes for tags, need %d\n", ++ oobavail, YTAG1_SIZE); ++ return YAFFS_FAIL; ++ } ++ return YAFFS_OK; ++} ++ ++/* Query for the current state of a specific block. ++ * ++ * Examine the tags of the first chunk of the block and return the state: ++ * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad ++ * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use ++ * - YAFFS_BLOCK_STATE_EMPTY, the block is clean ++ * ++ * Always returns YAFFS_OK. ++ */ ++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *pState, __u32 *pSequenceNumber) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkNo = blockNo * dev->nChunksPerBlock; ++ loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; ++ yaffs_ExtendedTags etags; ++ int state = YAFFS_BLOCK_STATE_DEAD; ++ int seqnum = 0; ++ int retval; ++ ++ /* We don't yet have a good place to test for MTD config prerequists. ++ * Do it here as we are called during the initial scan. ++ */ ++ if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); ++ etags.blockBad = (mtd->block_isbad)(mtd, addr); ++ if (etags.blockBad) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is marked bad\n", blockNo); ++ state = YAFFS_BLOCK_STATE_DEAD; ++ } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { ++ /* bad tags, need to look more closely */ ++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ } else if (etags.chunkUsed) { ++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ seqnum = etags.sequenceNumber; ++ } else { ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ *pState = state; ++ *pSequenceNumber = seqnum; ++ ++ /* query always succeeds */ ++ return YAFFS_OK; ++} ++ ++#endif /*MTD_VERSION*/ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF1_H__ ++#define __YAFFS_MTDIF1_H__ ++ ++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_ExtendedTags *tags); ++ ++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags); ++ ++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++ ++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,246 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++/* mtd interface for YAFFS2 */ ++ ++const char *yaffs_mtdif2_c_version = ++ "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++ ++#include "yaffs_mtdif2.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++ ++#include "yaffs_packedtags2.h" ++ ++/* NB For use with inband tags.... ++ * We assume that the data buffer is of size totalBytersPerChunk so that we can also ++ * use it to load the tags. ++ */ ++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#else ++ size_t dummy; ++#endif ++ int retval = 0; ++ ++ loff_t addr; ++ ++ yaffs_PackedTags2 pt; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" ++ TENDSTR), chunkInNAND, data, tags)); ++ ++ ++ addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; ++ ++ /* For yaffs2 writing there must be both data and tags. ++ * If we're using inband tags, then the tags are stuffed into ++ * the end of the data buffer. ++ */ ++ if (!data || !tags) ++ BUG(); ++ else if (dev->inbandTags) { ++ yaffs_PackedTags2TagsPart *pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); ++ yaffs_PackTags2TagsPart(pt2tp, tags); ++ } else ++ yaffs_PackTags2(&pt, tags); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt); ++ ops.len = dev->totalBytesPerChunk; ++ ops.ooboffs = 0; ++ ops.datbuf = (__u8 *)data; ++ ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; ++ retval = mtd->write_oob(mtd, addr, &ops); ++ ++#else ++ if (!dev->inbandTags) { ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, (__u8 *) &pt, NULL); ++ } else { ++ retval = ++ mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, ++ data); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ int localData = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; ++ ++ yaffs_PackedTags2 pt; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" ++ TENDSTR), chunkInNAND, data, tags)); ++ ++ if (dev->inbandTags) { ++ ++ if (!data) { ++ localData = 1; ++ data = yaffs_GetTempBuffer(dev, __LINE__); ++ } ++ ++ ++ } ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ if (dev->inbandTags || (data && !tags)) ++ retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, ++ &dummy, data); ++ else if (tags) { ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = sizeof(pt); ++ ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt); ++ ops.ooboffs = 0; ++ ops.datbuf = data; ++ ops.oobbuf = dev->spareBuffer; ++ retval = mtd->read_oob(mtd, addr, &ops); ++ } ++#else ++ if (!dev->inbandTags && data && tags) { ++ ++ retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, dev->spareBuffer, ++ NULL); ++ } else { ++ if (data) ++ retval = ++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (!dev->inbandTags && tags) ++ retval = ++ mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, ++ dev->spareBuffer); ++ } ++#endif ++ ++ ++ if (dev->inbandTags) { ++ if (tags) { ++ yaffs_PackedTags2TagsPart *pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; ++ yaffs_UnpackTags2TagsPart(tags, pt2tp); ++ } ++ } else { ++ if (tags) { ++ memcpy(&pt, dev->spareBuffer, sizeof(pt)); ++ yaffs_UnpackTags2(tags, &pt); ++ } ++ } ++ ++ if (localData) ++ yaffs_ReleaseTempBuffer(dev, data, __LINE__); ++ ++ if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) ++ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ int retval; ++ T(YAFFS_TRACE_MTD, ++ (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); ++ ++ retval = ++ mtd->block_markbad(mtd, ++ blockNo * dev->nChunksPerBlock * ++ dev->totalBytesPerChunk); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++ ++} ++ ++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ int retval; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); ++ retval = ++ mtd->block_isbad(mtd, ++ blockNo * dev->nChunksPerBlock * ++ dev->totalBytesPerChunk); ++ ++ if (retval) { ++ T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); ++ ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ *sequenceNumber = 0; ++ } else { ++ yaffs_ExtendedTags t; ++ nandmtd2_ReadChunkWithTagsFromNAND(dev, ++ blockNo * ++ dev->nChunksPerBlock, NULL, ++ &t); ++ ++ if (t.chunkUsed) { ++ *sequenceNumber = t.sequenceNumber; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ } else { ++ *sequenceNumber = 0; ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ } ++ T(YAFFS_TRACE_MTD, ++ (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber, ++ *state)); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF2_H__ ++#define __YAFFS_MTDIF2_H__ ++ ++#include "yaffs_guts.h" ++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags); ++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.30/fs/yaffs2/yaffs_mtdif.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,241 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_mtdif_c_version = ++ "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++ ++#include "yaffs_mtdif.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++#include "linux/mtd/nand.h" ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) ++static struct nand_oobinfo yaffs_oobinfo = { ++ .useecc = 1, ++ .eccbytes = 6, ++ .eccpos = {8, 9, 10, 13, 14, 15} ++}; ++ ++static struct nand_oobinfo yaffs_noeccinfo = { ++ .useecc = 0, ++}; ++#endif ++ ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) ++{ ++ oob[0] = spare->tagByte0; ++ oob[1] = spare->tagByte1; ++ oob[2] = spare->tagByte2; ++ oob[3] = spare->tagByte3; ++ oob[4] = spare->tagByte4; ++ oob[5] = spare->tagByte5 & 0x3f; ++ oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; ++ oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; ++ oob[6] = spare->tagByte6; ++ oob[7] = spare->tagByte7; ++} ++ ++static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) ++{ ++ struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; ++ spare->tagByte0 = oob[0]; ++ spare->tagByte1 = oob[1]; ++ spare->tagByte2 = oob[2]; ++ spare->tagByte3 = oob[3]; ++ spare->tagByte4 = oob[4]; ++ spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; ++ spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; ++ spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; ++ spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; ++ spare->tagByte6 = oob[6]; ++ spare->tagByte7 = oob[7]; ++ spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; ++ ++ nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ ++} ++#endif ++ ++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_Spare *spare) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ __u8 spareAsBytes[8]; /* OOB */ ++ ++ if (data && !spare) ++ retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data); ++ else if (spare) { ++ if (dev->useNANDECC) { ++ translate_spare2oob(spare, spareAsBytes); ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = 8; /* temp hack */ ++ } else { ++ ops.mode = MTD_OOB_RAW; ++ ops.ooblen = YAFFS_BYTES_PER_SPARE; ++ } ++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; ++ ops.datbuf = (u8 *)data; ++ ops.ooboffs = 0; ++ ops.oobbuf = spareAsBytes; ++ retval = mtd->write_oob(mtd, addr, &ops); ++ } ++#else ++ __u8 *spareAsBytes = (__u8 *) spare; ++ ++ if (data && spare) { ++ if (dev->useNANDECC) ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_oobinfo); ++ else ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_noeccinfo); ++ } else { ++ if (data) ++ retval = ++ mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (spare) ++ retval = ++ mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, ++ &dummy, spareAsBytes); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ __u8 spareAsBytes[8]; /* OOB */ ++ ++ if (data && !spare) ++ retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data); ++ else if (spare) { ++ if (dev->useNANDECC) { ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = 8; /* temp hack */ ++ } else { ++ ops.mode = MTD_OOB_RAW; ++ ops.ooblen = YAFFS_BYTES_PER_SPARE; ++ } ++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; ++ ops.datbuf = data; ++ ops.ooboffs = 0; ++ ops.oobbuf = spareAsBytes; ++ retval = mtd->read_oob(mtd, addr, &ops); ++ if (dev->useNANDECC) ++ translate_oob2spare(spare, spareAsBytes); ++ } ++#else ++ __u8 *spareAsBytes = (__u8 *) spare; ++ ++ if (data && spare) { ++ if (dev->useNANDECC) { ++ /* Careful, this call adds 2 ints */ ++ /* to the end of the spare data. Calling function */ ++ /* should allocate enough memory for spare, */ ++ /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ ++ retval = ++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_oobinfo); ++ } else { ++ retval = ++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_noeccinfo); ++ } ++ } else { ++ if (data) ++ retval = ++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (spare) ++ retval = ++ mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, ++ &dummy, spareAsBytes); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ __u32 addr = ++ ((loff_t) blockNumber) * dev->nDataBytesPerChunk ++ * dev->nChunksPerBlock; ++ struct erase_info ei; ++ int retval = 0; ++ ++ ei.mtd = mtd; ++ ei.addr = addr; ++ ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++ ++ /* Todo finish off the ei if required */ ++ ++ sema_init(&dev->sem, 0); ++ ++ retval = mtd->erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_InitialiseNAND(yaffs_Device *dev) ++{ ++ return YAFFS_OK; ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.30/fs/yaffs2/yaffs_mtdif.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF_H__ ++#define __YAFFS_MTDIF_H__ ++ ++#include "yaffs_guts.h" ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) ++extern struct nand_oobinfo yaffs_oobinfo; ++extern struct nand_oobinfo yaffs_noeccinfo; ++#endif ++ ++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_Spare *spare); ++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare); ++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); ++int nandmtd_InitialiseNAND(yaffs_Device *dev); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c linux-2.6.30/fs/yaffs2/yaffs_nand.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nand.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,135 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_nand_c_version = ++ "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $"; ++ ++#include "yaffs_nand.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_tagsvalidity.h" ++ ++#include "yaffs_getblockinfo.h" ++ ++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *buffer, ++ yaffs_ExtendedTags *tags) ++{ ++ int result; ++ yaffs_ExtendedTags localTags; ++ ++ int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; ++ ++ /* If there are no tags provided, use local tags to get prioritised gc working */ ++ if (!tags) ++ tags = &localTags; ++ ++ if (dev->readChunkWithTagsFromNAND) ++ result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, ++ tags); ++ else ++ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, ++ realignedChunkInNAND, ++ buffer, ++ tags); ++ if (tags && ++ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { ++ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); ++ yaffs_HandleChunkError(dev, bi); ++ } ++ ++ return result; ++} ++ ++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags) ++{ ++ chunkInNAND -= dev->chunkOffset; ++ ++ ++ if (tags) { ++ tags->sequenceNumber = dev->sequenceNumber; ++ tags->chunkUsed = 1; ++ if (!yaffs_ValidateTags(tags)) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("Writing uninitialised tags" TENDSTR))); ++ YBUG(); ++ } ++ T(YAFFS_TRACE_WRITE, ++ (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND, ++ tags->objectId, tags->chunkId)); ++ } else { ++ T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR))); ++ YBUG(); ++ } ++ ++ if (dev->writeChunkWithTagsToNAND) ++ return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, ++ tags); ++ else ++ return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, ++ chunkInNAND, ++ buffer, ++ tags); ++} ++ ++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) ++{ ++ blockNo -= dev->blockOffset; ++ ++; ++ if (dev->markNANDBlockBad) ++ return dev->markNANDBlockBad(dev, blockNo); ++ else ++ return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); ++} ++ ++int yaffs_QueryInitialBlockState(yaffs_Device *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber) ++{ ++ blockNo -= dev->blockOffset; ++ ++ if (dev->queryNANDBlock) ++ return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); ++ else ++ return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, ++ state, ++ sequenceNumber); ++} ++ ++ ++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND) ++{ ++ int result; ++ ++ blockInNAND -= dev->blockOffset; ++ ++ ++ dev->nBlockErasures++; ++ result = dev->eraseBlockInNAND(dev, blockInNAND); ++ ++ return result; ++} ++ ++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) ++{ ++ return dev->initialiseNAND(dev); ++} ++ ++ ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* Interface to emulated NAND functions (2k page size) */ ++ ++#ifndef __YAFFS_NANDEMUL2K_H__ ++#define __YAFFS_NANDEMUL2K_H__ ++ ++#include "yaffs_guts.h" ++ ++int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_ExtendedTags *tags); ++int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); ++int nandemul2k_GetBytesPerChunk(void); ++int nandemul2k_GetChunksPerBlock(void); ++int nandemul2k_GetNumberOfBlocks(void); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h linux-2.6.30/fs/yaffs2/yaffs_nand.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nand.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_NAND_H__ ++#define __YAFFS_NAND_H__ ++#include "yaffs_guts.h" ++ ++ ++ ++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *buffer, ++ yaffs_ExtendedTags *tags); ++ ++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags); ++ ++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo); ++ ++int yaffs_QueryInitialBlockState(yaffs_Device *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ unsigned *sequenceNumber); ++ ++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++ ++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev); ++ ++#endif ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags1.h" ++#include "yportenv.h" ++ ++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t) ++{ ++ pt->chunkId = t->chunkId; ++ pt->serialNumber = t->serialNumber; ++ pt->byteCount = t->byteCount; ++ pt->objectId = t->objectId; ++ pt->ecc = 0; ++ pt->deleted = (t->chunkDeleted) ? 0 : 1; ++ pt->unusedStuff = 0; ++ pt->shouldBeFF = 0xFFFFFFFF; ++ ++} ++ ++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt) ++{ ++ static const __u8 allFF[] = ++ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff }; ++ ++ if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) { ++ t->blockBad = 0; ++ if (pt->shouldBeFF != 0xFFFFFFFF) ++ t->blockBad = 1; ++ t->chunkUsed = 1; ++ t->objectId = pt->objectId; ++ t->chunkId = pt->chunkId; ++ t->byteCount = pt->byteCount; ++ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ t->chunkDeleted = (pt->deleted) ? 0 : 1; ++ t->serialNumber = pt->serialNumber; ++ } else { ++ memset(t, 0, sizeof(yaffs_ExtendedTags)); ++ } ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS1_H__ ++#define __YAFFS_PACKEDTAGS1_H__ ++ ++#include "yaffs_guts.h" ++ ++typedef struct { ++ unsigned chunkId:20; ++ unsigned serialNumber:2; ++ unsigned byteCount:10; ++ unsigned objectId:18; ++ unsigned ecc:12; ++ unsigned deleted:1; ++ unsigned unusedStuff:1; ++ unsigned shouldBeFF; ++ ++} yaffs_PackedTags1; ++ ++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,206 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags2.h" ++#include "yportenv.h" ++#include "yaffs_tagsvalidity.h" ++ ++/* This code packs a set of extended tags into a binary structure for ++ * NAND storage ++ */ ++ ++/* Some of the information is "extra" struff which can be packed in to ++ * speed scanning ++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set. ++ */ ++ ++/* Extra flags applied to chunkId */ ++ ++#define EXTRA_HEADER_INFO_FLAG 0x80000000 ++#define EXTRA_SHRINK_FLAG 0x40000000 ++#define EXTRA_SHADOWS_FLAG 0x20000000 ++#define EXTRA_SPARE_FLAGS 0x10000000 ++ ++#define ALL_EXTRA_FLAGS 0xF0000000 ++ ++/* Also, the top 4 bits of the object Id are set to the object type. */ ++#define EXTRA_OBJECT_TYPE_SHIFT (28) ++#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) ++ ++ ++static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) ++{ ++ T(YAFFS_TRACE_MTD, ++ (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), ++ ptt->objectId, ptt->chunkId, ptt->byteCount, ++ ptt->sequenceNumber)); ++} ++static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt) ++{ ++ yaffs_DumpPackedTags2TagsPart(&pt->t); ++} ++ ++static void yaffs_DumpTags2(const yaffs_ExtendedTags *t) ++{ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" ++ TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, ++ t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, ++ t->sequenceNumber)); ++ ++} ++ ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, ++ const yaffs_ExtendedTags *t) ++{ ++ ptt->chunkId = t->chunkId; ++ ptt->sequenceNumber = t->sequenceNumber; ++ ptt->byteCount = t->byteCount; ++ ptt->objectId = t->objectId; ++ ++ if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { ++ /* Store the extra header info instead */ ++ /* We save the parent object in the chunkId */ ++ ptt->chunkId = EXTRA_HEADER_INFO_FLAG ++ | t->extraParentObjectId; ++ if (t->extraIsShrinkHeader) ++ ptt->chunkId |= EXTRA_SHRINK_FLAG; ++ if (t->extraShadows) ++ ptt->chunkId |= EXTRA_SHADOWS_FLAG; ++ ++ ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ptt->objectId |= ++ (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); ++ ++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) ++ ptt->byteCount = t->extraEquivalentObjectId; ++ else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) ++ ptt->byteCount = t->extraFileLength; ++ else ++ ptt->byteCount = 0; ++ } ++ ++ yaffs_DumpPackedTags2TagsPart(ptt); ++ yaffs_DumpTags2(t); ++} ++ ++ ++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) ++{ ++ yaffs_PackTags2TagsPart(&pt->t, t); ++ ++#ifndef YAFFS_IGNORE_TAGS_ECC ++ { ++ yaffs_ECCCalculateOther((unsigned char *)&pt->t, ++ sizeof(yaffs_PackedTags2TagsPart), ++ &pt->ecc); ++ } ++#endif ++} ++ ++ ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, ++ yaffs_PackedTags2TagsPart *ptt) ++{ ++ ++ memset(t, 0, sizeof(yaffs_ExtendedTags)); ++ ++ yaffs_InitialiseTags(t); ++ ++ if (ptt->sequenceNumber != 0xFFFFFFFF) { ++ t->blockBad = 0; ++ t->chunkUsed = 1; ++ t->objectId = ptt->objectId; ++ t->chunkId = ptt->chunkId; ++ t->byteCount = ptt->byteCount; ++ t->chunkDeleted = 0; ++ t->serialNumber = 0; ++ t->sequenceNumber = ptt->sequenceNumber; ++ ++ /* Do extra header info stuff */ ++ ++ if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) { ++ t->chunkId = 0; ++ t->byteCount = 0; ++ ++ t->extraHeaderInfoAvailable = 1; ++ t->extraParentObjectId = ++ ptt->chunkId & (~(ALL_EXTRA_FLAGS)); ++ t->extraIsShrinkHeader = ++ (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; ++ t->extraShadows = ++ (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; ++ t->extraObjectType = ++ ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT; ++ t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) ++ t->extraEquivalentObjectId = ptt->byteCount; ++ else ++ t->extraFileLength = ptt->byteCount; ++ } ++ } ++ ++ yaffs_DumpPackedTags2TagsPart(ptt); ++ yaffs_DumpTags2(t); ++ ++} ++ ++ ++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) ++{ ++ ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ if (pt->t.sequenceNumber != 0xFFFFFFFF) { ++ /* Page is in use */ ++#ifndef YAFFS_IGNORE_TAGS_ECC ++ { ++ yaffs_ECCOther ecc; ++ int result; ++ yaffs_ECCCalculateOther((unsigned char *)&pt->t, ++ sizeof ++ (yaffs_PackedTags2TagsPart), ++ &ecc); ++ result = ++ yaffs_ECCCorrectOther((unsigned char *)&pt->t, ++ sizeof ++ (yaffs_PackedTags2TagsPart), ++ &pt->ecc, &ecc); ++ switch (result) { ++ case 0: ++ eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ case 1: ++ eccResult = YAFFS_ECC_RESULT_FIXED; ++ break; ++ case -1: ++ eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ break; ++ default: ++ eccResult = YAFFS_ECC_RESULT_UNKNOWN; ++ } ++ } ++#endif ++ } ++ ++ yaffs_UnpackTags2TagsPart(t, &pt->t); ++ ++ t->eccResult = eccResult; ++ ++ yaffs_DumpPackedTags2(pt); ++ yaffs_DumpTags2(t); ++ ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,43 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS2_H__ ++#define __YAFFS_PACKEDTAGS2_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_ecc.h" ++ ++typedef struct { ++ unsigned sequenceNumber; ++ unsigned objectId; ++ unsigned chunkId; ++ unsigned byteCount; ++} yaffs_PackedTags2TagsPart; ++ ++typedef struct { ++ yaffs_PackedTags2TagsPart t; ++ yaffs_ECCOther ecc; ++} yaffs_PackedTags2; ++ ++/* Full packed tags with ECC, used for oob tags */ ++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt); ++ ++/* Only the tags part (no ECC for use with inband tags */ ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c linux-2.6.30/fs/yaffs2/yaffs_qsort.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_qsort.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (c) 1992, 1993 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#include "yportenv.h" ++/* #include */ ++ ++/* ++ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". ++ */ ++#define swapcode(TYPE, parmi, parmj, n) do { \ ++ long i = (n) / sizeof (TYPE); \ ++ register TYPE *pi = (TYPE *) (parmi); \ ++ register TYPE *pj = (TYPE *) (parmj); \ ++ do { \ ++ register TYPE t = *pi; \ ++ *pi++ = *pj; \ ++ *pj++ = t; \ ++ } while (--i > 0); \ ++} while (0) ++ ++#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ ++ es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1; ++ ++static __inline void ++swapfunc(char *a, char *b, int n, int swaptype) ++{ ++ if (swaptype <= 1) ++ swapcode(long, a, b, n); ++ else ++ swapcode(char, a, b, n); ++} ++ ++#define yswap(a, b) do { \ ++ if (swaptype == 0) { \ ++ long t = *(long *)(a); \ ++ *(long *)(a) = *(long *)(b); \ ++ *(long *)(b) = t; \ ++ } else \ ++ swapfunc(a, b, es, swaptype); \ ++} while (0) ++ ++#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) ++ ++static __inline char * ++med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) ++{ ++ return cmp(a, b) < 0 ? ++ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) ++ : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c)); ++} ++ ++#ifndef min ++#define min(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++ ++void ++yaffs_qsort(void *aa, size_t n, size_t es, ++ int (*cmp)(const void *, const void *)) ++{ ++ char *pa, *pb, *pc, *pd, *pl, *pm, *pn; ++ int d, r, swaptype, swap_cnt; ++ register char *a = aa; ++ ++loop: SWAPINIT(a, es); ++ swap_cnt = 0; ++ if (n < 7) { ++ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) ++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; ++ pl -= es) ++ yswap(pl, pl - es); ++ return; ++ } ++ pm = (char *)a + (n / 2) * es; ++ if (n > 7) { ++ pl = (char *)a; ++ pn = (char *)a + (n - 1) * es; ++ if (n > 40) { ++ d = (n / 8) * es; ++ pl = med3(pl, pl + d, pl + 2 * d, cmp); ++ pm = med3(pm - d, pm, pm + d, cmp); ++ pn = med3(pn - 2 * d, pn - d, pn, cmp); ++ } ++ pm = med3(pl, pm, pn, cmp); ++ } ++ yswap(a, pm); ++ pa = pb = (char *)a + es; ++ ++ pc = pd = (char *)a + (n - 1) * es; ++ for (;;) { ++ while (pb <= pc && (r = cmp(pb, a)) <= 0) { ++ if (r == 0) { ++ swap_cnt = 1; ++ yswap(pa, pb); ++ pa += es; ++ } ++ pb += es; ++ } ++ while (pb <= pc && (r = cmp(pc, a)) >= 0) { ++ if (r == 0) { ++ swap_cnt = 1; ++ yswap(pc, pd); ++ pd -= es; ++ } ++ pc -= es; ++ } ++ if (pb > pc) ++ break; ++ yswap(pb, pc); ++ swap_cnt = 1; ++ pb += es; ++ pc -= es; ++ } ++ if (swap_cnt == 0) { /* Switch to insertion sort */ ++ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) ++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; ++ pl -= es) ++ yswap(pl, pl - es); ++ return; ++ } ++ ++ pn = (char *)a + n * es; ++ r = min(pa - (char *)a, pb - pa); ++ vecswap(a, pb - r, r); ++ r = min((long)(pd - pc), (long)(pn - pd - es)); ++ vecswap(pb, pn - r, r); ++ r = pb - pa; ++ if (r > es) ++ yaffs_qsort(a, r / es, es, cmp); ++ r = pd - pc; ++ if (r > es) { ++ /* Iterate rather than recurse to save stack space */ ++ a = pn - r; ++ n = r / es; ++ goto loop; ++ } ++/* yaffs_qsort(pn - r, r / es, es, cmp);*/ ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h linux-2.6.30/fs/yaffs2/yaffs_qsort.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_qsort.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YAFFS_QSORT_H__ ++#define __YAFFS_QSORT_H__ ++ ++extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, ++ int (*cmp)(const void *, const void *)); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,541 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_ecc.h" ++#include "yaffs_getblockinfo.h" ++ ++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); ++#ifdef NOTYET ++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND); ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_Spare *spare); ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_Spare *spare); ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND); ++#endif ++ ++static const char yaffs_countBitsTable[256] = { ++ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 ++}; ++ ++int yaffs_CountBits(__u8 x) ++{ ++ int retVal; ++ retVal = yaffs_countBitsTable[x]; ++ return retVal; ++} ++ ++/********** Tags ECC calculations *********/ ++ ++void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) ++{ ++ yaffs_ECCCalculate(data, spare->ecc1); ++ yaffs_ECCCalculate(&data[256], spare->ecc2); ++} ++ ++void yaffs_CalcTagsECC(yaffs_Tags *tags) ++{ ++ /* Calculate an ecc */ ++ ++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; ++ unsigned i, j; ++ unsigned ecc = 0; ++ unsigned bit = 0; ++ ++ tags->ecc = 0; ++ ++ for (i = 0; i < 8; i++) { ++ for (j = 1; j & 0xff; j <<= 1) { ++ bit++; ++ if (b[i] & j) ++ ecc ^= bit; ++ } ++ } ++ ++ tags->ecc = ecc; ++ ++} ++ ++int yaffs_CheckECCOnTags(yaffs_Tags *tags) ++{ ++ unsigned ecc = tags->ecc; ++ ++ yaffs_CalcTagsECC(tags); ++ ++ ecc ^= tags->ecc; ++ ++ if (ecc && ecc <= 64) { ++ /* TODO: Handle the failure better. Retire? */ ++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; ++ ++ ecc--; ++ ++ b[ecc / 8] ^= (1 << (ecc & 7)); ++ ++ /* Now recvalc the ecc */ ++ yaffs_CalcTagsECC(tags); ++ ++ return 1; /* recovered error */ ++ } else if (ecc) { ++ /* Wierd ecc failure value */ ++ /* TODO Need to do somethiong here */ ++ return -1; /* unrecovered error */ ++ } ++ ++ return 0; ++} ++ ++/********** Tags **********/ ++ ++static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, ++ yaffs_Tags *tagsPtr) ++{ ++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; ++ ++ yaffs_CalcTagsECC(tagsPtr); ++ ++ sparePtr->tagByte0 = tu->asBytes[0]; ++ sparePtr->tagByte1 = tu->asBytes[1]; ++ sparePtr->tagByte2 = tu->asBytes[2]; ++ sparePtr->tagByte3 = tu->asBytes[3]; ++ sparePtr->tagByte4 = tu->asBytes[4]; ++ sparePtr->tagByte5 = tu->asBytes[5]; ++ sparePtr->tagByte6 = tu->asBytes[6]; ++ sparePtr->tagByte7 = tu->asBytes[7]; ++} ++ ++static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr, ++ yaffs_Tags *tagsPtr) ++{ ++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; ++ int result; ++ ++ tu->asBytes[0] = sparePtr->tagByte0; ++ tu->asBytes[1] = sparePtr->tagByte1; ++ tu->asBytes[2] = sparePtr->tagByte2; ++ tu->asBytes[3] = sparePtr->tagByte3; ++ tu->asBytes[4] = sparePtr->tagByte4; ++ tu->asBytes[5] = sparePtr->tagByte5; ++ tu->asBytes[6] = sparePtr->tagByte6; ++ tu->asBytes[7] = sparePtr->tagByte7; ++ ++ result = yaffs_CheckECCOnTags(tagsPtr); ++ if (result > 0) ++ dev->tagsEccFixed++; ++ else if (result < 0) ++ dev->tagsEccUnfixed++; ++} ++ ++static void yaffs_SpareInitialise(yaffs_Spare *spare) ++{ ++ memset(spare, 0xFF, sizeof(yaffs_Spare)); ++} ++ ++static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ yaffs_Spare *spare) ++{ ++ if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), ++ chunkInNAND)); ++ return YAFFS_FAIL; ++ } ++ ++ dev->nPageWrites++; ++ return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); ++} ++ ++static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_Spare *spare, ++ yaffs_ECCResult *eccResult, ++ int doErrorCorrection) ++{ ++ int retVal; ++ yaffs_Spare localSpare; ++ ++ dev->nPageReads++; ++ ++ if (!spare && data) { ++ /* If we don't have a real spare, then we use a local one. */ ++ /* Need this for the calculation of the ecc */ ++ spare = &localSpare; ++ } ++ ++ if (!dev->useNANDECC) { ++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); ++ if (data && doErrorCorrection) { ++ /* Do ECC correction */ ++ /* Todo handle any errors */ ++ int eccResult1, eccResult2; ++ __u8 calcEcc[3]; ++ ++ yaffs_ECCCalculate(data, calcEcc); ++ eccResult1 = ++ yaffs_ECCCorrect(data, spare->ecc1, calcEcc); ++ yaffs_ECCCalculate(&data[256], calcEcc); ++ eccResult2 = ++ yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc); ++ ++ if (eccResult1 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error fix performed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ dev->eccFixed++; ++ } else if (eccResult1 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error unfixed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ dev->eccUnfixed++; ++ } ++ ++ if (eccResult2 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error fix performed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ dev->eccFixed++; ++ } else if (eccResult2 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error unfixed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ dev->eccUnfixed++; ++ } ++ ++ if (eccResult1 || eccResult2) { ++ /* We had a data problem on this page */ ++ yaffs_HandleReadDataError(dev, chunkInNAND); ++ } ++ ++ if (eccResult1 < 0 || eccResult2 < 0) ++ *eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ else if (eccResult1 > 0 || eccResult2 > 0) ++ *eccResult = YAFFS_ECC_RESULT_FIXED; ++ else ++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ } ++ } else { ++ /* Must allocate enough memory for spare+2*sizeof(int) */ ++ /* for ecc results from device. */ ++ struct yaffs_NANDSpare nspare; ++ ++ memset(&nspare, 0, sizeof(nspare)); ++ ++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, ++ (yaffs_Spare *) &nspare); ++ memcpy(spare, &nspare, sizeof(yaffs_Spare)); ++ if (data && doErrorCorrection) { ++ if (nspare.eccres1 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error fix performed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ } else if (nspare.eccres1 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error unfixed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ } ++ ++ if (nspare.eccres2 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error fix performed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ } else if (nspare.eccres2 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error unfixed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ } ++ ++ if (nspare.eccres1 || nspare.eccres2) { ++ /* We had a data problem on this page */ ++ yaffs_HandleReadDataError(dev, chunkInNAND); ++ } ++ ++ if (nspare.eccres1 < 0 || nspare.eccres2 < 0) ++ *eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) ++ *eccResult = YAFFS_ECC_RESULT_FIXED; ++ else ++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ } ++ } ++ return retVal; ++} ++ ++#ifdef NOTYET ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND) ++{ ++ static int init; ++ static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; ++ static __u8 data[YAFFS_BYTES_PER_CHUNK]; ++ /* Might as well always allocate the larger size for */ ++ /* dev->useNANDECC == true; */ ++ static __u8 spare[sizeof(struct yaffs_NANDSpare)]; ++ ++ dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); ++ ++ if (!init) { ++ memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); ++ init = 1; ++ } ++ ++ if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK)) ++ return YAFFS_FAIL; ++ if (memcmp(cmpbuf, spare, 16)) ++ return YAFFS_FAIL; ++ ++ return YAFFS_OK; ++ ++} ++#endif ++ ++/* ++ * Functions for robustisizing ++ */ ++ ++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ ++ /* Mark the block for retirement */ ++ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); ++ ++ /* TODO: ++ * Just do a garbage collection on the affected block ++ * then retire the block ++ * NB recursion ++ */ ++} ++ ++#ifdef NOTYET ++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND) ++{ ++} ++ ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_Spare *spare) ++{ ++} ++ ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_Spare *spare) ++{ ++} ++ ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ ++ /* Mark the block for retirement */ ++ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; ++ /* Delete the chunk */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++} ++ ++static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1, ++ const yaffs_Spare *s0, const yaffs_Spare *s1) ++{ ++ ++ if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 || ++ s0->tagByte0 != s1->tagByte0 || ++ s0->tagByte1 != s1->tagByte1 || ++ s0->tagByte2 != s1->tagByte2 || ++ s0->tagByte3 != s1->tagByte3 || ++ s0->tagByte4 != s1->tagByte4 || ++ s0->tagByte5 != s1->tagByte5 || ++ s0->tagByte6 != s1->tagByte6 || ++ s0->tagByte7 != s1->tagByte7 || ++ s0->ecc1[0] != s1->ecc1[0] || ++ s0->ecc1[1] != s1->ecc1[1] || ++ s0->ecc1[2] != s1->ecc1[2] || ++ s0->ecc2[0] != s1->ecc2[0] || ++ s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) { ++ return 0; ++ } ++ ++ return 1; ++} ++#endif /* NOTYET */ ++ ++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *eTags) ++{ ++ yaffs_Spare spare; ++ yaffs_Tags tags; ++ ++ yaffs_SpareInitialise(&spare); ++ ++ if (eTags->chunkDeleted) ++ spare.pageStatus = 0; ++ else { ++ tags.objectId = eTags->objectId; ++ tags.chunkId = eTags->chunkId; ++ ++ tags.byteCountLSB = eTags->byteCount & 0x3ff; ++ ++ if (dev->nDataBytesPerChunk >= 1024) ++ tags.byteCountMSB = (eTags->byteCount >> 10) & 3; ++ else ++ tags.byteCountMSB = 3; ++ ++ ++ tags.serialNumber = eTags->serialNumber; ++ ++ if (!dev->useNANDECC && data) ++ yaffs_CalcECC(data, &spare); ++ ++ yaffs_LoadTagsIntoSpare(&spare, &tags); ++ ++ } ++ ++ return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare); ++} ++ ++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_ExtendedTags *eTags) ++{ ++ ++ yaffs_Spare spare; ++ yaffs_Tags tags; ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN; ++ ++ static yaffs_Spare spareFF; ++ static int init; ++ ++ if (!init) { ++ memset(&spareFF, 0xFF, sizeof(spareFF)); ++ init = 1; ++ } ++ ++ if (yaffs_ReadChunkFromNAND ++ (dev, chunkInNAND, data, &spare, &eccResult, 1)) { ++ /* eTags may be NULL */ ++ if (eTags) { ++ ++ int deleted = ++ (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; ++ ++ eTags->chunkDeleted = deleted; ++ eTags->eccResult = eccResult; ++ eTags->blockBad = 0; /* We're reading it */ ++ /* therefore it is not a bad block */ ++ eTags->chunkUsed = ++ (memcmp(&spareFF, &spare, sizeof(spareFF)) != ++ 0) ? 1 : 0; ++ ++ if (eTags->chunkUsed) { ++ yaffs_GetTagsFromSpare(dev, &spare, &tags); ++ ++ eTags->objectId = tags.objectId; ++ eTags->chunkId = tags.chunkId; ++ eTags->byteCount = tags.byteCountLSB; ++ ++ if (dev->nDataBytesPerChunk >= 1024) ++ eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10); ++ ++ eTags->serialNumber = tags.serialNumber; ++ } ++ } ++ ++ return YAFFS_OK; ++ } else { ++ return YAFFS_FAIL; ++ } ++} ++ ++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, ++ int blockInNAND) ++{ ++ ++ yaffs_Spare spare; ++ ++ memset(&spare, 0xff, sizeof(yaffs_Spare)); ++ ++ spare.blockStatus = 'Y'; ++ ++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, ++ &spare); ++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, ++ NULL, &spare); ++ ++ return YAFFS_OK; ++ ++} ++ ++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber) ++{ ++ ++ yaffs_Spare spare0, spare1; ++ static yaffs_Spare spareFF; ++ static int init; ++ yaffs_ECCResult dummy; ++ ++ if (!init) { ++ memset(&spareFF, 0xFF, sizeof(spareFF)); ++ init = 1; ++ } ++ ++ *sequenceNumber = 0; ++ ++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, ++ &spare0, &dummy, 1); ++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, ++ &spare1, &dummy, 1); ++ ++ if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ else ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ ++ return YAFFS_OK; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSCOMPAT_H__ ++#define __YAFFS_TAGSCOMPAT_H__ ++ ++#include "yaffs_guts.h" ++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_ExtendedTags *tags); ++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, ++ int blockNo); ++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber); ++ ++void yaffs_CalcTagsECC(yaffs_Tags *tags); ++int yaffs_CheckECCOnTags(yaffs_Tags *tags); ++int yaffs_CountBits(__u8 byte); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_tagsvalidity.h" ++ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags) ++{ ++ memset(tags, 0, sizeof(yaffs_ExtendedTags)); ++ tags->validMarker0 = 0xAAAAAAAA; ++ tags->validMarker1 = 0x55555555; ++} ++ ++int yaffs_ValidateTags(yaffs_ExtendedTags *tags) ++{ ++ return (tags->validMarker0 == 0xAAAAAAAA && ++ tags->validMarker1 == 0x55555555); ++ ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,24 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YAFFS_TAGS_VALIDITY_H__ ++#define __YAFFS_TAGS_VALIDITY_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); ++int yaffs_ValidateTags(yaffs_ExtendedTags *tags); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yportenv.h linux-2.6.30/fs/yaffs2/yportenv.h +--- linux-2.6.30.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yportenv.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YPORTENV_H__ ++#define __YPORTENV_H__ ++ ++/* ++ * Define the MTD version in terms of Linux Kernel versions ++ * This allows yaffs to be used independantly of the kernel ++ * as well as with it. ++ */ ++ ++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) ++ ++#if defined CONFIG_YAFFS_WINCE ++ ++#include "ywinceenv.h" ++ ++#elif defined __KERNEL__ ++ ++#include "moduleconfig.h" ++ ++/* Linux kernel */ ++ ++#include ++#define MTD_VERSION_CODE LINUX_VERSION_CODE ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++#define yaffs_strcat(a, b) strcat(a, b) ++#define yaffs_strcpy(a, b) strcpy(a, b) ++#define yaffs_strncpy(a, b, c) strncpy(a, b, c) ++#define yaffs_strncmp(a, b, c) strncmp(a, b, c) ++#define yaffs_strlen(s) strlen(s) ++#define yaffs_sprintf sprintf ++#define yaffs_toupper(a) toupper(a) ++ ++#define Y_INLINE inline ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++ ++/* #define YPRINTF(x) printk x */ ++#define YMALLOC(x) kmalloc(x, GFP_NOFS) ++#define YFREE(x) kfree(x) ++#define YMALLOC_ALT(x) vmalloc(x) ++#define YFREE_ALT(x) vfree(x) ++#define YMALLOC_DMA(x) YMALLOC(x) ++ ++/* KR - added for use in scan so processes aren't blocked indefinitely. */ ++#define YYIELD() schedule() ++ ++#define YAFFS_ROOT_MODE 0666 ++#define YAFFS_LOSTNFOUND_MODE 0666 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec ++#define Y_TIME_CONVERT(x) (x).tv_sec ++#else ++#define Y_CURRENT_TIME CURRENT_TIME ++#define Y_TIME_CONVERT(x) (x) ++#endif ++ ++#define yaffs_SumCompare(x, y) ((x) == (y)) ++#define yaffs_strcmp(a, b) strcmp(a, b) ++ ++#define TENDSTR "\n" ++#define TSTR(x) KERN_WARNING x ++#define TCONT(x) x ++#define TOUT(p) printk p ++ ++#define yaffs_trace(mask, fmt, args...) \ ++ do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ ++ printk(KERN_WARNING "yaffs: " fmt, ## args); \ ++ } while (0) ++ ++#define compile_time_assertion(assertion) \ ++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) ++ ++#elif defined CONFIG_YAFFS_DIRECT ++ ++#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22) ++ ++/* Direct interface */ ++#include "ydirectenv.h" ++ ++#elif defined CONFIG_YAFFS_UTIL ++ ++/* Stuff for YAFFS utilities */ ++ ++#include "stdlib.h" ++#include "stdio.h" ++#include "string.h" ++ ++#include "devextras.h" ++ ++#define YMALLOC(x) malloc(x) ++#define YFREE(x) free(x) ++#define YMALLOC_ALT(x) malloc(x) ++#define YFREE_ALT(x) free(x) ++ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++#define yaffs_strcat(a, b) strcat(a, b) ++#define yaffs_strcpy(a, b) strcpy(a, b) ++#define yaffs_strncpy(a, b, c) strncpy(a, b, c) ++#define yaffs_strlen(s) strlen(s) ++#define yaffs_sprintf sprintf ++#define yaffs_toupper(a) toupper(a) ++ ++#define Y_INLINE inline ++ ++/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */ ++/* #define YALERT(s) YINFO(s) */ ++ ++#define TENDSTR "\n" ++#define TSTR(x) x ++#define TOUT(p) printf p ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++/* #define YPRINTF(x) printf x */ ++ ++#define YAFFS_ROOT_MODE 0666 ++#define YAFFS_LOSTNFOUND_MODE 0666 ++ ++#define yaffs_SumCompare(x, y) ((x) == (y)) ++#define yaffs_strcmp(a, b) strcmp(a, b) ++ ++#else ++/* Should have specified a configuration type */ ++#error Unknown configuration ++ ++#endif ++ ++/* see yaffs_fs.c */ ++extern unsigned int yaffs_traceMask; ++extern unsigned int yaffs_wr_attempts; ++ ++/* ++ * Tracing flags. ++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced. ++ */ ++ ++#define YAFFS_TRACE_OS 0x00000002 ++#define YAFFS_TRACE_ALLOCATE 0x00000004 ++#define YAFFS_TRACE_SCAN 0x00000008 ++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 ++#define YAFFS_TRACE_ERASE 0x00000020 ++#define YAFFS_TRACE_GC 0x00000040 ++#define YAFFS_TRACE_WRITE 0x00000080 ++#define YAFFS_TRACE_TRACING 0x00000100 ++#define YAFFS_TRACE_DELETION 0x00000200 ++#define YAFFS_TRACE_BUFFERS 0x00000400 ++#define YAFFS_TRACE_NANDACCESS 0x00000800 ++#define YAFFS_TRACE_GC_DETAIL 0x00001000 ++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 ++#define YAFFS_TRACE_MTD 0x00004000 ++#define YAFFS_TRACE_CHECKPOINT 0x00008000 ++ ++#define YAFFS_TRACE_VERIFY 0x00010000 ++#define YAFFS_TRACE_VERIFY_NAND 0x00020000 ++#define YAFFS_TRACE_VERIFY_FULL 0x00040000 ++#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 ++ ++ ++#define YAFFS_TRACE_ERROR 0x40000000 ++#define YAFFS_TRACE_BUG 0x80000000 ++#define YAFFS_TRACE_ALWAYS 0xF0000000 ++ ++ ++#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) ++ ++#ifndef YBUG ++#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) ++#endif ++ ++#endif -- cgit v1.2.3 From 30fa86e11903de3dc5695df9f326c88ae2a46ba4 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 23 Jul 2009 16:18:54 +0200 Subject: patch breaks rb532, need to investigate later --- toolchain/uClibc/patches/pagesize-fix.patch | 276 ---------------------------- 1 file changed, 276 deletions(-) delete mode 100644 toolchain/uClibc/patches/pagesize-fix.patch diff --git a/toolchain/uClibc/patches/pagesize-fix.patch b/toolchain/uClibc/patches/pagesize-fix.patch deleted file mode 100644 index 789820638..000000000 --- a/toolchain/uClibc/patches/pagesize-fix.patch +++ /dev/null @@ -1,276 +0,0 @@ -diff -Nur uClibc-0.9.30.1.orig/ldso/include/ldso.h uClibc-0.9.30.1/ldso/include/ldso.h ---- uClibc-0.9.30.1.orig/ldso/include/ldso.h 2008-05-30 16:35:31.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/include/ldso.h 2009-06-21 19:34:42.324963528 +0200 -@@ -39,6 +39,19 @@ - #include - #include - -+/* common align masks, if not specified by sysdep headers */ -+#ifndef ADDR_ALIGN -+#define ADDR_ALIGN (_dl_pagesize - 1) -+#endif -+ -+#ifndef PAGE_ALIGN -+#define PAGE_ALIGN (~ADDR_ALIGN) -+#endif -+ -+#ifndef OFFS_ALIGN -+#define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1))) -+#endif -+ - /* For INIT/FINI dependency sorting. */ - struct init_fini_list { - struct init_fini_list *next; -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/arm/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/arm/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/arm/dl-sysdep.h 2008-09-25 10:35:20.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/arm/dl-sysdep.h 2009-06-21 19:34:42.324963528 +0200 -@@ -55,11 +55,6 @@ - struct elf_resolve; - unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - PLT entries should not be allowed to define the value. - ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/avr32/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/avr32/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/avr32/dl-sysdep.h 2008-11-03 16:54:24.000000000 +0100 -+++ uClibc-0.9.30.1/ldso/ldso/avr32/dl-sysdep.h 2009-06-21 19:34:42.324963528 +0200 -@@ -46,11 +46,6 @@ - - unsigned long _dl_linux_resolver(unsigned long got_offset, unsigned long *got); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - #define elf_machine_type_class(type) \ - ((type == R_AVR32_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) - -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/bfin/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/bfin/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/bfin/dl-sysdep.h 2008-07-23 13:23:36.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/bfin/dl-sysdep.h 2009-06-21 19:34:42.324963528 +0200 -@@ -67,12 +67,6 @@ - - extern int _dl_linux_resolve(void) __attribute__((__visibility__("hidden"))); - --/* 4KiB page alignment. Should perhaps be made dynamic using -- getpagesize(), based on AT_PAGESZ from auxvt? */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - struct funcdesc_ht; - - #undef SEND_EARLY_STDERR -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/cris/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/cris/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/cris/dl-sysdep.h 2008-07-23 13:19:00.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/cris/dl-sysdep.h 2009-06-21 19:34:42.324963528 +0200 -@@ -18,11 +18,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry); - --/* 8192 bytes alignment */ --#define PAGE_ALIGN 0xffffe000 --#define ADDR_ALIGN 0x1fff --#define OFFS_ALIGN 0xffffe000 -- - /* The union of reloc-type-classes where the reloc TYPE is a member. - - TYPE is in the class ELF_RTYPE_CLASS_PLT if it can describe a -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/frv/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/frv/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/frv/dl-sysdep.h 2008-07-23 13:23:36.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/frv/dl-sysdep.h 2009-06-21 19:34:42.324963528 +0200 -@@ -51,12 +51,6 @@ - - extern int _dl_linux_resolve(void) __attribute__((__visibility__("hidden"))); - --/* 16KiB page alignment. Should perhaps be made dynamic using -- getpagesize(), based on AT_PAGESZ from auxvt? */ --#define PAGE_ALIGN 0xffffc000 --#define ADDR_ALIGN 0x3fff --#define OFFS_ALIGN 0x7fffc000 -- - struct funcdesc_ht; - - /* We must force strings used early in the bootstrap into the data -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/i386/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/i386/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/i386/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/i386/dl-sysdep.h 2009-06-21 19:34:42.328963480 +0200 -@@ -25,11 +25,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or - TLS variable, so undefined references should not be allowed to - define the value. -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/m68k/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/m68k/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/m68k/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/m68k/dl-sysdep.h 2009-06-21 19:34:42.328963480 +0200 -@@ -25,11 +25,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver (struct elf_resolve *, int); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - PLT entries should not be allowed to define the value. - ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/mips/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/mips/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/mips/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/mips/dl-sysdep.h 2009-06-22 20:51:04.324542339 +0200 -@@ -148,14 +148,9 @@ - - /* 4096 bytes alignment */ - #if _MIPS_SIM == _MIPS_SIM_ABI64 --#define PAGE_ALIGN (~0xfffUL) --#define ADDR_ALIGN 0xfffUL --#define OFFS_ALIGN (0x10000000000UL-0x1000) --#else /* O32 || N32 */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 --#endif /* O32 || N32 */ -+#define OFFS_ALIGN (0x10000000000UL-_dl_pagesize) -+#endif -+/* O32 || N32 */ - - #define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT - /* MIPS does not have COPY relocs */ -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/powerpc/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/powerpc/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/powerpc/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/powerpc/dl-sysdep.h 2009-06-21 19:34:42.328963480 +0200 -@@ -67,11 +67,6 @@ - extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); - void _dl_init_got(unsigned long *lpnt,struct elf_resolve *tpnt); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - PLT entries should not be allowed to define the value. - ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/sh/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/sh/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/sh/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/sh/dl-sysdep.h 2009-06-21 19:34:42.328963480 +0200 -@@ -83,11 +83,6 @@ - - #define do_rem(result, n, base) ((result) = _dl_urem((n), (base))) - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or - TLS variable, so undefined references should not be allowed to - define the value. -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/sh64/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/sh64/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/sh64/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/sh64/dl-sysdep.h 2009-06-21 19:34:42.328963480 +0200 -@@ -25,11 +25,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or - TLS variable, so undefined references should not be allowed to - define the value. -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/sparc/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/sparc/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/sparc/dl-sysdep.h 2008-09-15 18:36:11.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/sparc/dl-sysdep.h 2009-06-21 19:34:42.332963990 +0200 -@@ -89,18 +89,6 @@ - #define do_rem(result, n, base) ((result) = sparc_mod(n, base)) - #endif - --/* 4096 bytes alignment */ --#if defined(__sparc_v9__) --/* ...but 8192 is required for mmap() on sparc64 kernel */ --#define PAGE_ALIGN 0xffffe000 --#define ADDR_ALIGN 0x1fff --#define OFFS_ALIGN 0x7fffe000 --#elif defined(__sparc_v8__) --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 --#endif -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - PLT entries should not be allowed to define the value. - ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/x86_64/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/x86_64/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/x86_64/dl-sysdep.h 2006-03-08 04:58:13.000000000 +0100 -+++ uClibc-0.9.30.1/ldso/ldso/x86_64/dl-sysdep.h 2009-06-21 19:34:42.332963990 +0200 -@@ -41,11 +41,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or - TLS variable, so undefined references should not be allowed to - define the value. -diff -Nur uClibc-0.9.30.1.orig/ldso/ldso/xtensa/dl-sysdep.h uClibc-0.9.30.1/ldso/ldso/xtensa/dl-sysdep.h ---- uClibc-0.9.30.1.orig/ldso/ldso/xtensa/dl-sysdep.h 2008-07-23 13:19:00.000000000 +0200 -+++ uClibc-0.9.30.1/ldso/ldso/xtensa/dl-sysdep.h 2009-06-21 19:34:42.332963990 +0200 -@@ -76,11 +76,6 @@ - struct elf_resolve; - extern unsigned long _dl_linux_resolver (struct elf_resolve *, int); - --/* 4096 bytes alignment */ --#define PAGE_ALIGN 0xfffff000 --#define ADDR_ALIGN 0xfff --#define OFFS_ALIGN 0x7ffff000 -- - /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - undefined references should not be allowed to define the value. */ - #define elf_machine_type_class(type) \ -diff -Nur uClibc-0.9.30.1.orig/libc/sysdeps/linux/mips/bits/uClibc_page.h uClibc-0.9.30.1/libc/sysdeps/linux/mips/bits/uClibc_page.h ---- uClibc-0.9.30.1.orig/libc/sysdeps/linux/mips/bits/uClibc_page.h 2004-08-14 01:39:45.000000000 +0200 -+++ uClibc-0.9.30.1/libc/sysdeps/linux/mips/bits/uClibc_page.h 2009-06-22 21:04:53.505363149 +0200 -@@ -20,15 +20,17 @@ - #ifndef _UCLIBC_PAGE_H - #define _UCLIBC_PAGE_H - --/* PAGE_SIZE of mips is sortof wierd, and depends on how the kernel -- * happens to have been configured. It might use 4KB, 16K or 64K -- * pages. To avoid using the current kernel configuration settings, -- * uClibc will simply use 4KB on mips and call it good. */ --#if 0 --#define PAGE_SHIFT 16 -+/* This approach sucks, one should really use sysconf(_SC_PAGESIZE) -+ * instead. The current mips64 kernel only seems to boot with a 16K -+ * page size on a Loongson 2f notebook, so we hardcode it to 16K on -+ * MIPS64 (matching the kernel developer's default) and 4K otherwise. -+ */ -+#ifdef __mips64 - #define PAGE_SHIFT 14 --#endif -+#else - #define PAGE_SHIFT 12 -+#endif -+ - #define PAGE_SIZE (1UL << PAGE_SHIFT) - #define PAGE_MASK (~(PAGE_SIZE-1)) - -- cgit v1.2.3 From 47702b39eed1b8e442a2b670b6097908dd4757ec Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Fri, 24 Jul 2009 22:27:51 +0200 Subject: update asterisk --- package/asterisk/Makefile | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/package/asterisk/Makefile b/package/asterisk/Makefile index e5d428ed5..c3f9e0cef 100644 --- a/package/asterisk/Makefile +++ b/package/asterisk/Makefile @@ -4,12 +4,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:= asterisk -PKG_VERSION:= 1.4.25.1 +PKG_VERSION:= 1.4.26 PKG_RELEASE:= 1 -PKG_MD5SUM:= 1b42210127d6622c90fc5338de2b4aa9 +PKG_MD5SUM:= f54d6685533a149a0241c3468a88e02a PKG_DESCR:= Open Source PBX PKG_SECTION:= net -PKG_DEPENDS:= libncurses libpthread +PKG_DEPENDS:= libncurses libpthread libopenssl libcurl PKG_URL:= http://www.asterisk.org PKG_SITES:= http://downloads.digium.com/pub/telephony/asterisk/releases/ @@ -60,7 +60,6 @@ CONFIGURE_ARGS= --with-z=${STAGING_DIR}/usr \ --without-oss \ --without-pri \ --without-pwlib \ - --without-qt \ --without-tds \ --without-termcap \ --without-tinfo \ @@ -79,12 +78,6 @@ CONFIGURE_ARGS+= --with-ogg=${STAGING_DIR}/usr \ --with-vorbis=${STAGING_DIR}/usr TLDFLAGS+= -logg endif -ifneq (${ADK_PACKAGE_ASTERISK_RADIUS},) -CONFIGURE_ARGS+= --with-radius=${STAGING_DIR}/usr -endif -ifneq (${ADK_PACKAGE_ASTERISK_GNUTLS},) -CONFIGURE_ARGS+= --with-gnutls=${STAGING_DIR}/usr -endif ifneq (${ADK_PACKAGE_ASTERISK_CURL},) CONFIGURE_ARGS+= --with-curl=${STAGING_DIR}/usr else -- cgit v1.2.3 From 17a64091553c08d404917f37453555d674d9b324 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 1 Aug 2009 23:47:30 +0200 Subject: fix compilation of libtirpc when IPV6 is enabled --- package/libtirpc/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/package/libtirpc/Makefile b/package/libtirpc/Makefile index 0a8ee70e8..08d0d765e 100644 --- a/package/libtirpc/Makefile +++ b/package/libtirpc/Makefile @@ -16,11 +16,19 @@ DISTFILES:= $(PKG_NAME)-$(PKG_VERSION).tar.bz2 include ${TOPDIR}/mk/package.mk +ifeq (${ADK_IPV6},y) +PKG_DEPENDS+= libgssglue +endif + $(eval $(call PKG_template,LIBTIRPC,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) CONFIGURE_STYLE:= autotool gnu ifneq (${ADK_COMPILE_NFS_UTILS_WITH_KERBEROS},y) +ifneq (${ADK_IPV6},y) CONFIGURE_ARGS+= --disable-gss +else +CONFIGURE_ARGS+= --enable-gss +endif endif BUILD_STYLE:= auto INSTALL_STYLE:= auto -- cgit v1.2.3 From 24a7b2b06786d4d14ea1f5b5cf2ffb3430a2fb0e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 00:26:52 +0200 Subject: change all 'depends' lines to 'depends on' ones This is only a formal change, the semantics stay exactly the same. But linux-2.6's mconf forces this nowadays, so stay compatible. --- package/Config.in | 4 +- package/apr/Config.in | 2 +- package/asterisk/Config.in | 20 +++--- package/atftp/Config.in | 2 +- package/avahi/Config.in | 4 +- package/axtls/Config.in | 2 +- package/bc/Config.in | 2 +- package/bind/Config.in | 16 ++--- package/bogofilter/Config.in | 4 +- package/collectd/Config.in | 8 +-- package/curl/Config.in | 4 +- package/cyrus-sasl/Config.in | 2 +- package/dhcp/Config.in | 2 +- package/dropbear/Config.in | 2 +- package/e2fsprogs/Config.in | 4 +- package/expat/Config.in | 2 +- package/faad2/Config.in | 2 +- package/fetchmail/Config.in | 2 +- package/flac/Config.in | 2 +- package/freeradius-client/Config.in | 2 +- package/freeradius-server/Config.in | 28 ++++---- package/freetype/Config.in | 2 +- package/gmp/Config.in | 2 +- package/gnutls/Config.in | 10 +-- package/gsm/Config.in | 4 +- package/hostapd/Config.in | 2 +- package/iptables/Config.in | 4 +- package/irssi/Config.in | 2 +- package/jpeg/Config.in | 2 +- package/kismet/Config.in | 2 +- package/knock/Config.in | 2 +- package/libdb/Config.in | 2 +- package/libshout/Config.in | 2 +- package/libtool/Config.in | 2 +- package/libtorrent/Config.in | 2 +- package/lighttpd/Config.in | 32 ++++----- package/lua/Config.in | 2 +- package/mini_httpd/Config.in | 2 +- package/miredo/Config.in | 6 +- package/mksh/Config.in | 2 +- package/mpd/Config.in | 20 +++--- package/mysql/Config.in | 6 +- package/nano/Config.in | 2 +- package/ncurses/Config.in | 2 +- package/ndisc/Config.in | 10 +-- package/olsrd/Config.in | 8 +-- package/opencdk/Config.in | 2 +- package/opensips/Config.in | 46 ++++++------ package/openssl/Config.in | 6 +- package/openvpn/Config.in | 14 ++-- package/osiris/Config.in | 2 +- package/pcre/Config.in | 2 +- package/php/Config.in | 28 ++++---- package/pmacct/Config.in | 2 +- package/popt/Config.in | 2 +- package/postgresql/Config.in | 2 +- package/ppp/Config.in | 14 ++-- package/quagga/Config.in | 18 ++--- package/readline/Config.in | 2 +- package/rp-pppoe/Config.in | 2 +- package/rrdcollect/Config.in | 4 +- package/rrs/Config.in | 2 +- package/samba/Config.in | 2 +- package/sane-backends/Config.in | 116 +++++++++++++++---------------- package/shorewall-common/Config.in | 4 +- package/shorewall-shell/Config.in | 2 +- package/speex/Config.in | 4 +- package/sqlite/Config.in | 4 +- package/squid/Config.in | 18 ++--- package/subversion/Config.in | 2 +- package/tcp_wrappers/Config.in | 2 +- package/tinyproxy/Config.in | 6 +- package/tntnet/Config.in | 4 +- package/ulogd/Config.in | 10 +-- package/updatedd/Config.in | 18 ++--- package/usbutils/Config.in | 2 +- package/util-linux-ng/Config.in | 2 +- package/weechat/Config.in | 4 +- package/wpa_supplicant/Config.in | 4 +- target/Config.in | 2 +- target/linux/config/Config.in.block | 14 ++-- target/linux/config/Config.in.bluetooth | 24 +++---- target/linux/config/Config.in.fs | 4 +- target/linux/config/Config.in.fsnet | 2 +- target/linux/config/Config.in.ipvs | 8 +-- target/linux/config/Config.in.lib | 2 +- target/linux/config/Config.in.multimedia | 12 ++-- target/linux/config/Config.in.netfilter | 44 ++++++------ target/linux/config/Config.in.network | 12 ++-- target/linux/config/Config.in.nls | 76 ++++++++++---------- target/linux/config/Config.in.pcmcia | 4 +- target/linux/config/Config.in.sched | 20 +++--- target/linux/config/Config.in.usb | 44 ++++++------ 93 files changed, 434 insertions(+), 434 deletions(-) diff --git a/package/Config.in b/package/Config.in index 96aeec3aa..1716c763f 100644 --- a/package/Config.in +++ b/package/Config.in @@ -201,7 +201,7 @@ source "package/wput/Config.in" endmenu menu "IPv6" -depends ADK_IPV6 +depends on ADK_IPV6 source "package/6tunnel/Config.in" source "package/aiccu/Config.in" source "package/miredo/Config.in" @@ -452,7 +452,7 @@ source "package/zlib/Config.in" endmenu menu "X" -depends ADK_X11 +depends on ADK_X11 source "package/xorg-server/Config.in" source "package/xf86-video-geode/Config.in" diff --git a/package/apr/Config.in b/package/apr/Config.in index 0cee1afbc..f6c5e0708 100644 --- a/package/apr/Config.in +++ b/package/apr/Config.in @@ -11,6 +11,6 @@ config ADK_PACKAGE_APR_THREADING prompt " Enable threading support" bool default n - depends ADK_PACKAGE_APR + depends on ADK_PACKAGE_APR help Enable threading support in APR. diff --git a/package/asterisk/Config.in b/package/asterisk/Config.in index 70c88064f..72f8b6bca 100644 --- a/package/asterisk/Config.in +++ b/package/asterisk/Config.in @@ -12,7 +12,7 @@ config ADK_PACKAGE_ASTERISK_CHAN_MGCP prompt "asterisk-chan-mgcp.............. Media Gateway Control Protocol implementation" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Media Gateway Control Protocol implementation for Asterisk @@ -20,7 +20,7 @@ config ADK_PACKAGE_ASTERISK_CHAN_SKINNY prompt "asterisk-chan-skinny............ Skinny Client Control Protocol implementation" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Skinny Client Control Protocol implementation for Asterisk @@ -28,7 +28,7 @@ config ADK_PACKAGE_ASTERISK_CHAN_IAX2 prompt "asterisk-chan-iax2.............. Support for the Inter Asterisk Protocol" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help IAX2 allows trunking communication channels together. @@ -39,7 +39,7 @@ config ADK_PACKAGE_ASTERISK_CODEC_SPEEX prompt "asterisk-codec-speex............ Speex/PCM16 Codec Translator" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK select ADK_PACKAGE_LIBSPEEX help The Speex speech compression codec for Asterisk @@ -48,7 +48,7 @@ config ADK_PACKAGE_ASTERISK_CODEC_GSM prompt "asterisk-codec-gsm.............. GSM Codec" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help The GSM codec for Asterisk @@ -56,7 +56,7 @@ config ADK_PACKAGE_ASTERISK_PBX_DUNDI prompt "asterisk-pbx-dundi.............. Distributed Universal Number Discovery (DUNDi) support" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Distributed Universal Number Discovery (DUNDi) support for Asterisk @@ -64,7 +64,7 @@ config ADK_PACKAGE_ASTERISK_RES_AGI prompt "asterisk-res-agi................ Asterisk Gateway Interface module" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Asterisk Gateway Interface module @@ -72,7 +72,7 @@ config ADK_PACKAGE_ASTERISK_PGSQL prompt "asterisk-pgsql.................. PostgreSQL modules" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK select ADK_PACKAGE_LIBPQ help PostgreSQL modules for Asterisk @@ -81,7 +81,7 @@ config ADK_PACKAGE_ASTERISK_SOUNDS prompt "asterisk-sounds................. Sound files" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Sound files for Asterisk @@ -89,7 +89,7 @@ config ADK_PACKAGE_ASTERISK_VOICEMAIL prompt "asterisk-voicemail.............. Voicemail support" tristate default n - depends ADK_PACKAGE_ASTERISK + depends on ADK_PACKAGE_ASTERISK help Voicemail related modules for Asterisk diff --git a/package/atftp/Config.in b/package/atftp/Config.in index 11e1c02b2..8d48e2094 100644 --- a/package/atftp/Config.in +++ b/package/atftp/Config.in @@ -3,7 +3,7 @@ config ADK_COMPILE_ATFTP tristate default n - depends ADK_PACKAGE_ATFTP || ADK_PACKAGE_ATFTPD + depends on ADK_PACKAGE_ATFTP || ADK_PACKAGE_ATFTPD select ADK_PACKAGE_LIBREADLINE config ADK_PACKAGE_ATFTP diff --git a/package/avahi/Config.in b/package/avahi/Config.in index 260096bb6..53d0e1ff8 100644 --- a/package/avahi/Config.in +++ b/package/avahi/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_AVAHI tristate default n - depends ADK_PACKAGE_AVAHI_DAEMON || ADK_PACKAGE_AVAHI_DNSCONFD || ADK_PACKAGE_LIBAVAHI + depends on ADK_PACKAGE_AVAHI_DAEMON || ADK_PACKAGE_AVAHI_DNSCONFD || ADK_PACKAGE_LIBAVAHI config ADK_PACKAGE_AVAHI_DAEMON prompt "avahi-daemon...................... An mDNS/DNS-SD (ZeroConf) implementation (daemon)" @@ -28,7 +28,7 @@ config ADK_PACKAGE_AVAHI_DNSCONFD tristate default n select ADK_COMPILE_AVAHI - depends ADK_PACKAGE_AVAHI_DAEMON + depends on ADK_PACKAGE_AVAHI_DAEMON help Avahi is a system which facilitates service discovery on a local network -- this means that you can plug your laptop or computer into a network and diff --git a/package/axtls/Config.in b/package/axtls/Config.in index 5d1459da9..7c99a9617 100644 --- a/package/axtls/Config.in +++ b/package/axtls/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_AXTLS tristate default n - depends ADK_PACKAGE_LIBAXTLS || ADK_PACKAGE_AXHTTPD + depends on ADK_PACKAGE_LIBAXTLS || ADK_PACKAGE_AXHTTPD config ADK_PACKAGE_AXHTTPD prompt "axhttpd........................... small embedded webserver" diff --git a/package/bc/Config.in b/package/bc/Config.in index cae451a06..20a7d15c4 100644 --- a/package/bc/Config.in +++ b/package/bc/Config.in @@ -1,6 +1,6 @@ config ADK_COMPILE_BC tristate - depends ADK_PACKAGE_BC || ADK_PACKAGE_DC + depends on ADK_PACKAGE_BC || ADK_PACKAGE_DC default n config ADK_PACKAGE_BC diff --git a/package/bind/Config.in b/package/bind/Config.in index 1286057ba..b561312fc 100644 --- a/package/bind/Config.in +++ b/package/bind/Config.in @@ -12,7 +12,7 @@ config ADK_PACKAGE_BIND_RNDC prompt "bind-rndc......................... Bind administration tools (rndc & rndc-confgen only)" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -23,7 +23,7 @@ config ADK_PACKAGE_BIND_CHECK prompt "bind-check........................ Bind administration tools (named-checkconf & named-checkzone only)" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -34,7 +34,7 @@ config ADK_PACKAGE_BIND_DNSSEC prompt "bind-dnssec....................... Bind administration tools (dnssec-keygen & dnssec-signzone only)" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -45,7 +45,7 @@ config ADK_PACKAGE_BIND_HOST prompt "bind-host......................... A simple DNS client" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -57,7 +57,7 @@ config ADK_PACKAGE_BIND_DIG prompt "bind-dig.......................... A DNS client" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -69,7 +69,7 @@ config ADK_PACKAGE_BIND_CLIENT prompt "bind-client....................... A dynamic DNS client" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -80,7 +80,7 @@ config ADK_PACKAGE_BIND_SERVER prompt "bind-server....................... A DNS server" tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND select ADK_PACKAGE_LIBBIND help @@ -91,7 +91,7 @@ config ADK_PACKAGE_LIBBIND prompt "libbind........................... Support library for the bind tools and dns server/client." tristate default n - depends ADK_DUMMY_BIND + depends on ADK_DUMMY_BIND select ADK_COMPILE_BIND help http://www.isc.org/sw/bind/ diff --git a/package/bogofilter/Config.in b/package/bogofilter/Config.in index 1dfb7d2d5..503345cc3 100644 --- a/package/bogofilter/Config.in +++ b/package/bogofilter/Config.in @@ -15,12 +15,12 @@ config ADK_PACKAGE_BOGOFILTER_BOGOUTIL prompt " include bogoutil in firmware image and package file" bool default n - depends ADK_PACKAGE_BOGOFILTER + depends on ADK_PACKAGE_BOGOFILTER config ADK_PACKAGE_BOGOFILTER_BOGOTUNE prompt " include bogotune in firmware image and package file" bool default n - depends ADK_PACKAGE_BOGOFILTER + depends on ADK_PACKAGE_BOGOFILTER diff --git a/package/collectd/Config.in b/package/collectd/Config.in index f645ee403..d040e581c 100644 --- a/package/collectd/Config.in +++ b/package/collectd/Config.in @@ -15,22 +15,22 @@ config ADK_PACKAGE_COLLECTD_CPU prompt "Enable cpu support" bool default y - depends ADK_PACKAGE_COLLECTD + depends on ADK_PACKAGE_COLLECTD config ADK_PACKAGE_COLLECTD_LOAD prompt "Enable load support" bool default y - depends ADK_PACKAGE_COLLECTD + depends on ADK_PACKAGE_COLLECTD config ADK_PACKAGE_COLLECTD_MEMORY prompt "Enable memory support" bool default y - depends ADK_PACKAGE_COLLECTD + depends on ADK_PACKAGE_COLLECTD config ADK_PACKAGE_COLLECTD_PING prompt "Enable ping support" bool default y - depends ADK_PACKAGE_COLLECTD + depends on ADK_PACKAGE_COLLECTD diff --git a/package/curl/Config.in b/package/curl/Config.in index a74a823e2..b5d42ea1f 100644 --- a/package/curl/Config.in +++ b/package/curl/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_CURL tristate default n - depends ADK_PACKAGE_LIBCURL + depends on ADK_PACKAGE_LIBCURL config ADK_PACKAGE_LIBCURL prompt "libcurl........................... A client-side URL transfer library" @@ -19,7 +19,7 @@ config ADK_PACKAGE_CURL prompt "curl............................ A client-side URL transfer tool" tristate default n - depends ADK_PACKAGE_LIBCURL + depends on ADK_PACKAGE_LIBCURL help A client-side URL transfer tool. diff --git a/package/cyrus-sasl/Config.in b/package/cyrus-sasl/Config.in index 6a03bbfb4..2b4657e5a 100644 --- a/package/cyrus-sasl/Config.in +++ b/package/cyrus-sasl/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_CYRUS_SASL tristate default n - depends ADK_PACKAGE_LIBSASL2 + depends on ADK_PACKAGE_LIBSASL2 config ADK_PACKAGE_LIBSASL2 prompt "libsasl2.......................... General purpose authentication library" diff --git a/package/dhcp/Config.in b/package/dhcp/Config.in index 42fbf67f0..f58191e64 100644 --- a/package/dhcp/Config.in +++ b/package/dhcp/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_DHCP tristate default n - depends ADK_PACKAGE_DHCP_RELAY || ADK_PACKAGE_DHCP_SERVER + depends on ADK_PACKAGE_DHCP_RELAY || ADK_PACKAGE_DHCP_SERVER config ADK_PACKAGE_DHCP_RELAY prompt "dhcp-relay........................ ISC DHCP relay" diff --git a/package/dropbear/Config.in b/package/dropbear/Config.in index 0729a7422..ea087b8bb 100644 --- a/package/dropbear/Config.in +++ b/package/dropbear/Config.in @@ -11,4 +11,4 @@ config ADK_PACKAGE_DBCONVERT prompt "dropbearconvert................. Utility for converting SSH keys" tristate default n - depends ADK_PACKAGE_DROPBEAR + depends on ADK_PACKAGE_DROPBEAR diff --git a/package/e2fsprogs/Config.in b/package/e2fsprogs/Config.in index 6638f88fc..0dff689d1 100644 --- a/package/e2fsprogs/Config.in +++ b/package/e2fsprogs/Config.in @@ -13,14 +13,14 @@ config ADK_PACKAGE_E2FSPROGS config ADK_PACKAGE_LIBUUID prompt "libuuid......................... UUID library" - depends ADK_PACKAGE_E2FSPROGS + depends on ADK_PACKAGE_E2FSPROGS tristate default n help config ADK_PACKAGE_LIBCOM_ERR prompt "libcom_err...................... Common error library" - depends ADK_PACKAGE_E2FSPROGS + depends on ADK_PACKAGE_E2FSPROGS tristate default n help diff --git a/package/expat/Config.in b/package/expat/Config.in index 861777a94..209d357b7 100644 --- a/package/expat/Config.in +++ b/package/expat/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_EXPAT tristate default n - depends ADK_PACKAGE_LIBEXPAT + depends on ADK_PACKAGE_LIBEXPAT config ADK_PACKAGE_LIBEXPAT prompt "libexpat.......................... A fast, non-validating, stream-oriented XML parsing library" diff --git a/package/faad2/Config.in b/package/faad2/Config.in index 21d3194c3..8d554727d 100644 --- a/package/faad2/Config.in +++ b/package/faad2/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_FAAD2 tristate default n - depends ADK_PACKAGE_LIBFAAD2 + depends on ADK_PACKAGE_LIBFAAD2 config ADK_PACKAGE_LIBFAAD2 prompt "libfaad2.......................... MP4 decoding library" diff --git a/package/fetchmail/Config.in b/package/fetchmail/Config.in index fa7f1bfe2..1cdb42cc6 100644 --- a/package/fetchmail/Config.in +++ b/package/fetchmail/Config.in @@ -10,7 +10,7 @@ config ADK_PACKAGE_FETCHMAIL config ADK_PACKAGE_FETCHMAIL_SSL bool " Enable SSL/TLS support" - depends ADK_PACKAGE_FETCHMAIL + depends on ADK_PACKAGE_FETCHMAIL select ADK_PACKAGE_LIBOPENSSL default n help diff --git a/package/flac/Config.in b/package/flac/Config.in index bef5c0876..346e70e75 100644 --- a/package/flac/Config.in +++ b/package/flac/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_FLAC tristate default n - depends ADK_PACKAGE_LIBFLAC + depends on ADK_PACKAGE_LIBFLAC config ADK_PACKAGE_LIBFLAC prompt "libflac........................... Free Lossless Audio Codec library" diff --git a/package/freeradius-client/Config.in b/package/freeradius-client/Config.in index 79325a755..987c52c0a 100644 --- a/package/freeradius-client/Config.in +++ b/package/freeradius-client/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_FREERADIUS_CLIENT tristate default n - depends ADK_PACKAGE_LIBFREERADIUS_CLIENT + depends on ADK_PACKAGE_LIBFREERADIUS_CLIENT config ADK_PACKAGE_FREERADIUS_CLIENT prompt "freeradius-client................. RADIUS client" diff --git a/package/freeradius-server/Config.in b/package/freeradius-server/Config.in index 56fcf16ea..344472c22 100644 --- a/package/freeradius-server/Config.in +++ b/package/freeradius-server/Config.in @@ -13,86 +13,86 @@ config ADK_PACKAGE_FREERADIUS_DEMOCERTS prompt " freeradius-democerts.......... Demo certificates to test the server" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_CHAP prompt " freeradius-mod-chap........... CHAP module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_DETAIL prompt " freeradius-mod-detail......... Detailed accounting module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_DIGEST prompt " freeradius-mod-digest......... Digest authentication" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_FILES prompt " freeradius-mod-files.......... Module using local files for authorization" tristate default y - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_LDAP prompt " freeradius-mod-ldap........... LDAP module" tristate default n select ADK_PACKAGE_LIBOPENLDAP - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_MSCHAP prompt " freeradius-mod-mschap......... MS-CHAP and MS-CHAPv2 module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_PAP prompt " freeradius-mod-pap............ PAP module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_PREPROCESS prompt " freeradius-mod-preprocess..... Request pre-processing module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_REALM prompt " freeradius-mod-realm.......... Realms handling module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_SQL prompt " freeradius-mod-sql............ Base SQL module" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_SQL_MYSQL prompt " freeradius-mod-sql-mysql.... MySQL module" tristate default n depends on ADK_CXX - depends ADK_PACKAGE_FREERADIUS_MOD_SQL + depends on ADK_PACKAGE_FREERADIUS_MOD_SQL select ADK_PACKAGE_LIBMYSQLCLIENT config ADK_PACKAGE_FREERADIUS_MOD_SQL_PGSQL prompt " freeradius-mod-sql-pgsql.... PostgreSQL module" tristate default n - depends ADK_PACKAGE_FREERADIUS_MOD_SQL + depends on ADK_PACKAGE_FREERADIUS_MOD_SQL select ADK_PACKAGE_LIBPQ config ADK_PACKAGE_FREERADIUS_UTILS prompt " freeradius-utils.............. Misc. client utilities" tristate default n - depends ADK_PACKAGE_FREERADIUS_SERVER + depends on ADK_PACKAGE_FREERADIUS_SERVER diff --git a/package/freetype/Config.in b/package/freetype/Config.in index f860e7ce0..408998aa8 100644 --- a/package/freetype/Config.in +++ b/package/freetype/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_FREETYPE tristate default n - depends ADK_PACKAGE_LIBFREETYPE + depends on ADK_PACKAGE_LIBFREETYPE config ADK_PACKAGE_LIBFREETYPE tristate "libfreetype....................... A free, high-quality and portable font engine" diff --git a/package/gmp/Config.in b/package/gmp/Config.in index e681b6519..9ef3f1e4a 100644 --- a/package/gmp/Config.in +++ b/package/gmp/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_GMP tristate default n - depends ADK_PACKAGE_LIBGMP + depends on ADK_PACKAGE_LIBGMP config ADK_PACKAGE_LIBGMP prompt "libgmp............................ GNU multiprecision arithmetic library" diff --git a/package/gnutls/Config.in b/package/gnutls/Config.in index ffe1125b0..83db1d706 100644 --- a/package/gnutls/Config.in +++ b/package/gnutls/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_GNUTLS tristate default n - depends ADK_PACKAGE_LIBGNUTLS + depends on ADK_PACKAGE_LIBGNUTLS config ADK_PACKAGE_LIBGNUTLS prompt "libgnutls......................... The GNU TLS library" @@ -41,7 +41,7 @@ config ADK_PACKAGE_LIBGNUTLS_EXTRA prompt "libgnutls-extra................... The GNU TLS extra library" tristate default n - depends ADK_PACKAGE_LIBGNUTLS + depends on ADK_PACKAGE_LIBGNUTLS select ADK_PACKAGE_LIBOPENCDK select ADK_PACKAGE_LIBLZO help @@ -58,7 +58,7 @@ config ADK_PACKAGE_LIBGNUTLS_OPENSSL prompt "libgnutls-openssl................. The GNU TLS OpenSSL compatibility layer library" tristate default n - depends ADK_PACKAGE_LIBGNUTLS + depends on ADK_PACKAGE_LIBGNUTLS help GnuTLS is a project that aims to develop a library which provides a secure layer, over a reliable transport layer. Currently the GnuTLS @@ -73,7 +73,7 @@ config ADK_PACKAGE_LIBGNUTLSXX tristate default n depends on ADK_CXX - depends ADK_PACKAGE_LIBGNUTLS + depends on ADK_PACKAGE_LIBGNUTLS help GnuTLS is a project that aims to develop a library which provides a secure layer, over a reliable transport layer. Currently the GnuTLS @@ -104,7 +104,7 @@ config ADK_PACKAGE_GNUTLS_UTILS prompt "gnutls-utils...................... The GNU TLS utilities" tristate default n - depends ADK_PACKAGE_LIBGNUTLS + depends on ADK_PACKAGE_LIBGNUTLS select ADK_PACKAGE_LIBGNUTLS_EXTRA help GnuTLS is a project that aims to develop a library which provides a diff --git a/package/gsm/Config.in b/package/gsm/Config.in index 77bf91626..9af1d7dda 100644 --- a/package/gsm/Config.in +++ b/package/gsm/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_GSM tristate default n - depends ADK_PACKAGE_LIBGSM + depends on ADK_PACKAGE_LIBGSM config ADK_PACKAGE_LIBGSM prompt "libgsm............................ A GSM 06.10 full-rate speech transcoding implementation (library)" @@ -20,7 +20,7 @@ config ADK_PACKAGE_GSM_UTILS prompt "gsm-utils....................... A GSM 06.10 full-rate speech transcoding implementation (utilities)" tristate default n - depends ADK_PACKAGE_LIBGSM + depends on ADK_PACKAGE_LIBGSM help An implementation of the European GSM 06.10 provisional standard for full-rate speech transcoding, prI-ETS 300 036, which uses diff --git a/package/hostapd/Config.in b/package/hostapd/Config.in index 562f1f23c..bd0ec3865 100644 --- a/package/hostapd/Config.in +++ b/package/hostapd/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_HOSTAPD tristate default n - depends ADK_PACKAGE_HOSTAPD || ADK_PACKAGE_HOSTAPD_UTILS + depends on ADK_PACKAGE_HOSTAPD || ADK_PACKAGE_HOSTAPD_UTILS config ADK_PACKAGE_HOSTAPD prompt "hostapd........................... An IEEE 802.11 AP, IEEE 802.1x/WPA/WPA2/EAP/RADIUS Authenticator" diff --git a/package/iptables/Config.in b/package/iptables/Config.in index bf7fd0ebb..5b82599ad 100644 --- a/package/iptables/Config.in +++ b/package/iptables/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_IPTABLES bool default n - depends ADK_PACKAGE_IPTABLES || ADK_PACKAGE_IP6TABLES + depends on ADK_PACKAGE_IPTABLES || ADK_PACKAGE_IP6TABLES config ADK_PACKAGE_IPTABLES prompt "iptables.......................... IPv4 firewall administration tool" @@ -25,7 +25,7 @@ config ADK_PACKAGE_IPTABLES_UTILS prompt "iptables-utils.................. Save and restore utilities" tristate default n - depends ADK_PACKAGE_IPTABLES + depends on ADK_PACKAGE_IPTABLES help iptables-save and iptables-restore for Iptables (IPv4) diff --git a/package/irssi/Config.in b/package/irssi/Config.in index 44fa5d5a4..f60e946ee 100644 --- a/package/irssi/Config.in +++ b/package/irssi/Config.in @@ -11,7 +11,7 @@ config ADK_PACKAGE_IRSSI config ADK_PACKAGE_IRSSI_SSL bool " Enable SSL/TLS support" - depends ADK_PACKAGE_IRSSI + depends on ADK_PACKAGE_IRSSI select ADK_PACKAGE_LIBOPENSSL default n help diff --git a/package/jpeg/Config.in b/package/jpeg/Config.in index 4d05a0761..4fe390d21 100644 --- a/package/jpeg/Config.in +++ b/package/jpeg/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_JPEG tristate default n - depends ADK_PACKAGE_LIBJPEG + depends on ADK_PACKAGE_LIBJPEG config ADK_PACKAGE_LIBJPEG prompt "libjpeg........................... The Independent JPEG Group's JPEG runtime library" diff --git a/package/kismet/Config.in b/package/kismet/Config.in index 84b256509..2583f88d2 100644 --- a/package/kismet/Config.in +++ b/package/kismet/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_KISMET tristate default n - depends ADK_PACKAGE_KISMET_CLIENT || ADK_PACKAGE_KISMET_DRONE || ADK_PACKAGE_KISMET_SERVER + depends on ADK_PACKAGE_KISMET_CLIENT || ADK_PACKAGE_KISMET_DRONE || ADK_PACKAGE_KISMET_SERVER config ADK_PACKAGE_KISMET_CLIENT prompt "kismet-client..................... The Kismet client" diff --git a/package/knock/Config.in b/package/knock/Config.in index ada7f06c8..291ea3b0d 100644 --- a/package/knock/Config.in +++ b/package/knock/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_KNOCK tristate default n - depends ADK_PACKAGE_KNOCK || ADK_PACKAGE_KNOCKD + depends on ADK_PACKAGE_KNOCK || ADK_PACKAGE_KNOCKD config ADK_PACKAGE_KNOCK prompt "knock............................. A port-knocking client" diff --git a/package/libdb/Config.in b/package/libdb/Config.in index f8360bee8..510311508 100644 --- a/package/libdb/Config.in +++ b/package/libdb/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_DB tristate default n - depends ADK_PACKAGE_LIBDB + depends on ADK_PACKAGE_LIBDB config ADK_PACKAGE_LIBDB prompt "libdb............................. Berkeley DB" diff --git a/package/libshout/Config.in b/package/libshout/Config.in index 9c9aaf3d5..2a34f2c1b 100644 --- a/package/libshout/Config.in +++ b/package/libshout/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_LIBSHOUT tristate default n - depends ADK_PACKAGE_LIBSHOUT + depends on ADK_PACKAGE_LIBSHOUT config ADK_PACKAGE_LIBSHOUT prompt "libshout.......................... Streaming library" diff --git a/package/libtool/Config.in b/package/libtool/Config.in index aed0c9640..5d26b838b 100644 --- a/package/libtool/Config.in +++ b/package/libtool/Config.in @@ -1,6 +1,6 @@ config ADK_COMPILE_LIBTOOL tristate - depends ADK_PACKAGE_LIBLTDL + depends on ADK_PACKAGE_LIBLTDL config ADK_PACKAGE_LIBLTDL prompt "libltdl........................... A generic dynamic object loading library" diff --git a/package/libtorrent/Config.in b/package/libtorrent/Config.in index be20ecbea..ab8ae5585 100644 --- a/package/libtorrent/Config.in +++ b/package/libtorrent/Config.in @@ -22,7 +22,7 @@ config ADK_COMPILE_LIBTORRENT_WITH_STDCXX config ADK_COMPILE_LIBTORRENT_WITH_UCLIBCXX bool "Embedded uClibc++ library" select ADK_PACKAGE_UCLIBCXX - depends ADK_BROKEN + depends on ADK_BROKEN help endchoice diff --git a/package/lighttpd/Config.in b/package/lighttpd/Config.in index 6eea65df2..f83aebb46 100644 --- a/package/lighttpd/Config.in +++ b/package/lighttpd/Config.in @@ -20,94 +20,94 @@ config ADK_PACKAGE_LIGHTTPD_MOD_ACCESSLOG prompt " lighttpd-mod-accesslog........ Access logging module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_ALIAS prompt " lighttpd-mod-alias............ Directory alias module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_AUTH prompt " lighttpd-mod-auth............. Authentication module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_CGI prompt " lighttpd-mod-cgi.............. CGI module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_EVASIVE prompt " lighttpd-mod-evasive.......... Evasive module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_EXPIRE prompt " lighttpd-mod-expire........... Expire module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_FASTCGI prompt " lighttpd-mod-fastcgi.......... FastCGI module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_PROXY prompt " lighttpd-mod-proxy............ Proxy module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_REDIRECT prompt " lighttpd-mod-redirect......... URL redirection module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_REWRITE prompt " lighttpd-mod-rewrite.......... URL rewriting module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SETENV prompt " lighttpd-mod-setenv........... Environment variable setting module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SIMPLE_VHOST prompt " lighttpd-mod-simple-vhost..... Simple virtual hosting module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SSI prompt " lighttpd-mod-ssi.............. SSI module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_STATUS prompt " lighttpd-mod-status........... Server status display module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_USERTRACK prompt " lighttpd-mod-usertrack........ User tracking module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_WEBDAV prompt " lighttpd-mod-webdav........... webdav module" tristate default n - depends ADK_PACKAGE_LIGHTTPD + depends on ADK_PACKAGE_LIGHTTPD diff --git a/package/lua/Config.in b/package/lua/Config.in index 1fbff9ebe..580d82217 100644 --- a/package/lua/Config.in +++ b/package/lua/Config.in @@ -3,7 +3,7 @@ config ADK_COMPILE_LUA tristate default n - depends ADK_PACKAGE_LIBLUA + depends on ADK_PACKAGE_LIBLUA config ADK_PACKAGE_LIBLUA prompt "liblua............................ LUA programming language shared libraries" diff --git a/package/mini_httpd/Config.in b/package/mini_httpd/Config.in index 3922f14cd..bd83fdb09 100644 --- a/package/mini_httpd/Config.in +++ b/package/mini_httpd/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_MINI_HTTPD tristate default n - depends ADK_PACKAGE_MINI_HTTPD || ADK_PACKAGE_MINI_HTTPD_OPENSSL + depends on ADK_PACKAGE_MINI_HTTPD || ADK_PACKAGE_MINI_HTTPD_OPENSSL config ADK_PACKAGE_MINI_HTTPD prompt "mini-httpd........................ A small web server" diff --git a/package/miredo/Config.in b/package/miredo/Config.in index 928e06c5d..8fb215c06 100644 --- a/package/miredo/Config.in +++ b/package/miredo/Config.in @@ -3,13 +3,13 @@ config ADK_COMPILE_MIREDO default n depends on ADK_CXX depends on ADK_IPV6 - depends ADK_PACKAGE_MIREDO || ADK_PACKAGE_MIREDO_SERVER + depends on ADK_PACKAGE_MIREDO || ADK_PACKAGE_MIREDO_SERVER config ADK_PACKAGE_MIREDO prompt "miredo............................ Teredo (IPv6 tunneling over UDP through NAT) client and relay daemon" tristate default n - depends ADK_IPV6 + depends on ADK_IPV6 depends on ADK_CXX select ADK_COMPILE_MIREDO select ADK_KPACKAGE_KMOD_IPV6 @@ -23,7 +23,7 @@ config ADK_PACKAGE_MIREDO_SERVER prompt "miredo-server..................... Teredo (IPv6 tunneling over UDP through NAT) server daemon" tristate default n - depends ADK_IPV6 + depends on ADK_IPV6 depends on ADK_CXX select ADK_COMPILE_MIREDO select ADK_KPACKAGE_KMOD_IPV6 diff --git a/package/mksh/Config.in b/package/mksh/Config.in index 39f792af3..dacca6427 100644 --- a/package/mksh/Config.in +++ b/package/mksh/Config.in @@ -22,7 +22,7 @@ config ADK_PACKAGE_MKSH config ADK_PACKAGE_MKSH_FULL bool " Include all features" - depends ADK_PACKAGE_MKSH + depends on ADK_PACKAGE_MKSH default y help Disable this to remove a few functions from mksh to make it smaller. diff --git a/package/mpd/Config.in b/package/mpd/Config.in index 259df005f..0d0cde14a 100644 --- a/package/mpd/Config.in +++ b/package/mpd/Config.in @@ -18,7 +18,7 @@ config ADK_COMPILE_MPD_WITH_MP3 prompt " MP3 support" bool default y - depends ADK_PACKAGE_MPD + depends on ADK_PACKAGE_MPD select ADK_PACKAGE_LIBMAD select ADK_PACKAGE_LIBID3TAG help @@ -28,7 +28,7 @@ config ADK_COMPILE_MPD_WITH_MP4 prompt " MP4/AAC support" bool default y - depends ADK_PACKAGE_MPD + depends on ADK_PACKAGE_MPD select ADK_PACKAGE_LIBFAAD2 help Enable mp4/aac support (libfaad2). @@ -36,7 +36,7 @@ config ADK_COMPILE_MPD_WITH_MP4 config ADK_COMPILE_MPD_OGG prompt " Ogg/Vorbis Support" tristate - depends ADK_PACKAGE_MPD + depends on ADK_PACKAGE_MPD select ADK_COMPILE_MPD_WITH_OGG if ADK_COMPILE_MPD_OGG_FLOAT select ADK_COMPILE_MPD_WITH_TREMOR if ADK_COMPILE_MPD_OGG_FIXED default y @@ -55,8 +55,8 @@ endchoice config ADK_COMPILE_MPD_WITH_OGG bool default n - depends ADK_PACKAGE_MPD - depends ADK_COMPILE_MPD_OGG_FLOAT + depends on ADK_PACKAGE_MPD + depends on ADK_COMPILE_MPD_OGG_FLOAT select ADK_PACKAGE_LIBOGG select ADK_PACKAGE_LIBVORBIS help @@ -65,8 +65,8 @@ config ADK_COMPILE_MPD_WITH_OGG config ADK_COMPILE_MPD_WITH_TREMOR bool default n - depends ADK_PACKAGE_MPD - depends ADK_COMPILE_MPD_OGG_FIXED + depends on ADK_PACKAGE_MPD + depends on ADK_COMPILE_MPD_OGG_FIXED select ADK_PACKAGE_LIBVORBISIDEC help Enable ogg support (tremor). @@ -76,7 +76,7 @@ config ADK_COMPILE_MPD_WITH_FLAC prompt " FLAC Support" bool default y - depends ADK_PACKAGE_MPD + depends on ADK_PACKAGE_MPD select ADK_PACKAGE_LIBFLAC help Enable flac support (libflac). @@ -85,8 +85,8 @@ config ADK_COMPILE_MPD_WITH_SHOUT prompt " Shout Support (Streaming support)" bool default y - depends ADK_PACKAGE_MPD - depends ADK_COMPILE_MPD_WITH_OGG + depends on ADK_PACKAGE_MPD + depends on ADK_COMPILE_MPD_WITH_OGG select ADK_PACKAGE_LIBSHOUT select ADK_PACKAGE_LIBVORBISENC select ADK_PACKAGE_LIBLAME diff --git a/package/mysql/Config.in b/package/mysql/Config.in index 14b27169e..411823eb7 100644 --- a/package/mysql/Config.in +++ b/package/mysql/Config.in @@ -1,8 +1,8 @@ config ADK_COMPILE_MYSQL tristate default n - depends ADK_PACKAGE_LIBMYSQLCLIENT - depends ADK_CXX + depends on ADK_PACKAGE_LIBMYSQLCLIENT + depends on ADK_CXX select ADK_PACKAGE_LIBNCURSES select ADK_PACKAGE_ZLIB select ADK_PACKAGE_LIBREADLINE @@ -11,7 +11,7 @@ config ADK_PACKAGE_LIBMYSQLCLIENT prompt "libmysqlclient.................... MySQL client library" tristate default n - depends ADK_CXX + depends on ADK_CXX select ADK_COMPILE_MYSQL help MySQL client library. diff --git a/package/nano/Config.in b/package/nano/Config.in index 7b164fa22..19b9ca6d9 100644 --- a/package/nano/Config.in +++ b/package/nano/Config.in @@ -12,7 +12,7 @@ config ADK_PACKAGE_NANO_TINY prompt " only compile a minimal nano (using --enable-tiny)" bool default y - depends ADK_PACKAGE_NANO + depends on ADK_PACKAGE_NANO help If not selected, nano will support justify, line wrapping, tab completion and multiple open file buffers. diff --git a/package/ncurses/Config.in b/package/ncurses/Config.in index 4847013b6..e5526dbcc 100644 --- a/package/ncurses/Config.in +++ b/package/ncurses/Config.in @@ -1,6 +1,6 @@ config ADK_COMPILE_NCURSES tristate - depends ADK_PACKAGE_LIBNCURSES + depends on ADK_PACKAGE_LIBNCURSES config ADK_PACKAGE_LIBNCURSES prompt "libncurses........................ Terminal handling library" diff --git a/package/ndisc/Config.in b/package/ndisc/Config.in index e7cafd5ee..c5723d37b 100644 --- a/package/ndisc/Config.in +++ b/package/ndisc/Config.in @@ -3,14 +3,14 @@ config ADK_COMPILE_NDISC6 tristate default n - depends ADK_IPV6 - depends ADK_PACKAGE_NDISC6 || ADK_PACKAGE_RDISC6 || ADK_PACKAGE_TCPTRACEROUTE6 + depends on ADK_IPV6 + depends on ADK_PACKAGE_NDISC6 || ADK_PACKAGE_RDISC6 || ADK_PACKAGE_TCPTRACEROUTE6 config ADK_PACKAGE_NDISC6 prompt "ndisc6............................ An ICMPv6 neighbour discovery tool" tristate default n - depends ADK_IPV6 + depends on ADK_IPV6 select ADK_COMPILE_NDISC6 help @@ -22,7 +22,7 @@ config ADK_PACKAGE_RDISC6 prompt "rdisc6............................ An ICMPv6 router discovery tool" tristate default n - depends ADK_IPV6 + depends on ADK_IPV6 select ADK_COMPILE_NDISC6 help @@ -34,7 +34,7 @@ config ADK_PACKAGE_TCPTRACEROUTE6 prompt "tcptraceroute6.................... A TCP/IPv6-based traceroute implementation" tristate default n - depends ADK_IPV6 + depends on ADK_IPV6 select ADK_COMPILE_NDISC6 help diff --git a/package/olsrd/Config.in b/package/olsrd/Config.in index c715b9ada..a4f25efe3 100644 --- a/package/olsrd/Config.in +++ b/package/olsrd/Config.in @@ -13,24 +13,24 @@ config ADK_PACKAGE_OLSRD_MOD_DYN_GW prompt " olsrd-mod-dyn-gw.............. Dynamic internet gateway plugin" tristate default n - depends ADK_PACKAGE_OLSRD + depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_HTTPINFO prompt " olsrd-mod-httpinfo............ Small informative web server plugin" tristate default n - depends ADK_PACKAGE_OLSRD + depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_NAMESERVICE prompt " olsrd-mod-nameservice......... Lightweight hostname resolver plugin" tristate default n - depends ADK_PACKAGE_OLSRD + depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_TAS prompt " olsrd-mod-tas................. Tiny Application Server (TAS) plugin for olsrd" tristate default n - depends ADK_PACKAGE_OLSRD + depends on ADK_PACKAGE_OLSRD #endmenu diff --git a/package/opencdk/Config.in b/package/opencdk/Config.in index dffbc2b32..ce8fdf27c 100644 --- a/package/opencdk/Config.in +++ b/package/opencdk/Config.in @@ -1,7 +1,7 @@ config ADK_PACKAGE_OPENCDK tristate default n - depends ADK_PACKAGE_LIBOPENCDK + depends on ADK_PACKAGE_LIBOPENCDK config ADK_PACKAGE_LIBOPENCDK prompt "libopencdk........................ The Open Crypto Development Kit library" diff --git a/package/opensips/Config.in b/package/opensips/Config.in index bc03bd78a..fce57634e 100644 --- a/package/opensips/Config.in +++ b/package/opensips/Config.in @@ -13,7 +13,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_ACCOUNTING prompt " opensips-mod-acc............... Accounting support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable accounting support @@ -21,7 +21,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AUTH prompt " opensips-mod-auth.............. Authentication support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable authentication support @@ -29,7 +29,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AUTH_DB prompt " opensips-mod-auth-db......... Authentication with database support" tristate default n - depends ADK_PACKAGE_OPENSIPS_MOD_AUTH + depends on ADK_PACKAGE_OPENSIPS_MOD_AUTH help Enable authentication with database support @@ -37,7 +37,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AVPOPS prompt " opensips-mod-avpops............ AVP options support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable AVP options support @@ -45,7 +45,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_DISPATCHER prompt " opensips-mod-dispatcher........ dispatcher support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable dispatcher options support @@ -53,7 +53,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_DIVERSION prompt " opensips-mod-diversion......... diversion support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable diversion options support @@ -61,7 +61,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_FLATSTORE prompt " opensips-mod-flatstore......... flatstore support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable flatstore support @@ -69,7 +69,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_GFLAGS prompt " opensips-mod-gflags............ gflags support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable GFlags support @@ -77,7 +77,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_GROUP prompt " opensips-mod-group............. group support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable group support @@ -85,7 +85,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_MEDIAPROXY prompt " opensips-mod-mediaproxy........ Mediaproxy support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable mediaproxy support @@ -93,7 +93,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_MSILO prompt " opensips-mod-msilo............. MSilo support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable msilo support @@ -101,7 +101,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_NATHELPER prompt " opensips-mod-nathelper......... NAT helper support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help NAT helper support @@ -109,7 +109,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_OPTIONS prompt " opensips-mod-options........... options support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable options support @@ -117,7 +117,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PDT prompt " opensips-mod-pdt............... PDT support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable pdt support @@ -125,7 +125,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PERMISSIONS prompt " opensips-mod-permissions....... Permissions support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable permissions support @@ -133,7 +133,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PIKE prompt " opensips-mod-pike.............. PIKE support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable pike support @@ -141,7 +141,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_SMS prompt " opensips-mod-sms............... SMS support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help SMS support @@ -149,7 +149,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_SPEEDDIAL prompt " opensips-mod-speeddial......... Speed Dial support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Speed Dial support @@ -157,7 +157,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_UAC prompt " opensips-mod-uac............... UAC support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable UAC support @@ -165,7 +165,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_UAC_REDIRECT prompt " opensips-mod-uac............... UAC redirect support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable UAC redirect support @@ -173,7 +173,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_URI prompt " opensips-mod-uri............... URI support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable URI support @@ -181,7 +181,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_URI_DB prompt " opensips-mod-uri-db............ URI database support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Enable URI database support @@ -189,7 +189,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_XLOG prompt " opensips-mod-xlog.............. Logging support" tristate default n - depends ADK_PACKAGE_OPENSIPS + depends on ADK_PACKAGE_OPENSIPS help Logging support diff --git a/package/openssl/Config.in b/package/openssl/Config.in index 1375cc39a..172fa1355 100644 --- a/package/openssl/Config.in +++ b/package/openssl/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_OPENSSL tristate default n - depends ADK_PACKAGE_LIBOPENSSL + depends on ADK_PACKAGE_LIBOPENSSL config ADK_PACKAGE_LIBOPENSSL prompt "openssl........................... Open source SSL (Secure Socket Layer) libraries" @@ -23,7 +23,7 @@ config ADK_PACKAGE_OPENSSL_UTIL prompt "openssl-util.................... OpenSSL command line tool" tristate default n - depends ADK_PACKAGE_LIBOPENSSL + depends on ADK_PACKAGE_LIBOPENSSL help The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing @@ -38,4 +38,4 @@ config ADK_PACKAGE_CA_CERTS prompt "ca-certificates................... X.509 Root CA Certs of common CAs" tristate default n - depends ADK_COMPILE_OPENSSL + depends on ADK_COMPILE_OPENSSL diff --git a/package/openvpn/Config.in b/package/openvpn/Config.in index 18fd4f298..28d9696a2 100644 --- a/package/openvpn/Config.in +++ b/package/openvpn/Config.in @@ -15,19 +15,19 @@ config ADK_COMPILE_OPENVPN_WITH_SERVER prompt "server support.................. enable to use OpenVPN as server" bool default y - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN config ADK_COMPILE_OPENVPN_WITH_HTTP prompt "enable http proxy support....... allow tunneling through http-proxy" bool default y - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN config ADK_COMPILE_OPENVPN_WITH_OPENSSL prompt "enable openssl.................. encryption support" bool default y - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN select ADK_PACKAGE_LIBOPENSSL help if unsure say "y" you really want that! @@ -36,27 +36,27 @@ config ADK_COMPILE_OPENVPN_WITH_LZO prompt "enable lzo...................... Enable transparent compression" bool default y - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN select ADK_PACKAGE_LIBLZO config ADK_COMPILE_OPENVPN_WITH_PASSWORD_SAVE prompt "Enable password saving.......... allow to read passwords for PKCS12 from file" bool default y - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN config ADK_COMPILE_OPENVPN_WITH_SMALL prompt "Reduce executable size.......... disable OCC, usage message, and verb 4 parm list" bool default n - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN config ADK_PACKAGE_OPENVPN_EASY_RSA prompt "openvpn-easy-rsa................ simple shell scripts to manage a Certificate Authority" tristate default n select ADK_PACKAGE_OPENSSL_UTIL - depends ADK_PACKAGE_OPENVPN + depends on ADK_PACKAGE_OPENVPN help collection of shell scripts to manage a simple CA infrastructure diff --git a/package/osiris/Config.in b/package/osiris/Config.in index 84a16435a..b8bfe8210 100644 --- a/package/osiris/Config.in +++ b/package/osiris/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_OSIRIS tristate default n - depends ADK_PACKAGE_OSIRISD + depends on ADK_PACKAGE_OSIRISD config ADK_PACKAGE_OSIRISD prompt "osirisd........................... Host integrity monitoring system (scanning agent)" diff --git a/package/pcre/Config.in b/package/pcre/Config.in index 955cd3ca4..21a23884c 100644 --- a/package/pcre/Config.in +++ b/package/pcre/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_PCRE tristate default n - depends ADK_PACKAGE_LIBPCRE + depends on ADK_PACKAGE_LIBPCRE config ADK_PACKAGE_LIBPCRE prompt "libpcre........................... A Perl Compatible Regular Expression library" diff --git a/package/php/Config.in b/package/php/Config.in index 422ede8c2..57ab1f333 100644 --- a/package/php/Config.in +++ b/package/php/Config.in @@ -27,20 +27,20 @@ config ADK_PACKAGE_PHP_MOD_CURL prompt "php-mod-curl..................... cURL module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBCURL config ADK_PACKAGE_PHP_MOD_FTP prompt "php-mod-ftp...................... FTP module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP config ADK_PACKAGE_PHP_MOD_GD prompt "php-mod-gd....................... GD graphics library module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBGD select ADK_PACKAGE_LIBPNG @@ -48,69 +48,69 @@ config ADK_PACKAGE_PHP_MOD_GMP prompt "php-mod-gmp...................... GMP module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBGMP config ADK_PACKAGE_PHP_MOD_LDAP prompt "php-mod-ldap..................... LDAP module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBOPENLDAP config ADK_PACKAGE_PHP_MOD_MYSQL prompt "php-mod-mysql.................... MySQL module" tristate default n - depends ADK_CXX - depends ADK_COMPILE_PHP + depends on ADK_CXX + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBMYSQLCLIENT config ADK_PACKAGE_PHP_MOD_OPENSSL prompt "php-mod-openssl.................. OpenSSL module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBOPENSSL config ADK_PACKAGE_PHP_MOD_PCRE prompt "php-mod-pcre..................... PCRE module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBPCRE config ADK_PACKAGE_PHP_MOD_PGSQL prompt "php-mod-pgsql.................... PostgreSQL module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBPQ config ADK_PACKAGE_PHP_MOD_SESSION prompt "php-mod-session.................. Sessions module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP config ADK_PACKAGE_PHP_MOD_SQLITE prompt "php-mod-sqlite................... SQLite module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBSQLITE config ADK_PACKAGE_PHP_MOD_SOCKETS prompt "php-mod-sockets.................. Sockets module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP config ADK_PACKAGE_PHP_MOD_XML prompt "php-mod-xml...................... XML module" tristate default n - depends ADK_COMPILE_PHP + depends on ADK_COMPILE_PHP select ADK_PACKAGE_LIBEXPAT endmenu diff --git a/package/pmacct/Config.in b/package/pmacct/Config.in index ef1e85a41..fe3e4d99d 100644 --- a/package/pmacct/Config.in +++ b/package/pmacct/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_PMACCT tristate default n - depends ADK_PACKAGE_PMACCTD || ADK_PACKAGE_PMACCT_CLIENT || ADK_PACKAGE_SFACCTD || ADK_PACKAGE_NFACCTD + depends on ADK_PACKAGE_PMACCTD || ADK_PACKAGE_PMACCT_CLIENT || ADK_PACKAGE_SFACCTD || ADK_PACKAGE_NFACCTD config ADK_PACKAGE_PMACCTD prompt "pmacctd....................... IP accounting daemon (libpcap based)" diff --git a/package/popt/Config.in b/package/popt/Config.in index 554cd3b32..a16ba04d5 100644 --- a/package/popt/Config.in +++ b/package/popt/Config.in @@ -1,6 +1,6 @@ config ADK_COMPILE_POPT tristate - depends ADK_PACKAGE_LIBPOPT + depends on ADK_PACKAGE_LIBPOPT config ADK_PACKAGE_LIBPOPT prompt "libpopt........................... Command line option parsing library" diff --git a/package/postgresql/Config.in b/package/postgresql/Config.in index d1d0d09fe..d2e77a9c4 100644 --- a/package/postgresql/Config.in +++ b/package/postgresql/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_POSTGRESQL tristate default n - depends ADK_PACKAGE_LIBPQ + depends on ADK_PACKAGE_LIBPQ config ADK_PACKAGE_LIBPQ prompt "libpq............................. PostgreSQL client library" diff --git a/package/ppp/Config.in b/package/ppp/Config.in index 493c74e58..0969ae40a 100644 --- a/package/ppp/Config.in +++ b/package/ppp/Config.in @@ -10,38 +10,38 @@ config ADK_PACKAGE_PPP # tristate # default n # select ADK_KPACKAGE_KMOD_PPPOATM -# depends ADK_PACKAGE_PPP +# depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_PPPOE prompt "ppp-mod-pppoe................... PPPoE (PPP over Ethernet) plugin" tristate default n select ADK_KPACKAGE_KMOD_PPPOE - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_RADIUS prompt "ppp-mod-radius.................. RADIUS (Remote Authentication Dial-In User Service) plugin" tristate default n - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_CHAT prompt "chat............................ Utility to establish conversation with other PPP servers (via a modem)" tristate default n - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_PPPDUMP prompt "pppdump......................... Utility to read PPP record file" tristate default n - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_PPPSTATS prompt "pppstats........................ Utility to report PPP statistics" tristate default n - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP config ADK_PACKAGE_PPP_MOD_PPPUMTS prompt "GPRS/UMTS support............... Package with scripts and dependencies to run UMTS/GRPS" @@ -49,4 +49,4 @@ config ADK_PACKAGE_PPP_MOD_PPPUMTS default n select ADK_PACKAGE_COMGT select ADK_KPACKAGE_KMOD_USB_SERIAL - depends ADK_PACKAGE_PPP + depends on ADK_PACKAGE_PPP diff --git a/package/quagga/Config.in b/package/quagga/Config.in index 93ae9a2f4..331e38ca6 100644 --- a/package/quagga/Config.in +++ b/package/quagga/Config.in @@ -3,7 +3,7 @@ config ADK_PACKAGE_QUAGGA prompt "quagga............................ The Quagga Software Routing Suite" tristate - depends ADK_IPV6 + depends on ADK_IPV6 default n help A routing software package that provides TCP/IP based routing services @@ -16,7 +16,7 @@ config ADK_PACKAGE_QUAGGA_BGPD prompt " quagga-bgpd................... BGPv4, BGPv4+, BGPv4- routing engine" tristate default n - depends ADK_PACKAGE_QUAGGA + depends on ADK_PACKAGE_QUAGGA help A BGPv4, BGPv4+, BGPv4- routing engine for use with Quagga routing software. @@ -25,7 +25,7 @@ config ADK_PACKAGE_QUAGGA_OSPFD prompt " quagga-ospfd.................. OSPFv2 routing engine" tristate default n - depends ADK_PACKAGE_QUAGGA + depends on ADK_PACKAGE_QUAGGA help An OSPFv2 (IPv4) routing engine for use with Quagga routing software. @@ -33,8 +33,8 @@ config ADK_PACKAGE_QUAGGA_OSPF6D prompt " quagga-ospf6d................. OSPFv3 routing engine" tristate default n - depends ADK_PACKAGE_QUAGGA - depends ADK_IPV6 + depends on ADK_PACKAGE_QUAGGA + depends on ADK_IPV6 help An OSPFv3 (IPv6) routing engine for use with Quagga routing software. @@ -42,7 +42,7 @@ config ADK_PACKAGE_QUAGGA_RIPD prompt " quagga-ripd................... RIP routing engine" tristate default n - depends ADK_PACKAGE_QUAGGA + depends on ADK_PACKAGE_QUAGGA help A RIP (IPv4) routing engine for use with Quagga routing software. @@ -50,8 +50,8 @@ config ADK_PACKAGE_QUAGGA_RIPNGD prompt " quagga-ripngd................. RIPNG routing engine" tristate default n - depends ADK_PACKAGE_QUAGGA - depends ADK_IPV6 + depends on ADK_PACKAGE_QUAGGA + depends on ADK_IPV6 help A RIPNG (IPv6) routing engine for use with Quagga routing software. @@ -59,7 +59,7 @@ config ADK_PACKAGE_QUAGGA_VTYSH prompt " quagga-vtysh.................. integrated shell for Quagga routing software" tristate default n - depends ADK_PACKAGE_QUAGGA + depends on ADK_PACKAGE_QUAGGA select ADK_PACKAGE_LIBREADLINE select ADK_PACKAGE_LIBNCURSES help diff --git a/package/readline/Config.in b/package/readline/Config.in index aa126e21f..c46e6fe22 100644 --- a/package/readline/Config.in +++ b/package/readline/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_READLINE tristate default n - depends ADK_PACKAGE_LIBREADLINE + depends on ADK_PACKAGE_LIBREADLINE config ADK_PACKAGE_LIBREADLINE prompt "libreadline....................... Command lines edition library" diff --git a/package/rp-pppoe/Config.in b/package/rp-pppoe/Config.in index 439d582ee..6d27ecb4b 100644 --- a/package/rp-pppoe/Config.in +++ b/package/rp-pppoe/Config.in @@ -3,7 +3,7 @@ config ADK_COMPILE_RP_PPPOE tristate default n - depends ADK_PACKAGE_PPPOE_CLIENT || ADK_PACKAGE_PPPOE_RELAY || ADK_PACKAGE_PPPOE_SERVER || ADK_PACKAGE_PPPOE_SNIFF + depends on ADK_PACKAGE_PPPOE_CLIENT || ADK_PACKAGE_PPPOE_RELAY || ADK_PACKAGE_PPPOE_SERVER || ADK_PACKAGE_PPPOE_SNIFF config ADK_PACKAGE_PPPOE_CLIENT prompt "pppoe-client...................... PPPoE (PPP over Ethernet) client" diff --git a/package/rrdcollect/Config.in b/package/rrdcollect/Config.in index a6935c706..240cddc3b 100644 --- a/package/rrdcollect/Config.in +++ b/package/rrdcollect/Config.in @@ -2,7 +2,7 @@ config ADK_PACKAGE_RRDCOLLECT prompt " rrdcollect...................... Round-Robin Database (RRD) collecting daemon" tristate default n - depends ADK_PACKAGE_LIBRRD || ADK_PACKAGE_LIBRRD1 + depends on ADK_PACKAGE_LIBRRD || ADK_PACKAGE_LIBRRD1 help RRDcollect is a daemon which polls ceratin files in /proc/ directory, gathering data and storing it inside RRDtool's @@ -18,7 +18,7 @@ config ADK_PACKAGE_RRDCOLLECT_EXAMPLE prompt " rrdcollect-example.......... Example setup for RRD collecting daemon above" tristate default n - depends ADK_PACKAGE_RRDCOLLECT + depends on ADK_PACKAGE_RRDCOLLECT help RRDcollect is a daemon which polls ceratin files in /proc/ directory, gathering data and storing it inside RRDtool's diff --git a/package/rrs/Config.in b/package/rrs/Config.in index 6fe48d0fd..901492074 100644 --- a/package/rrs/Config.in +++ b/package/rrs/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_RRS tristate default n - depends ADK_PACKAGE_RRS || ADK_PACKAGE_RRS_NOSSL + depends on ADK_PACKAGE_RRS || ADK_PACKAGE_RRS_NOSSL config ADK_PACKAGE_RRS prompt "rrs............................... A reverse (connecting) remote shell, with SSL support" diff --git a/package/samba/Config.in b/package/samba/Config.in index f548a5e2b..b26d2791e 100644 --- a/package/samba/Config.in +++ b/package/samba/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_SAMBA tristate default n - depends ADK_PACKAGE_SAMBA || ADK_PACKAGE_SAMBA_CLIENT || ADK_PACKAGE_SMBFS + depends on ADK_PACKAGE_SAMBA || ADK_PACKAGE_SAMBA_CLIENT || ADK_PACKAGE_SMBFS config ADK_PACKAGE_SAMBA prompt "samba............................. NetBIOS/SMB file and print server" diff --git a/package/sane-backends/Config.in b/package/sane-backends/Config.in index dd0e2522f..de3c1ecd2 100644 --- a/package/sane-backends/Config.in +++ b/package/sane-backends/Config.in @@ -20,7 +20,7 @@ config ADK_PACKAGE_SANE_BACKEND_ABATON prompt "sane-backend-abaton............. Scanner Access Now Easy (ABATON)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -31,7 +31,7 @@ config ADK_PACKAGE_SANE_BACKEND_AGFAFOCUS prompt "sane-backend-agfafocus.......... Scanner Access Now Easy (AGFAFOCUS)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -42,7 +42,7 @@ config ADK_PACKAGE_SANE_BACKEND_APPLE prompt "sane-backend-apple.............. Scanner Access Now Easy (APPLE)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -53,7 +53,7 @@ config ADK_PACKAGE_SANE_BACKEND_ARTEC_EPLUS48U prompt "sane-backend-artec-eplus48u..... Scanner Access Now Easy (ARTEC_EPLUS48U)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -64,7 +64,7 @@ config ADK_PACKAGE_SANE_BACKEND_ARTEC prompt "sane-backend-artec.............. Scanner Access Now Easy (ARTEC)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -75,7 +75,7 @@ config ADK_PACKAGE_SANE_BACKEND_AS6E prompt "sane-backend-as6e............... Scanner Access Now Easy (AS6E)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -86,7 +86,7 @@ config ADK_PACKAGE_SANE_BACKEND_AVISION prompt "sane-backend-avision............ Scanner Access Now Easy (AVISION)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -97,7 +97,7 @@ config ADK_PACKAGE_SANE_BACKEND_BH prompt "sane-backend-bh................. Scanner Access Now Easy (BH)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -108,7 +108,7 @@ config ADK_PACKAGE_SANE_BACKEND_CANON630U prompt "sane-backend-canon630u.......... Scanner Access Now Easy (CANON630U)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -119,7 +119,7 @@ config ADK_PACKAGE_SANE_BACKEND_CANON prompt "sane-backend-canon.............. Scanner Access Now Easy (CANON)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -130,7 +130,7 @@ config ADK_PACKAGE_SANE_BACKEND_COOLSCAN2 prompt "sane-backend-coolscan2.......... Scanner Access Now Easy (COOLSCAN2)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -141,7 +141,7 @@ config ADK_PACKAGE_SANE_BACKEND_COOLSCAN prompt "sane-backend-coolscan........... Scanner Access Now Easy (COOLSCAN)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -152,7 +152,7 @@ config ADK_PACKAGE_SANE_BACKEND_DC25 prompt "sane-backend-dc25............... Scanner Access Now Easy (DC25)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -163,7 +163,7 @@ config ADK_PACKAGE_SANE_BACKEND_DMC prompt "sane-backend-dmc................ Scanner Access Now Easy (DMC)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -174,7 +174,7 @@ config ADK_PACKAGE_SANE_BACKEND_EPSON prompt "sane-backend-epson.............. Scanner Access Now Easy (EPSON)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -185,7 +185,7 @@ config ADK_PACKAGE_SANE_BACKEND_FUJITSU prompt "sane-backend-fujitsu............ Scanner Access Now Easy (FUJITSU)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -196,7 +196,7 @@ config ADK_PACKAGE_SANE_BACKEND_GENESYS prompt "sane-backend-genesys............ Scanner Access Now Easy (GENESYS)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -207,7 +207,7 @@ config ADK_PACKAGE_SANE_BACKEND_GT68XX prompt "sane-backend-gt68xx............. Scanner Access Now Easy (GT68XX)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -218,7 +218,7 @@ config ADK_PACKAGE_SANE_BACKEND_HP3500 prompt "sane-backend-hp3500............. Scanner Access Now Easy (HP3500)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -229,7 +229,7 @@ config ADK_PACKAGE_SANE_BACKEND_HP4200 prompt "sane-backend-hp4200............. Scanner Access Now Easy (HP4200)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -240,7 +240,7 @@ config ADK_PACKAGE_SANE_BACKEND_HP5400 prompt "sane-backend-hp5400............. Scanner Access Now Easy (HP5400)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -251,7 +251,7 @@ config ADK_PACKAGE_SANE_BACKEND_HP prompt "sane-backend-hp................. Scanner Access Now Easy (HP)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -262,7 +262,7 @@ config ADK_PACKAGE_SANE_BACKEND_IBM prompt "sane-backend-ibm................ Scanner Access Now Easy (IBM)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -273,7 +273,7 @@ config ADK_PACKAGE_SANE_BACKEND_LEO prompt "sane-backend-leo................ Scanner Access Now Easy (LEO)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -284,7 +284,7 @@ config ADK_PACKAGE_SANE_BACKEND_LEXMARK prompt "sane-backend-lexmark............ Scanner Access Now Easy (LEXMARK)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -295,7 +295,7 @@ config ADK_PACKAGE_SANE_BACKEND_MA1509 prompt "sane-backend-ma1509............. Scanner Access Now Easy (MA1509)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -306,7 +306,7 @@ config ADK_PACKAGE_SANE_BACKEND_MATSUSHITA prompt "sane-backend-matsushita......... Scanner Access Now Easy (MATSUSHITA)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -317,7 +317,7 @@ config ADK_PACKAGE_SANE_BACKEND_MICROTEK2 prompt "sane-backend-microtek2.......... Scanner Access Now Easy (MICROTEK2)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -328,7 +328,7 @@ config ADK_PACKAGE_SANE_BACKEND_MICROTEK prompt "sane-backend-microtek........... Scanner Access Now Easy (MICROTEK)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -339,7 +339,7 @@ config ADK_PACKAGE_SANE_BACKEND_MUSTEK prompt "sane-backend-mustek............. Scanner Access Now Easy (MUSTEK)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -350,7 +350,7 @@ config ADK_PACKAGE_SANE_BACKEND_MUSTEK_USB2 prompt "sane-backend-mustek-usb2........ Scanner Access Now Easy (MUSTEK_USB2)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -361,7 +361,7 @@ config ADK_PACKAGE_SANE_BACKEND_MUSTEK_USB prompt "sane-backend-mustek-usb......... Scanner Access Now Easy (MUSTEK_USB)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -372,7 +372,7 @@ config ADK_PACKAGE_SANE_BACKEND_NEC prompt "sane-backend-nec................ Scanner Access Now Easy (NEC)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -383,7 +383,7 @@ config ADK_PACKAGE_SANE_BACKEND_NIASH prompt "sane-backend-niash.............. Scanner Access Now Easy (NIASH)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -394,7 +394,7 @@ config ADK_PACKAGE_SANE_BACKEND_PIE prompt "sane-backend-pie................ Scanner Access Now Easy (PIE)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -405,7 +405,7 @@ config ADK_PACKAGE_SANE_BACKEND_PIXMA prompt "sane-backend-pixma.............. Scanner Access Now Easy (PIXMA)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -416,7 +416,7 @@ config ADK_PACKAGE_SANE_BACKEND_PLUSTEK_PP prompt "sane-backend-plustek-pp......... Scanner Access Now Easy (PLUSTEK_PP)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -426,7 +426,7 @@ config ADK_PACKAGE_SANE_BACKEND_PLUSTEK prompt "sane-backend-plustek............ Scanner Access Now Easy (PLUSTEK)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -437,7 +437,7 @@ config ADK_PACKAGE_SANE_BACKEND_QCAM prompt "sane-backend-qcam............... Scanner Access Now Easy (QCAM)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -448,7 +448,7 @@ config ADK_PACKAGE_SANE_BACKEND_RICOH prompt "sane-backend-ricoh.............. Scanner Access Now Easy (RICOH)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -459,7 +459,7 @@ config ADK_PACKAGE_SANE_BACKEND_S9036 prompt "sane-backend-s9036.............. Scanner Access Now Easy (S9036)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -470,7 +470,7 @@ config ADK_PACKAGE_SANE_BACKEND_SCEPTRE prompt "sane-backend-sceptre............ Scanner Access Now Easy (SCEPTRE)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -481,7 +481,7 @@ config ADK_PACKAGE_SANE_BACKEND_SHARP prompt "sane-backend-sharp.............. Scanner Access Now Easy (SHARP)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -492,7 +492,7 @@ config ADK_PACKAGE_SANE_BACKEND_SM3600 prompt "sane-backend-sm3600............. Scanner Access Now Easy (SM3600)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -503,7 +503,7 @@ config ADK_PACKAGE_SANE_BACKEND_SM3840 prompt "sane-backend-sm3840............. Scanner Access Now Easy (SM3840)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -514,7 +514,7 @@ config ADK_PACKAGE_SANE_BACKEND_SNAPSCAN prompt "sane-backend-snapscan........... Scanner Access Now Easy (SNAPSCAN)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -525,7 +525,7 @@ config ADK_PACKAGE_SANE_BACKEND_SP15C prompt "sane-backend-sp15c.............. Scanner Access Now Easy (SP15C)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -536,7 +536,7 @@ config ADK_PACKAGE_SANE_BACKEND_ST400 prompt "sane-backend-st400.............. Scanner Access Now Easy (ST400)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -547,7 +547,7 @@ config ADK_PACKAGE_SANE_BACKEND_STV680 prompt "sane-backend-stv680............. Scanner Access Now Easy (STV680)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -558,7 +558,7 @@ config ADK_PACKAGE_SANE_BACKEND_TAMARACK prompt "sane-backend-tamarack........... Scanner Access Now Easy (TAMARACK)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -569,7 +569,7 @@ config ADK_PACKAGE_SANE_BACKEND_TECO1 prompt "sane-backend-teco1.............. Scanner Access Now Easy (TECO1)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -580,7 +580,7 @@ config ADK_PACKAGE_SANE_BACKEND_TECO2 prompt "sane-backend-teco2.............. Scanner Access Now Easy (TECO2)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -591,7 +591,7 @@ config ADK_PACKAGE_SANE_BACKEND_TECO3 prompt "sane-backend-teco3.............. Scanner Access Now Easy (TECO3)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -602,7 +602,7 @@ config ADK_PACKAGE_SANE_BACKEND_TEST prompt "sane-backend-test............... Scanner Access Now Easy (TEST)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -613,7 +613,7 @@ config ADK_PACKAGE_SANE_BACKEND_U12 prompt "sane-backend-u12................ Scanner Access Now Easy (U12)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -624,7 +624,7 @@ config ADK_PACKAGE_SANE_BACKEND_UMAX1220U prompt "sane-backend-umax1220u.......... Scanner Access Now Easy (UMAX1220U)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -635,7 +635,7 @@ config ADK_PACKAGE_SANE_BACKEND_UMAX_PP prompt "sane-backend-umax-pp............ Scanner Access Now Easy (UMAX_PP)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS help SANE (Scanner Access Now Easy) is a universal scanner interface. @@ -645,7 +645,7 @@ config ADK_PACKAGE_SANE_BACKEND_UMAX prompt "sane-backend-umax............... Scanner Access Now Easy (UMAX)" tristate default n - depends ADK_PACKAGE_SANE_BACKENDS + depends on ADK_PACKAGE_SANE_BACKENDS select ADK_PACKAGE_LIBUSB help SANE (Scanner Access Now Easy) is a universal scanner interface. diff --git a/package/shorewall-common/Config.in b/package/shorewall-common/Config.in index d45386d64..59296e1fe 100644 --- a/package/shorewall-common/Config.in +++ b/package/shorewall-common/Config.in @@ -17,7 +17,7 @@ config ADK_PACKAGE_SHOREWALL_STRIPCONF prompt "Strip shorewall configuration files" bool default n - depends ADK_PACKAGE_SHOREWALL + depends on ADK_PACKAGE_SHOREWALL help To save space, all shorewall files in /etc/shorewall will get striped. This means that all comments, empty lines etc. are removed. @@ -29,7 +29,7 @@ config ADK_PACKAGE_SHOREWALL_STRIPSHARED prompt "Strip shared shorewall files (macros & actions mainly)" bool default y - depends ADK_PACKAGE_SHOREWALL + depends on ADK_PACKAGE_SHOREWALL help To save space, all shared shorewall files in /usr/share/shorewall will get striped. This means that all comments, empty lines etc. diff --git a/package/shorewall-shell/Config.in b/package/shorewall-shell/Config.in index 76270351b..03f119786 100644 --- a/package/shorewall-shell/Config.in +++ b/package/shorewall-shell/Config.in @@ -1,7 +1,7 @@ config ADK_PACKAGE_SHOREWALL_SHELL prompt "shorewall-shell................. shorewall shell compiler" tristate - depends ADK_PACKAGE_SHOREWALL + depends on ADK_PACKAGE_SHOREWALL default y help http://www.shorewall.net/ diff --git a/package/speex/Config.in b/package/speex/Config.in index f9cfe97ba..6fa3d9995 100644 --- a/package/speex/Config.in +++ b/package/speex/Config.in @@ -1,8 +1,8 @@ config ADK_COMPILE_SPEEX tristate default n - depends ADK_CXX - depends ADK_PACKAGE_LIBSPEEX + depends on ADK_CXX + depends on ADK_PACKAGE_LIBSPEEX config ADK_PACKAGE_LIBSPEEX prompt "libspeex.......................... Open source patent-free speech compression codec" diff --git a/package/sqlite/Config.in b/package/sqlite/Config.in index b534356b6..870f02c82 100644 --- a/package/sqlite/Config.in +++ b/package/sqlite/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_SQLITE tristate default n - depends ADK_PACKAGE_LIBSQLITE + depends on ADK_PACKAGE_LIBSQLITE config ADK_PACKAGE_LIBSQLITE prompt "libsqlite......................... Self-contained, embeddable, zero-configuration SQL database engine" @@ -42,7 +42,7 @@ config ADK_PACKAGE_SQLITE_CLI prompt "sqlite-cli...................... Command line interface for SQLite" tristate default n - depends ADK_PACKAGE_LIBSQLITE + depends on ADK_PACKAGE_LIBSQLITE help SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine. Features include: diff --git a/package/squid/Config.in b/package/squid/Config.in index bdace2a49..29e4e7489 100644 --- a/package/squid/Config.in +++ b/package/squid/Config.in @@ -3,7 +3,7 @@ config ADK_PACKAGE_SQUID prompt "squid............................. full-featured Web proxy cache" tristate default n - depends ADK_CXX + depends on ADK_CXX select ADK_PACKAGE_LIBOPENSSL help Squid is a high-performance proxy caching server for web clients, @@ -18,56 +18,56 @@ menu "squid............................. proxy and web cache modules" config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_GETPWNAM prompt " squid-mod-basic-auth-getpwnam....... getpwnam basic authentication helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Password basic authentication helper config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_NCSA prompt " squid-mod-basic-auth-ncsa........... NCSA basic authentication helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help NCSA basic authentication helper config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_SMB prompt " squid-mod-basic-auth-smb............ Samba basic authentication helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Samba basic authentication helper config ADK_PACKAGE_SQUID_MOD_DIGEST_AUTH_PASSWORD prompt " squid-mod-digest-auth-password...... Password digest authentication ehlper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Password digest authentication helper config ADK_PACKAGE_SQUID_MOD_EXTERNAL_ACL_IP_USER prompt " squid-mod-external-acl-ip_user...... IP user external ACL helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help IP user external ACL helper config ADK_PACKAGE_SQUID_MOD_EXTERNAL_ACL_UNIX_GROUP prompt " squid-mod-external-acl-unix-group... Unix group external ACL helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Unix group external ACL helper config ADK_PACKAGE_SQUID_MOD_NTLM_AUTH_FAKEAUTH prompt " squid-mod-ntlm-auth-fakeauth........ Fakeauth NTLM authentication helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Fakeauth NTLM authentication helper config ADK_PACKAGE_SQUID_MOD_NTLM_AUTH_SMB_AUTH prompt " squid-mod-ntlm-auth-smb-auth........ Samba NTLM authentication helper" tristate - depends ADK_PACKAGE_SQUID + depends on ADK_PACKAGE_SQUID help Samba NTLM authentication helper diff --git a/package/subversion/Config.in b/package/subversion/Config.in index 4ab4537dc..b8e07d595 100644 --- a/package/subversion/Config.in +++ b/package/subversion/Config.in @@ -15,7 +15,7 @@ config ADK_PACKAGE_SUBVERSION_NEON prompt " Enable interaction with remote repositories over WebDAV" bool default n - depends ADK_PACKAGE_SUBVERSION + depends on ADK_PACKAGE_SUBVERSION select ADK_PACKAGE_NEON help Allows a Subversion client to interact with remote diff --git a/package/tcp_wrappers/Config.in b/package/tcp_wrappers/Config.in index 7da5381fb..0066cad78 100644 --- a/package/tcp_wrappers/Config.in +++ b/package/tcp_wrappers/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_TCP_WRAPPERS bool default n - depends ADK_PACKAGE_LIBWRAP + depends on ADK_PACKAGE_LIBWRAP config ADK_PACKAGE_LIBWRAP prompt "libwrap........................... Security wrapper library for TCP services" diff --git a/package/tinyproxy/Config.in b/package/tinyproxy/Config.in index c7182965b..fd3a449f1 100644 --- a/package/tinyproxy/Config.in +++ b/package/tinyproxy/Config.in @@ -13,18 +13,18 @@ config ADK_COMPILE_TINYPROXY_WITH_TRANSPARENT_PROXY prompt " Enable transparent proxying" bool default y - depends ADK_PACKAGE_TINYPROXY + depends on ADK_PACKAGE_TINYPROXY config ADK_COMPILE_TINYPROXY_WITH_FILTER prompt " Enable filtering support" bool default y - depends ADK_PACKAGE_TINYPROXY + depends on ADK_PACKAGE_TINYPROXY config ADK_COMPILE_TINYPROXY_WITH_UPSTREAM prompt " Enable upstream support" bool default y - depends ADK_PACKAGE_TINYPROXY + depends on ADK_PACKAGE_TINYPROXY #endmenu diff --git a/package/tntnet/Config.in b/package/tntnet/Config.in index 9abab9b82..0d4391674 100644 --- a/package/tntnet/Config.in +++ b/package/tntnet/Config.in @@ -24,13 +24,13 @@ config ADK_COMPILE_TNTNET_WITHOUT_OPENSSL config ADK_COMPILE_TNTNET_WITH_OPENSSL bool "enable openssl encryption support" - depends ADK_PACKAGE_TNTNET + depends on ADK_PACKAGE_TNTNET select ADK_PACKAGE_LIBOPENSSL help config ADK_COMPILE_TNTNET_WITH_GNUTLS bool "enable gnutls encryption support" - depends ADK_PACKAGE_TNTNET + depends on ADK_PACKAGE_TNTNET select ADK_PACKAGE_LIBGNUTLS help diff --git a/package/ulogd/Config.in b/package/ulogd/Config.in index e725f2807..20a276bee 100644 --- a/package/ulogd/Config.in +++ b/package/ulogd/Config.in @@ -15,34 +15,34 @@ config ADK_PACKAGE_ULOGD_MOD_MYSQL tristate default n depends on ADK_CXX - depends ADK_PACKAGE_ULOGD + depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBMYSQLCLIENT config ADK_PACKAGE_ULOGD_MOD_PCAP prompt " ulogd-mod-pcap................. Output plugin for logging into pcap format" tristate default n - depends ADK_PACKAGE_ULOGD + depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBPCAP config ADK_PACKAGE_ULOGD_MOD_PGSQL prompt " ulogd-mod-pgsql............... Output plugin for logging into a PostgreSQL database" tristate default n - depends ADK_PACKAGE_ULOGD + depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBPQ config ADK_PACKAGE_ULOGD_MOD_SQLITE prompt " ulogd-mod-sqlite.............. Output plugin for logging into an SQLite database" tristate default n - depends ADK_PACKAGE_ULOGD + depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBSQLITE config ADK_PACKAGE_ULOGD_MOD_EXTRA prompt " ulogd-mod-extra............... All other plugins" tristate default n - depends ADK_PACKAGE_ULOGD + depends on ADK_PACKAGE_ULOGD #endmenu diff --git a/package/updatedd/Config.in b/package/updatedd/Config.in index 763961614..08e800d59 100644 --- a/package/updatedd/Config.in +++ b/package/updatedd/Config.in @@ -14,54 +14,54 @@ config ADK_PACKAGE_UPDATEDD config ADK_PACKAGE_UPDATEDD_MOD_CHANGEIP prompt "updatedd-mod-changeip........... changeip.com" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_DYNDNS prompt "updatedd-mod-dyndns............. dyndns.org" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_EURODYNDNS prompt "updatedd-mod-eurodyndns......... eurodyndns.org" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_HN prompt "updatedd-mod-hn................. hn.org" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_NOIP prompt "updatedd-mod-noip............... no-ip.com" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_ODS prompt "updatedd-mod-ods................ ods.org" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_OVH prompt "updatedd-mod-ovh................ ovh.com" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_REGFISH prompt "updatedd-mod-regfish............ regfish.com" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n config ADK_PACKAGE_UPDATEDD_MOD_TZO prompt "updatedd-mod-tzo................ tzo.com" tristate - depends ADK_PACKAGE_UPDATEDD + depends on ADK_PACKAGE_UPDATEDD default n diff --git a/package/usbutils/Config.in b/package/usbutils/Config.in index e73eb1008..8b80238ea 100644 --- a/package/usbutils/Config.in +++ b/package/usbutils/Config.in @@ -1,6 +1,6 @@ config ADK_COMPILE_USBUTILS tristate - depends ADK_PACKAGE_LSUSB + depends on ADK_PACKAGE_LSUSB config ADK_PACKAGE_LSUSB prompt "lsusb............................. USB devices listing program" diff --git a/package/util-linux-ng/Config.in b/package/util-linux-ng/Config.in index 705c3cbff..8c39f0a55 100644 --- a/package/util-linux-ng/Config.in +++ b/package/util-linux-ng/Config.in @@ -1,7 +1,7 @@ config ADK_COMPILE_UTIL_LINUX_NG tristate default n - depends ADK_PACKAGE_FDISK || ADK_PACKAGE_SWAP_UTILS + depends on ADK_PACKAGE_FDISK || ADK_PACKAGE_SWAP_UTILS config ADK_PACKAGE_FDISK prompt "fdisk............................. Partition table manipulation utility" diff --git a/package/weechat/Config.in b/package/weechat/Config.in index 0945c9dc9..4073c3979 100644 --- a/package/weechat/Config.in +++ b/package/weechat/Config.in @@ -15,12 +15,12 @@ config ADK_COMPILE_WEECHAT_WITH_TLS prompt " Enable TLS support" bool select ADK_PACKAGE_LIBGNUTLS - depends ADK_PACKAGE_WEECHAT + depends on ADK_PACKAGE_WEECHAT config ADK_COMPILE_WEECHAT_WITH_LUA prompt " Enable LUA scripting" bool select ADK_PACKAGE_LIBLUA - depends ADK_PACKAGE_WEECHAT + depends on ADK_PACKAGE_WEECHAT #endmenu diff --git a/package/wpa_supplicant/Config.in b/package/wpa_supplicant/Config.in index 325b71bf1..b0044856a 100644 --- a/package/wpa_supplicant/Config.in +++ b/package/wpa_supplicant/Config.in @@ -18,13 +18,13 @@ default ADK_COMPILE_WPA_SUPPLICANT_WITH_OPENSSL config ADK_COMPILE_WPA_SUPPLICANT_WITH_OPENSSL bool "enable openssl encryption support" - depends ADK_PACKAGE_WPA_SUPPLICANT + depends on ADK_PACKAGE_WPA_SUPPLICANT select ADK_PACKAGE_LIBOPENSSL help config ADK_COMPILE_WPA_SUPPLICANT_WITH_INCLUDED bool "enable included encryption support" - depends ADK_PACKAGE_WPA_SUPPLICANT + depends on ADK_PACKAGE_WPA_SUPPLICANT help endchoice diff --git a/target/Config.in b/target/Config.in index b2c29d0d0..aa5814df1 100644 --- a/target/Config.in +++ b/target/Config.in @@ -310,7 +310,7 @@ source "target/linux/config/Config.in.kernel" choice prompt "Target C library" -depends ! ADK_NATIVE +depends on ! ADK_NATIVE config ADK_TARGET_LIB_UCLIBC bool "uClibc embedded C library" help diff --git a/target/linux/config/Config.in.block b/target/linux/config/Config.in.block index 1c9f0aa49..5ceacf608 100644 --- a/target/linux/config/Config.in.block +++ b/target/linux/config/Config.in.block @@ -157,8 +157,8 @@ config ADK_KPACKAGE_KMOD_SCSI config ADK_KPACKAGE_KMOD_BLK_DEV_SD prompt "kmod-scsi-disk.................... SCSI disk support" - depends !ADK_KERNEL_SCSI - depends ADK_KPACKAGE_KMOD_SCSI + depends on !ADK_KERNEL_SCSI + depends on ADK_KPACKAGE_KMOD_SCSI tristate help If you want to use SCSI hard disks, Fibre Channel disks, @@ -170,8 +170,8 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_SD config ADK_KPACKAGE_KMOD_BLK_DEV_SR prompt "kmod-scsi-cdrom................... SCSI CDROM support" - depends !ADK_KERNEL_SCSI - depends ADK_KPACKAGE_KMOD_SCSI + depends on !ADK_KERNEL_SCSI + depends on ADK_KPACKAGE_KMOD_SCSI tristate help If you want to use a SCSI or FireWire CD-ROM under Linux, @@ -188,19 +188,19 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_MD config ADK_KPACKAGE_KMOD_MD_RAID0 prompt "kmod-md-raid0..................... RAID0 support" tristate - depends ADK_KPACKAGE_KMOD_BLK_DEV_MD + depends on ADK_KPACKAGE_KMOD_BLK_DEV_MD help config ADK_KPACKAGE_KMOD_MD_RAID1 prompt "kmod-md-raid1..................... RAID1 support" tristate - depends ADK_KPACKAGE_KMOD_BLK_DEV_MD + depends on ADK_KPACKAGE_KMOD_BLK_DEV_MD help config ADK_KPACKAGE_KMOD_MD_RAID456 prompt "kmod-md-raid456................... RAID456 support" tristate - depends ADK_KPACKAGE_KMOD_BLK_DEV_MD + depends on ADK_KPACKAGE_KMOD_BLK_DEV_MD help config ADK_KPACKAGE_KMOD_BLK_DEV_DM diff --git a/target/linux/config/Config.in.bluetooth b/target/linux/config/Config.in.bluetooth index 7d868ace5..7342a0f52 100644 --- a/target/linux/config/Config.in.bluetooth +++ b/target/linux/config/Config.in.bluetooth @@ -25,7 +25,7 @@ config ADK_KPACKAGE_KMOD_BT_L2CAP prompt "kmod-bluetooth-l2cap.............. L2CAP protocol support" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help L2CAP (Logical Link Control and Adaptation Protocol) provides connection oriented and connection-less data transport. L2CAP @@ -36,7 +36,7 @@ config ADK_KPACKAGE_KMOD_BT_SCO prompt "kmod-bluetooth-sco................ SCO links support" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help SCO link provides voice transport over Bluetooth. SCO support is required for voice applications like Headset and Audio. @@ -45,8 +45,8 @@ config ADK_KPACKAGE_KMOD_BT_RFCOMM prompt "kmod-bluetooth-rfcomm............. RFCOMM protocol support" tristate default n - depends ADK_KPACKAGE_KMOD_BT - depends ADK_KPACKAGE_KMOD_BT_L2CAP + depends on ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT_L2CAP help RFCOMM provides connection oriented stream transport. RFCOMM support is required for Dialup Networking, OBEX and other Bluetooth @@ -56,8 +56,8 @@ config ADK_KPACKAGE_KMOD_BT_BNEP prompt "kmod-bluetooth-bnep............... BNEP protocol support" tristate default n - depends ADK_KPACKAGE_KMOD_BT - depends ADK_KPACKAGE_KMOD_BT_L2CAP + depends on ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT_L2CAP help BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet emulation layer on top of Bluetooth. BNEP is required for @@ -68,8 +68,8 @@ config ADK_KPACKAGE_KMOD_BT_HIDP tristate default n select ADK_KERNEL_HID - depends ADK_KPACKAGE_KMOD_BT - depends ADK_KPACKAGE_KMOD_BT_L2CAP + depends on ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT_L2CAP help HIDP (Human Interface Device Protocol) is a transport layer for HID reports. HIDP is required for the Bluetooth Human @@ -79,7 +79,7 @@ config ADK_KPACKAGE_KMOD_BT_HCIBTUSB prompt "kmod-bluetooth-hci-usb............ HCI USB driver" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with @@ -89,7 +89,7 @@ config ADK_KPACKAGE_KMOD_BT_HCIUART prompt "kmod-bluetooth-hci-uart........... HCI UART driver" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with @@ -101,7 +101,7 @@ config ADK_KPACKAGE_KMOD_BT_HCIBCM203X prompt "kmod-bluetooth-hci-bcm203x........ HCI BCM203x USB driver" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help Bluetooth HCI BCM203x USB driver. This driver provides the firmware loading mechanism for the Broadcom @@ -111,7 +111,7 @@ config ADK_KPACKAGE_KMOD_BT_HCIBPA10X prompt "kmod-bluetooth-hci-bpa10x......... HCI BPA10x USB driver" tristate default n - depends ADK_KPACKAGE_KMOD_BT + depends on ADK_KPACKAGE_KMOD_BT help Bluetooth HCI BPA10x USB driver. This driver provides support for the Digianswer BPA 100/105 Bluetooth diff --git a/target/linux/config/Config.in.fs b/target/linux/config/Config.in.fs index 020025f95..5b96e96ce 100644 --- a/target/linux/config/Config.in.fs +++ b/target/linux/config/Config.in.fs @@ -21,8 +21,8 @@ config ADK_KPACKAGE_KMOD_EXT2_FS prompt "kmod-fs-ext2...................... EXT2 filesystem support" tristate default n - depends !ADK_TARGET_ROOTFS_EXT2_CF - depends !ADK_KERNEL_EXT2_FS + depends on !ADK_TARGET_ROOTFS_EXT2_CF + depends on !ADK_KERNEL_EXT2_FS help Ext2 is a standard Linux file system for hard disks. diff --git a/target/linux/config/Config.in.fsnet b/target/linux/config/Config.in.fsnet index 3cb37e52f..78c21d52c 100644 --- a/target/linux/config/Config.in.fsnet +++ b/target/linux/config/Config.in.fsnet @@ -94,7 +94,7 @@ config ADK_KPACKAGE_KMOD_NFSD default n select ADK_KPACKAGE_KMOD_EXPORTFS select ADK_KERNEL_NFSD_V3 - depends ADK_KPACKAGE_KMOD_NFS_FS + depends on ADK_KPACKAGE_KMOD_NFS_FS help If you want your Linux box to act as an NFS *server*, so that other computers on your local network which support NFS can access certain diff --git a/target/linux/config/Config.in.ipvs b/target/linux/config/Config.in.ipvs index cec68d6cf..1a5fbd063 100644 --- a/target/linux/config/Config.in.ipvs +++ b/target/linux/config/Config.in.ipvs @@ -10,10 +10,10 @@ config ADK_KERNEL_IP_VS_DEBUG prompt "enable debugging support" boolean default n - depends ADK_KPACKAGE_KMOD_IP_VS + depends on ADK_KPACKAGE_KMOD_IP_VS menu "IPVS transport protocol load balancing support" - depends ADK_KPACKAGE_KMOD_IP_VS + depends on ADK_KPACKAGE_KMOD_IP_VS config ADK_KERNEL_IP_VS_PROTO_TCP prompt "TCP load balancing support" @@ -50,7 +50,7 @@ config ADK_KERNEL_IP_VS_PROTO_AH endmenu menu "IPVS Scheduler" - depends ADK_KPACKAGE_KMOD_IP_VS + depends on ADK_KPACKAGE_KMOD_IP_VS config ADK_KPACKAGE_KMOD_IP_VS_RR prompt "kmod-ip-vs-rr......................... round-robin" @@ -105,7 +105,7 @@ config ADK_KPACKAGE_KMOD_IP_VS_NQ endmenu menu "IPVS application helper" - depends ADK_KPACKAGE_KMOD_IP_VS + depends on ADK_KPACKAGE_KMOD_IP_VS config ADK_KPACKAGE_KMOD_IP_VS_FTP prompt "kmod-ip-vs-ftp........................ FTP protocol" diff --git a/target/linux/config/Config.in.lib b/target/linux/config/Config.in.lib index e7b223c43..0f8847010 100644 --- a/target/linux/config/Config.in.lib +++ b/target/linux/config/Config.in.lib @@ -17,7 +17,7 @@ config ADK_KPACKAGE_KMOD_CRC_ITU_T config ADK_KPACKAGE_KMOD_CRC32 prompt "kmod-crc32.......................... provide CRC32 library functions" tristate - depends ! ADK_KERNEL_CRC32 + depends on ! ADK_KERNEL_CRC32 default n help diff --git a/target/linux/config/Config.in.multimedia b/target/linux/config/Config.in.multimedia index 88ee9e00c..d485d31ec 100644 --- a/target/linux/config/Config.in.multimedia +++ b/target/linux/config/Config.in.multimedia @@ -39,7 +39,7 @@ config ADK_KPACKAGE_KMOD_SND config ADK_KPACKAGE_KMOD_SND_OSSEMUL prompt "kmod-sound-alsa-oss-emul........ ALSA OSS Emulation" - depends ADK_KPACKAGE_KMOD_SND + depends on ADK_KPACKAGE_KMOD_SND select ADK_KERNEL_SND_MIXER_OSS select ADK_KERNEL_SND_PCM_OSS tristate @@ -49,7 +49,7 @@ config ADK_KPACKAGE_KMOD_SND_OSSEMUL config ADK_KPACKAGE_KMOD_SND_AC97_CODEC prompt "kmod-sound-alsa-ac97-codec..... ALSA AC97 codec" - depends ADK_KPACKAGE_KMOD_SND + depends on ADK_KPACKAGE_KMOD_SND tristate default n help @@ -57,7 +57,7 @@ config ADK_KPACKAGE_KMOD_SND_AC97_CODEC config ADK_KPACKAGE_KMOD_SND_VIA82XX prompt "kmod-sound-alsa-via82xx........ ALSA VIA82XX driver" - depends ADK_KPACKAGE_KMOD_SND + depends on ADK_KPACKAGE_KMOD_SND select ADK_KPACKAGE_KMOD_SND_AC97_CODEC tristate default n @@ -66,7 +66,7 @@ config ADK_KPACKAGE_KMOD_SND_VIA82XX config ADK_KPACKAGE_KMOD_SND_CS5535AUDIO prompt "kmod-sound-alsa-cs5535......... ALSA AMD CS5535 driver (ALIX1C)" - depends ADK_KPACKAGE_KMOD_SND + depends on ADK_KPACKAGE_KMOD_SND select ADK_KPACKAGE_KMOD_SND_AC97_CODEC depends on ADK_LINUX_X86_ALIX1C tristate @@ -97,7 +97,7 @@ config ADK_KPACKAGE_KMOD_VIDEO_V4L1 prompt "................................ Enable Video For Linux API 1 (DEPRECATED)" boolean default n - depends ADK_KPACKAGE_KMOD_VIDEO_DEV + depends on ADK_KPACKAGE_KMOD_VIDEO_DEV help Enables a compatibility API used by most V4L2 devices to allow its usage with legacy applications that supports only V4L1 api. @@ -105,7 +105,7 @@ config ADK_KPACKAGE_KMOD_VIDEO_V4L1 config ADK_KPACKAGE_KMOD_USB_PWC prompt "kmod-usb-pwc.................... Kernel driver for USB Philips Cameras" tristate - depends ADK_KPACKAGE_KMOD_USB + depends on ADK_KPACKAGE_KMOD_USB default n help diff --git a/target/linux/config/Config.in.netfilter b/target/linux/config/Config.in.netfilter index 48db426ef..a4dc9b7c7 100644 --- a/target/linux/config/Config.in.netfilter +++ b/target/linux/config/Config.in.netfilter @@ -199,7 +199,7 @@ config ADK_KPACKAGE_KMOD_NF_CONNTRACK_IPV4 config ADK_KPACKAGE_KMOD_IP_NF_CT_ACCT bool 'Connection tracking flow accounting' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help If this option is enabled, the connection tracking code will keep per-flow packet and byte counters. @@ -209,7 +209,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_CT_ACCT config ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK_MARK bool 'Connection mark tracking support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK select ADK_KERNEL_IP_NF_MATCH_CONNMARK help This option enables support for connection marks, used by the @@ -219,7 +219,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK_MARK config ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK_SECMARK bool 'Connection tracking security mark support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK #FIXME select NETWORK_SECMARK help This option enables security markings to be applied to @@ -230,7 +230,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK_SECMARK config ADK_KPACKAGE_KMOD_IP_NF_FTP tristate 'FTP protocol support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help Tracking FTP connections is problematic: special helpers are required for tracking them, and doing masquerading and other forms @@ -238,7 +238,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_FTP config ADK_KPACKAGE_KMOD_IP_NF_IRC tristate 'IRC protocol support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help There is a commonly-used extension to IRC called Direct Client-to-Client Protocol (DCC). This enables users to send @@ -251,7 +251,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_IRC config ADK_KPACKAGE_KMOD_IP_NF_NETBIOS_NS tristate 'NetBIOS name service protocol support (EXPERIMENTAL)' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help NetBIOS name service requests are sent as broadcast messages from an unprivileged port and responded to with unicast messages to the @@ -268,7 +268,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_NETBIOS_NS config ADK_KPACKAGE_KMOD_IP_NF_TFTP tristate 'TFTP protocol support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help TFTP connection tracking helper, this is required depending on how restrictive your ruleset is. @@ -277,7 +277,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_TFTP config ADK_KPACKAGE_KMOD_IP_NF_AMANDA tristate 'Amanda backup protocol support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK #FIXME TEXTSEARCH && TEXTSEARCH_KMP help If you are running the Amanda backup package @@ -289,7 +289,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_AMANDA config ADK_KPACKAGE_KMOD_IP_NF_PPTP tristate 'PPTP protocol support' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help This module adds support for PPTP (Point to Point Tunnelling Protocol, RFC2637) connection tracking and NAT. @@ -303,7 +303,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_PPTP config ADK_KPACKAGE_KMOD_IP_NF_H323 tristate 'H.323 protocol support (EXPERIMENTAL)' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help H.323 is a VoIP signalling protocol from ITU-T. As one of the most important VoIP protocols, it is widely used by voice hardware and @@ -320,7 +320,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_H323 config ADK_KPACKAGE_KMOD_IP_NF_SIP tristate 'SIP protocol support (EXPERIMENTAL)' - depends ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK + depends on ADK_KPACKAGE_KMOD_IP_NF_CONNTRACK help SIP is an application-layer control protocol that can establish, modify, and terminate multimedia sessions (conferences) such as @@ -340,7 +340,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_IPTABLES config ADK_KPACKAGE_KMOD_IP_NF_FILTER tristate 'Packet Filtering' - depends ADK_KPACKAGE_KMOD_IP_NF_IPTABLES + depends on ADK_KPACKAGE_KMOD_IP_NF_IPTABLES help Packet filtering defines a table `filter', which has a series of rules for simple packet filtering at local input, forwarding and @@ -348,7 +348,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_FILTER config ADK_KPACKAGE_KMOD_NF_NAT tristate 'Full NAT' - depends ADK_KPACKAGE_KMOD_IP_NF_IPTABLES + depends on ADK_KPACKAGE_KMOD_IP_NF_IPTABLES help The Full NAT option allows masquerading, port forwarding and other forms of full Network Address Port Translation. It is controlled by @@ -356,7 +356,7 @@ config ADK_KPACKAGE_KMOD_NF_NAT config ADK_KPACKAGE_KMOD_IP_NF_TARGET_MASQUERADE tristate 'MASQUERADE target support' - depends ADK_KPACKAGE_KMOD_NF_NAT + depends on ADK_KPACKAGE_KMOD_NF_NAT help Masquerading is a special case of NAT: all outgoing connections are changed to seem to come from a particular interface's address, and @@ -366,7 +366,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_TARGET_MASQUERADE config ADK_KPACKAGE_KMOD_IP_NF_TARGET_REJECT tristate 'REJECT target support' - depends ADK_KPACKAGE_KMOD_IP_NF_FILTER + depends on ADK_KPACKAGE_KMOD_IP_NF_FILTER help The REJECT target allows a filtering rule to specify that an ICMP error should be issued in response to an incoming packet, rather @@ -374,14 +374,14 @@ config ADK_KPACKAGE_KMOD_IP_NF_TARGET_REJECT config ADK_KPACKAGE_KMOD_IP_NF_TARGET_LOG tristate 'LOG target support' - depends ADK_KPACKAGE_KMOD_IP_NF_FILTER + depends on ADK_KPACKAGE_KMOD_IP_NF_FILTER help This option adds a `LOG' target, which allows you to create rules in any iptables table which records the packet header to the syslog. config ADK_KPACKAGE_KMOD_IP_NF_TARGET_ULOG tristate 'ULOG target support (ipv4 only)' - depends ADK_KPACKAGE_KMOD_IP_NF_FILTER + depends on ADK_KPACKAGE_KMOD_IP_NF_FILTER help This option enables the old IPv4-only "ipt_ULOG" implementation which has been obsoleted by the new "nfnetlink_log" code (see @@ -397,7 +397,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_TARGET_ULOG config ADK_KPACKAGE_KMOD_IP_NF_TARGET_REDIRECT tristate 'REDIRECT target support' - depends ADK_KPACKAGE_KMOD_IP_NF_NAT + depends on ADK_KPACKAGE_KMOD_IP_NF_NAT help REDIRECT is a special case of NAT: all incoming connections are mapped onto the incoming interface's address, causing the packets to @@ -406,7 +406,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_TARGET_REDIRECT config ADK_KPACKAGE_KMOD_IP_NF_TARGET_NETMAP tristate 'NETMAP target support' - depends ADK_KPACKAGE_KMOD_IP_NF_NAT + depends on ADK_KPACKAGE_KMOD_IP_NF_NAT help NETMAP is an implementation of static 1:1 NAT mapping of network addresses. It maps the network address part, while keeping the host @@ -415,14 +415,14 @@ config ADK_KPACKAGE_KMOD_IP_NF_TARGET_NETMAP config ADK_KPACKAGE_KMOD_IP_NF_TARGET_SAME tristate 'SAME target support' - depends ADK_KPACKAGE_KMOD_IP_NF_NAT + depends on ADK_KPACKAGE_KMOD_IP_NF_NAT help This option adds a `SAME' target, which works like the standard SNAT target, but attempts to give clients the same IP for all connections. config ADK_KPACKAGE_KMOD_IP_NF_MANGLE tristate 'Packet mangling' - depends ADK_KPACKAGE_KMOD_IP_NF_IPTABLES + depends on ADK_KPACKAGE_KMOD_IP_NF_IPTABLES help This option adds a `mangle' table to iptables: see the man page for iptables(8). This table is used for various packet alterations @@ -430,7 +430,7 @@ config ADK_KPACKAGE_KMOD_IP_NF_MANGLE config ADK_KPACKAGE_KMOD_IP_NF_TARGET_ECN tristate 'ECN target support' - depends ADK_KPACKAGE_KMOD_IP_NF_MANGLE + depends on ADK_KPACKAGE_KMOD_IP_NF_MANGLE help This option adds a `ECN' target, which can be used in the iptables mangle table. diff --git a/target/linux/config/Config.in.network b/target/linux/config/Config.in.network index 195006c51..05bd03137 100644 --- a/target/linux/config/Config.in.network +++ b/target/linux/config/Config.in.network @@ -108,7 +108,7 @@ config ADK_KPACKAGE_KMOD_NET_IPIP config ADK_KPACKAGE_KMOD_NET_IPGRE prompt "kmod-net-ipgre.................... GRE tunnels over IP" tristate - #depends ADK_KPACKAGE_KMOD_NET_IPGRE_BROADCAST + #depends on ADK_KPACKAGE_KMOD_NET_IPGRE_BROADCAST default n help Tunneling means encapsulating data of one protocol type within @@ -124,7 +124,7 @@ config ADK_KPACKAGE_KMOD_NET_IPGRE config ADK_KPACKAGE_KMOD_IPV6 prompt "kmod-ipv6......................... IPv6 support" tristate - depends ADK_IPV6 + depends on ADK_IPV6 default n help This is complemental support for the IP version 6. @@ -139,7 +139,7 @@ config ADK_KPACKAGE_KMOD_IPV6 config ADK_KPACKAGE_KMOD_IPV6_SIT prompt "kmod-ipv6-sit..................... IPv6-in-IPv4 tunnel (SIT driver)" tristate - depends ADK_IPV6 + depends on ADK_IPV6 select ADK_KPACKAGE_KMOD_INET_TUNNEL default n help @@ -182,7 +182,7 @@ config ADK_KPACKAGE_KMOD_PPP_MPPE prompt "kmod-ppp-mppe................... PPP MPPE/MPPC module" tristate default n - depends ADK_KPACKAGE_KMOD_PPP + depends on ADK_KPACKAGE_KMOD_PPP select ADK_KERNEL_CRYPTO select ADK_KPACKAGE_KMOD_CRYPTO_ARC4 select ADK_KPACKAGE_KMOD_CRYPTO_SHA1 @@ -198,7 +198,7 @@ config ADK_KPACKAGE_KMOD_PPP_MPPE # prompt "kmod-pppoatm.................... PPPoA (PPP over ATM) kernel support" # tristate # default n -# depends ADK_KPACKAGE_KMOD_PPP +# depends on ADK_KPACKAGE_KMOD_PPP # select ADK_KPACKAGE_KMOD_ATM # help # Support for PPP over ATM @@ -207,7 +207,7 @@ config ADK_KPACKAGE_KMOD_PPPOE prompt "kmod-pppoe...................... PPPoE (PPP over Ethernet) kernel support" tristate default n - depends ADK_KPACKAGE_KMOD_PPP + depends on ADK_KPACKAGE_KMOD_PPP help Support for PPP over Ethernet diff --git a/target/linux/config/Config.in.nls b/target/linux/config/Config.in.nls index e656fe7f9..657103f74 100644 --- a/target/linux/config/Config.in.nls +++ b/target/linux/config/Config.in.nls @@ -18,7 +18,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_437 prompt "kmod-nls-codepage-437........... Codepage 437 (United States, Canada)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -33,7 +33,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_737 prompt "kmod-nls-codepage-737........... Codepage 737 (Greek)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -48,7 +48,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_775 prompt "kmod-nls-codepage-775........... Codepage 775 (Baltic Rim)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -64,7 +64,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_850 prompt "kmod-nls-codepage-850........... Codepage 850 (Western European Languages)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -81,7 +81,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_852 prompt "kmod-nls-codepage-852........... Codepage 852 (Eastern European Languages)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -99,7 +99,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_855 prompt "kmod-nls-codepage-855........... Codepage 855 (Cyrillic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -113,7 +113,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_857 prompt "kmod-nls-codepage-857........... Codepage 857 (Turkish)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -127,7 +127,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_860 prompt "kmod-nls-codepage-860........... Codepage 860 (Portuguese)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -141,7 +141,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_861 prompt "kmod-nls-codepage-861........... Codepage 861 (Icelandic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -155,7 +155,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_862 prompt "kmod-nls-codepage-862........... Codepage 862 (Hebrew)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -169,7 +169,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_863 prompt "kmod-nls-codepage-863........... Codepage 863 (French Canadian)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -184,7 +184,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_864 prompt "kmod-nls-codepage-864........... Codepage 864 (Arabic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -198,7 +198,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_865 prompt "kmod-nls-codepage-865........... Codepage 865 (Norwegian, Danish)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -213,7 +213,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_866 prompt "kmod-nls-codepage-866........... Codepage 866 (Cyrillic/Russian)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -228,7 +228,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_869 prompt "kmod-nls-codepage-869........... Codepage 869 (Greek)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -242,7 +242,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_874 prompt "kmod-nls-codepage-874........... Codepage 874 (Thai)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -256,7 +256,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_932 prompt "kmod-nls-codepage-932........... Codepage 932 (Japanese)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -272,7 +272,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_936 prompt "kmod-nls-codepage-936........... Codepage 936 (Simplified Chinese)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -287,7 +287,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_949 prompt "kmod-nls-codepage-949........... Codepage 949 (Korean)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -301,7 +301,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_950 prompt "kmod-nls-codepage-950........... Codepage 950 (Traditional Chinese)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -316,7 +316,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_1250 prompt "kmod-nls-codepage-1250.......... Codepage 1250 (Slavic/Central European)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CDROMs @@ -330,7 +330,7 @@ config ADK_KPACKAGE_KMOD_NLS_CODEPAGE_1251 prompt "kmod-nls-codepage-1251.......... Codepage 1251 (Bulgarian, Belarusian)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -345,7 +345,7 @@ config ADK_KPACKAGE_KMOD_NLS_ASCII prompt "kmod-nls-ascii.................. ASCII (United States)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help An ASCII NLS module is needed if you want to override the DEFAULT NLS with this very basic charset and don't want any @@ -355,7 +355,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_1 prompt "kmod-nls-iso8859-1.............. NLS ISO 8859-1 (Latin-1; Western European Languages)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -370,7 +370,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_2 prompt "kmod-nls-iso8859-2.............. NLS ISO 8859-2 (Latin-2; Central European Languages)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -384,7 +384,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_3 prompt "kmod-nls-iso8859-3.............. NLS ISO 8859-3 (Latin-3; Esperanto, Galician, Maltese, Turkish)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -397,7 +397,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_4 prompt "kmod-nls-iso8859-4.............. NLS ISO 8859-4 (Latin-4; old Baltic charset)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -410,7 +410,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_5 prompt "kmod-nls-iso8859-5.............. NLS ISO 8859-5 (Cyrillic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -424,7 +424,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_6 prompt "kmod-nls-iso8859-6.............. NLS ISO 8859-6 (Arabic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -436,7 +436,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_7 prompt "kmod-nls-iso8859-7.............. NLS ISO 8859-7 (Greek)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -448,7 +448,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_8 prompt "kmod-nls-iso8859-8.............. NLS ISO 8859-8 (Hebrew)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -460,7 +460,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_9 prompt "kmod-nls-iso8859-9.............. NLS ISO 8859-9 (Latin-5; Turkish)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -473,7 +473,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_13 prompt "kmod-nls-iso8859-13............. NLS ISO 8859-13 (Latin-7; Baltic Rim)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -486,7 +486,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_14 prompt "kmod-nls-iso8859-14............. NLS ISO 8859-14 (Latin-8; Celtic)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -500,7 +500,7 @@ config ADK_KPACKAGE_KMOD_NLS_ISO8859_15 prompt "kmod-nls-iso8859-15............. NLS ISO 8859-15 (Latin-9; Western European Languages with Euro)" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -519,7 +519,7 @@ config ADK_KPACKAGE_KMOD_NLS_KOI8_R prompt "kmod-nls-koi8-r................. NLS KOI8-R (Cryllic for Russian and Bulgarian" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -531,7 +531,7 @@ config ADK_KPACKAGE_KMOD_NLS_KOI8_U prompt "kmod-nls-koi8-u................. NLS KOI8-U (Cyrillic for Russian, Bulgarian and Ukrainian" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs @@ -543,7 +543,7 @@ config ADK_KPACKAGE_KMOD_NLS_UTF8 prompt "kmod-nls-utf8................... NLS UTF8" tristate default n - depends ADK_KPACKAGE_KMOD_NLS + depends on ADK_KPACKAGE_KMOD_NLS help If you want to display filenames with native language characters from the Microsoft FAT file system family or from JOLIET CD-ROMs diff --git a/target/linux/config/Config.in.pcmcia b/target/linux/config/Config.in.pcmcia index f06ad0783..385ede11b 100644 --- a/target/linux/config/Config.in.pcmcia +++ b/target/linux/config/Config.in.pcmcia @@ -12,14 +12,14 @@ config ADK_KPACKAGE_KMOD_PCCARD config ADK_KPACKAGE_KMOD_PCMCIA prompt "kmod-pcmcia....................... 16-bit PCMCIA support" tristate - depends ADK_KPACKAGE_KMOD_PCCARD + depends on ADK_KPACKAGE_KMOD_PCCARD select ADK_KERNEL_CRC32 default n config ADK_KPACKAGE_KMOD_YENTA prompt "kmod-cardbus...................... 32-bit CardBus support" tristate - depends ADK_KPACKAGE_KMOD_PCCARD + depends on ADK_KPACKAGE_KMOD_PCCARD select ADK_KERNEL_CARDBUS default n diff --git a/target/linux/config/Config.in.sched b/target/linux/config/Config.in.sched index c5a992ba4..808b00e41 100644 --- a/target/linux/config/Config.in.sched +++ b/target/linux/config/Config.in.sched @@ -92,7 +92,7 @@ config ADK_KPACKAGE_KMOD_NET_SCH_HFSC config ADK_KPACKAGE_KMOD_NET_SCH_ATM prompt "kmod-sched-atm.................... ATM Virtual Circuits (ATM)" tristate - depends ADK_KPACKAGE_KMOD_ATM + depends on ADK_KPACKAGE_KMOD_ATM select ADK_KERNEL_NET_SCHED default n help @@ -248,7 +248,7 @@ config ADK_KPACKAGE_KMOD_NET_CLS_U32_PERF prompt ".................................. Performance counters support" bool select ADK_KERNEL_NET_CLS - depends ADK_KPACKAGE_KMOD_NET_CLS_U32 + depends on ADK_KPACKAGE_KMOD_NET_CLS_U32 default n help Say Y here to make u32 gather additional statistics useful for @@ -258,8 +258,8 @@ config ADK_KPACKAGE_KMOD_NET_CLS_U32_MARK prompt ".................................. Netfilter marks support" bool select ADK_KERNEL_NET_CLS - depends ADK_KPACKAGE_KMOD_NET_CLS_U32 - depends ADK_KPACKAGE_KMOD_NET_CLS_FW + depends on ADK_KPACKAGE_KMOD_NET_CLS_U32 + depends on ADK_KPACKAGE_KMOD_NET_CLS_FW default n help Say Y here to be able to use netfilter marks as u32 key. @@ -276,7 +276,7 @@ config ADK_KPACKAGE_KMOD_NET_CLS_POLICE prompt "kmod-act-police................... Traffic Policing" tristate select ADK_KERNEL_NET_CLS_ACT - depends ADK_LINUX_2_4 + depends on ADK_LINUX_2_4 default n help Say Y here if you want to do traffic policing, i.e. strict @@ -287,7 +287,7 @@ config ADK_KPACKAGE_KMOD_NET_ACT_POLICE prompt "kmod-act-police................... Traffic Policing" tristate select ADK_KERNEL_NET_CLS_ACT - depends ADK_LINUX_2_6 + depends on ADK_LINUX_2_6 default n help Say Y here if you want to do traffic policing, i.e. strict @@ -298,7 +298,7 @@ config ADK_KPACKAGE_KMOD_NET_ACT_GACT prompt "kmod-act-gact..................... Generic actions" tristate select ADK_KERNEL_NET_CLS_ACT - depends ADK_LINUX_2_6 + depends on ADK_LINUX_2_6 default n help Say Y here to take generic actions such as dropping and @@ -308,7 +308,7 @@ config ADK_KPACKAGE_KMOD_NET_ACT_MIRRED prompt "kmod-act-mirred................... Redirecting and Mirroring" tristate select ADK_KERNEL_NET_CLS_ACT - depends ADK_LINUX_2_6 + depends on ADK_LINUX_2_6 default n help Say Y here to allow packets to be mirrored or redirected to @@ -319,7 +319,7 @@ config ADK_KPACKAGE_KMOD_NET_ACT_IPT tristate select ADK_KERNEL_NET_CLS_ACT select ADK_KPACKAGE_KMOD_IP_NF_IPTABLES - depends ADK_LINUX_2_6 + depends on ADK_LINUX_2_6 default n help Say Y here to be able to invoke iptables targets after successful @@ -329,7 +329,7 @@ config ADK_KPACKAGE_KMOD_NET_ACT_PEDIT prompt "kmod-act-pedit.................... Packet Editing" tristate select ADK_KERNEL_NET_CLS_ACT - depends ADK_LINUX_2_6 + depends on ADK_LINUX_2_6 default n help Say Y here if you want to mangle the content of packets. diff --git a/target/linux/config/Config.in.usb b/target/linux/config/Config.in.usb index b3dfa9cbd..2efab411b 100644 --- a/target/linux/config/Config.in.usb +++ b/target/linux/config/Config.in.usb @@ -50,8 +50,8 @@ config ADK_KPACKAGE_KMOD_USB config ADK_KPACKAGE_KMOD_USB_UHCI_HCD prompt "kmod-usb-uhci................... Support for UHCI controllers" tristate - depends ADK_KPACKAGE_KMOD_USB - depends !ADK_LINUX_CRIS_FOXBOARD + depends on ADK_KPACKAGE_KMOD_USB + depends on !ADK_LINUX_CRIS_FOXBOARD select ADK_PACKAGE_KMOD_USB_CONTROLLER help The Universal Host Controller Interface is a standard by Intel for @@ -68,8 +68,8 @@ config ADK_KPACKAGE_KMOD_USB_OHCI_HCD tristate default y if ADK_LINUX_X86_ALIX1C default n - depends !ADK_LINUX_CRIS_FOXBOARD - depends ADK_KPACKAGE_KMOD_USB + depends on !ADK_LINUX_CRIS_FOXBOARD + depends on ADK_KPACKAGE_KMOD_USB select ADK_PACKAGE_KMOD_USB_CONTROLLER help The Open Host Controller Interface (OHCI) is a standard for accessing @@ -85,7 +85,7 @@ config ADK_KPACKAGE_KMOD_USB_ISP116X_HCD prompt "kmod-usb-isp116x................ ISP116X HCD support" tristate default n - depends !ADK_LINUX_CRIS_FOXBOARD + depends on !ADK_LINUX_CRIS_FOXBOARD depends on ADK_KPACKAGE_KMOD_USB select ADK_PACKAGE_KMOD_USB_CONTROLLER help @@ -98,7 +98,7 @@ config ADK_KPACKAGE_KMOD_USB_SL811_HCD prompt "kmod-usb-sl811.................. SL811HS HCD support" tristate default n - depends !ADK_LINUX_CRIS_FOXBOARD + depends on !ADK_LINUX_CRIS_FOXBOARD depends on ADK_KPACKAGE_KMOD_USB select ADK_PACKAGE_KMOD_USB_CONTROLLER help @@ -111,10 +111,10 @@ config ADK_KPACKAGE_KMOD_USB_SL811_HCD config ADK_KPACKAGE_KMOD_USB_EHCI_HCD prompt "kmod-usb-ehci................... Support for USB 2.0 controllers" tristate - depends !ADK_LINUX_CRIS_FOXBOARD + depends on !ADK_LINUX_CRIS_FOXBOARD default y if ADK_LINUX_X86_ALIX1C default n - depends ADK_KPACKAGE_KMOD_USB + depends on ADK_KPACKAGE_KMOD_USB select ADK_PACKAGE_KMOD_USB_CONTROLLER help The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 @@ -145,25 +145,25 @@ config ADK_KPACKAGE_KMOD_USB_ACM prompt "kmod-usb-acm...................... Support for USB modems/isdn controllers" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER config ADK_KPACKAGE_KMOD_USB_PEGASUS prompt "kmod-usb-pegasus.................. Support for USB Pegasus" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER config ADK_KPACKAGE_KMOD_USB_PRINTER prompt "kmod-usb-printer.................. Support for USB printers" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER config ADK_KPACKAGE_KMOD_USB_SERIAL prompt "kmod-usb-serial................... Support for USB-to-serial converters" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER help Say Y here if you have a USB device that provides normal serial ports, or acts like a serial device, and you want to connect it to @@ -178,7 +178,7 @@ config ADK_KPACKAGE_KMOD_USB_SERIAL_BELKIN prompt "kmod-usb-serial-belkin.......... Support for Belkin USB-to-serial converters" tristate default n - depends ADK_KPACKAGE_KMOD_USB_SERIAL + depends on ADK_KPACKAGE_KMOD_USB_SERIAL help Say Y here if you want to use a Belkin USB Serial single port adaptor (F5U103 is one of the model numbers) or the Peracom single @@ -188,7 +188,7 @@ config ADK_KPACKAGE_KMOD_USB_SERIAL_FTDI_SIO prompt "kmod-usb-serial-ftdi............ Support for FTDI USB-to-serial converter" tristate default n - depends ADK_KPACKAGE_KMOD_USB_SERIAL + depends on ADK_KPACKAGE_KMOD_USB_SERIAL help Say Y here if you want to use a FTDI SIO single port USB to serial converter device. The implementation I have is called the USC-1000. @@ -201,7 +201,7 @@ config ADK_KPACKAGE_KMOD_USB_SERIAL_MCT_U232 prompt "kmod-usb-serial-mct-u232........ Support for Magic Control Technology USB-to-Serial converters" tristate default n - depends ADK_KPACKAGE_KMOD_USB_SERIAL + depends on ADK_KPACKAGE_KMOD_USB_SERIAL help Say Y here if you want to use a USB Serial single port adapter from Magic Control Technology Corp. (U232 is one of the model numbers). @@ -213,7 +213,7 @@ config ADK_KPACKAGE_KMOD_USB_SERIAL_PL2303 prompt "kmod-usb-serial-pl2303.......... Support for Prolific PL2303 USB-to-Serial converters" tristate default n - depends ADK_KPACKAGE_KMOD_USB_SERIAL + depends on ADK_KPACKAGE_KMOD_USB_SERIAL help Say Y here if you want to use the PL2303 USB Serial single port adapter from Prolific. @@ -222,7 +222,7 @@ config ADK_KPACKAGE_KMOD_USB_SERIAL_VISOR prompt "kmod-usb-serial-visor........... Support for Handspring Visor / Palm m50x / Sony Clie Driver" tristate default n - depends ADK_KPACKAGE_KMOD_USB_SERIAL + depends on ADK_KPACKAGE_KMOD_USB_SERIAL help Say Y here if you want to connect to your HandSpring Visor, Palm m500 or m505 through its USB docking station. See @@ -233,7 +233,7 @@ config ADK_KPACKAGE_KMOD_USB_STORAGE prompt "kmod-usb-storage.................. Support for USB storage devices" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER select ADK_KPACKAGE_KMOD_SCSI if !ADK_KERNEL_SCSI select ADK_KPACKAGE_KMOD_BLK_DEV_SD if !ADK_KERNEL_SCSI @@ -241,24 +241,24 @@ config ADK_KPACKAGE_KMOD_USB_ATM prompt "kmod-usb-atm...................... Support for USB ATM devices" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER config ADK_KPACKAGE_KMOD_USB_ATM_SPEEDTOUCH prompt "kmod-usb-atm-speedtouch......... Support for USB Speedtouch ADSL modem" tristate default n - depends ADK_KPACKAGE_KMOD_USB_ATM + depends on ADK_KPACKAGE_KMOD_USB_ATM config ADK_KPACKAGE_KMOD_USB_USBNET prompt "kmod-usb-usbnet................... Multi-purpose USB Networking Framework" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER config ADK_KPACKAGE_KMOD_USB_SISUSBVGA prompt "kmod-usb-svga..................... USB 2.0 SVGA dongle support (Net2280/SiS315)" tristate default n - depends ADK_PACKAGE_KMOD_USB_CONTROLLER + depends on ADK_PACKAGE_KMOD_USB_CONTROLLER endmenu -- cgit v1.2.3 From 04c8f363dfad7629a123fbb9410fdb089e38240a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 00:29:20 +0200 Subject: There is something wrong around this select to ADK_BROKEN linux-2.6's mconf complains about a circular dependency, this fixes the problem the fast way. Needs more investigation, so keep it there in commented form. --- target/Config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/Config.in b/target/Config.in index aa5814df1..da40e1b36 100644 --- a/target/Config.in +++ b/target/Config.in @@ -245,7 +245,7 @@ config ADK_LINUX_MIPS64EL_QEMU config ADK_LINUX_CRIS_QEMU bool "cris" select ADK_qemu_cris - select ADK_BROKEN +# select ADK_BROKEN help Qemu support for CRISv32 architecture. -- cgit v1.2.3 From f03bc8974965da8f30d81412014a49b6c161a58a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 13:21:56 +0200 Subject: drop old mconf implementation --- config/checklist.c | 377 --------- config/colors.h | 161 ---- config/conf.c | 601 --------------- config/confdata.c | 449 ----------- config/dialog.h | 196 ----- config/expr.c | 1089 -------------------------- config/expr.h | 194 ----- config/glob.c | 848 -------------------- config/glob.h | 100 --- config/inputbox.c | 240 ------ config/lex.backup | 1 - config/lkc.h | 113 --- config/lkc_proto.h | 39 - config/mconf.c | 717 ----------------- config/menu.c | 436 ----------- config/menubox.c | 438 ----------- config/msgbox.c | 85 -- config/symbol.c | 782 ------------------- config/textbox.c | 556 -------------- config/util.c | 375 --------- config/yesno.c | 118 --- config/zconf.l | 387 ---------- config/zconf.output | 2133 --------------------------------------------------- config/zconf.y | 693 ----------------- 24 files changed, 11128 deletions(-) delete mode 100644 config/checklist.c delete mode 100644 config/colors.h delete mode 100644 config/conf.c delete mode 100644 config/confdata.c delete mode 100644 config/dialog.h delete mode 100644 config/expr.c delete mode 100644 config/expr.h delete mode 100644 config/glob.c delete mode 100644 config/glob.h delete mode 100644 config/inputbox.c delete mode 100644 config/lex.backup delete mode 100644 config/lkc.h delete mode 100644 config/lkc_proto.h delete mode 100644 config/mconf.c delete mode 100644 config/menu.c delete mode 100644 config/menubox.c delete mode 100644 config/msgbox.c delete mode 100644 config/symbol.c delete mode 100644 config/textbox.c delete mode 100644 config/util.c delete mode 100644 config/yesno.c delete mode 100644 config/zconf.l delete mode 100644 config/zconf.output delete mode 100644 config/zconf.y diff --git a/config/checklist.c b/config/checklist.c deleted file mode 100644 index ec5a9ad68..000000000 --- a/config/checklist.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * checklist.c -- implements the checklist box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension - * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - -static int list_width, check_x, item_x, checkflag; - -/* - * Print list item - */ -static void -print_item (WINDOW * win, const char *item, int status, - int choice, int selected) -{ - int i; - - /* Clear 'residue' of last item */ - wattrset (win, menubox_attr); - wmove (win, choice, 0); - for (i = 0; i < list_width; i++) - waddch (win, ' '); - - wmove (win, choice, check_x); - wattrset (win, selected ? check_selected_attr : check_attr); - if (checkflag == FLAG_CHECK) - wprintw (win, "[%c]", status ? 'X' : ' '); - else - wprintw (win, "(%c)", status ? 'X' : ' '); - -#if 0 - wattrset (win, selected ? tag_selected_attr : tag_attr); - mvwaddch(win, choice, item_x, item[0]); - wattrset (win, selected ? item_selected_attr : item_attr); - waddstr (win, (char *)item+1); -#else - wattrset (win, selected ? item_selected_attr : item_attr); - waddstr (win, item); -#endif - if (selected) { - wmove (win, choice, check_x+1); - wrefresh (win); - } -} - -/* - * Print the scroll indicators. - */ -static void -print_arrows (WINDOW * win, int choice, int item_no, int scroll, - int y, int x, int height) -{ - wmove(win, y, x); - - if (scroll > 0) { - wattrset (win, uarrow_attr); - waddch (win, ACS_UARROW); - waddstr (win, "(-)"); - } - else { - wattrset (win, menubox_attr); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - } - - y = y + height + 1; - wmove(win, y, x); - - if ((height < item_no) && (scroll + choice < item_no - 1)) { - wattrset (win, darrow_attr); - waddch (win, ACS_DARROW); - waddstr (win, "(+)"); - } - else { - wattrset (win, menubox_border_attr); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - } -} - -/* - * Display the termination buttons - */ -static void -print_buttons( WINDOW *dialog, int height, int width, int selected) -{ - int x = width / 2 - 11; - int y = height - 2; - - print_button (dialog, "Select", y, x, selected == 0); - print_button (dialog, " Help ", y, x + 14, selected == 1); - - wmove(dialog, y, x+1 + 14*selected); - wrefresh (dialog); -} - -/* - * Display a dialog box with a list of options that can be turned on or off - * The `flag' parameter is used to select between radiolist and checklist. - */ -int -dialog_checklist (const char *title, const char *prompt, int height, int width, - int list_height, int item_no, struct dialog_list_item ** items, - int flag) - -{ - int i, x, y, box_x, box_y; - int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status; - WINDOW *dialog, *list; - - checkflag = flag; - - /* Allocate space for storing item on/off status */ - if ((status = malloc (sizeof (int) * item_no)) == NULL) { - endwin (); - fprintf (stderr, - "\nCan't allocate memory in dialog_checklist().\n"); - exit (-1); - } - - /* Initializes status */ - for (i = 0; i < item_no; i++) { - status[i] = (items[i]->selected == 1); /* ON */ - if ((!choice && status[i]) || items[i]->selected == 2) /* SELECTED */ - choice = i + 1; - } - if (choice) - choice--; - - max_choice = MIN (list_height, item_no); - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - wattrset (dialog, border_attr); - mvwaddch (dialog, height-3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - waddch (dialog, ACS_RTEE); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - - wattrset (dialog, dialog_attr); - print_autowrap (dialog, prompt, width - 2, 1, 3); - - list_width = width - 6; - box_y = height - list_height - 5; - box_x = (width - list_width) / 2 - 1; - - /* create new window for the list */ - list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1); - - keypad (list, TRUE); - - /* draw a box around the list items */ - draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2, - menubox_border_attr, menubox_attr); - - /* Find length of longest item in order to center checklist */ - check_x = 0; - for (i = 0; i < item_no; i++) - check_x = MAX (check_x, + strlen (items[i]->name) + 4); - - check_x = (list_width - check_x) / 2; - item_x = check_x + 4; - - if (choice >= list_height) { - scroll = choice - list_height + 1; - choice -= scroll; - } - - /* Print the list */ - for (i = 0; i < max_choice; i++) { - print_item (list, items[scroll + i]->name, - status[i+scroll], i, i == choice); - } - - print_arrows(dialog, choice, item_no, scroll, - box_y, box_x + check_x + 5, list_height); - - print_buttons(dialog, height, width, 0); - - wnoutrefresh (list); - wnoutrefresh (dialog); - doupdate (); - - while (key != ESC) { - key = wgetch (dialog); - - for (i = 0; i < max_choice; i++) - if (toupper(key) == toupper(items[scroll + i]->name[0])) - break; - - - if ( i < max_choice || key == KEY_UP || key == KEY_DOWN || - key == '+' || key == '-' ) { - if (key == KEY_UP || key == '-') { - if (!choice) { - if (!scroll) - continue; - /* Scroll list down */ - if (list_height > 1) { - /* De-highlight current first item */ - print_item (list, items[scroll]->name, - status[scroll], 0, FALSE); - scrollok (list, TRUE); - wscrl (list, -1); - scrollok (list, FALSE); - } - scroll--; - print_item (list, items[scroll]->name, - status[scroll], 0, TRUE); - wnoutrefresh (list); - - print_arrows(dialog, choice, item_no, scroll, - box_y, box_x + check_x + 5, list_height); - - wrefresh (dialog); - - continue; /* wait for another key press */ - } else - i = choice - 1; - } else if (key == KEY_DOWN || key == '+') { - if (choice == max_choice - 1) { - if (scroll + choice >= item_no - 1) - continue; - /* Scroll list up */ - if (list_height > 1) { - /* De-highlight current last item before scrolling up */ - print_item (list, items[scroll + max_choice - 1]->name, - status[scroll + max_choice - 1], - max_choice - 1, FALSE); - scrollok (list, TRUE); - scroll (list); - scrollok (list, FALSE); - } - scroll++; - print_item (list, items[scroll + max_choice - 1]->name, - status[scroll + max_choice - 1], - max_choice - 1, TRUE); - wnoutrefresh (list); - - print_arrows(dialog, choice, item_no, scroll, - box_y, box_x + check_x + 5, list_height); - - wrefresh (dialog); - - continue; /* wait for another key press */ - } else - i = choice + 1; - } - if (i != choice) { - /* De-highlight current item */ - print_item (list, items[scroll + choice]->name, - status[scroll + choice], choice, FALSE); - /* Highlight new item */ - choice = i; - print_item (list, items[scroll + choice]->name, - status[scroll + choice], choice, TRUE); - wnoutrefresh (list); - wrefresh (dialog); - } - continue; /* wait for another key press */ - } - switch (key) { - case 'H': - case 'h': - case '?': - for (i = 0; i < item_no; i++) - items[i]->selected = 0; - items[scroll + choice]->selected = 1; - delwin (dialog); - free (status); - return 1; - case TAB: - case KEY_LEFT: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 1 : (button > 1 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh (dialog); - break; - case 'S': - case 's': - case ' ': - case '\n': - if (!button) { - if (flag == FLAG_CHECK) { - status[scroll + choice] = !status[scroll + choice]; - wmove (list, choice, check_x); - wattrset (list, check_selected_attr); - wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' '); - } else { - if (!status[scroll + choice]) { - for (i = 0; i < item_no; i++) - status[i] = 0; - status[scroll + choice] = 1; - for (i = 0; i < max_choice; i++) - print_item (list, items[scroll + i]->name, - status[scroll + i], i, i == choice); - } - } - wnoutrefresh (list); - wrefresh (dialog); - - for (i = 0; i < item_no; i++) { - items[i]->selected = status[i]; - } - } else { - for (i = 0; i < item_no; i++) - items[i]->selected = 0; - items[scroll + choice]->selected = 1; - } - delwin (dialog); - free (status); - return button; - case 'X': - case 'x': - key = ESC; - case ESC: - break; - } - - /* Now, update everything... */ - doupdate (); - } - - - delwin (dialog); - free (status); - return -1; /* ESC pressed */ -} diff --git a/config/colors.h b/config/colors.h deleted file mode 100644 index d34dd37c6..000000000 --- a/config/colors.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * colors.h -- color attribute definitions - * - * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -/* - * Default color definitions - * - * *_FG = foreground - * *_BG = background - * *_HL = highlight? - */ -#define SCREEN_FG COLOR_CYAN -#define SCREEN_BG COLOR_BLUE -#define SCREEN_HL TRUE - -#define SHADOW_FG COLOR_BLACK -#define SHADOW_BG COLOR_BLACK -#define SHADOW_HL TRUE - -#define DIALOG_FG COLOR_BLACK -#define DIALOG_BG COLOR_WHITE -#define DIALOG_HL FALSE - -#define TITLE_FG COLOR_YELLOW -#define TITLE_BG COLOR_WHITE -#define TITLE_HL TRUE - -#define BORDER_FG COLOR_WHITE -#define BORDER_BG COLOR_WHITE -#define BORDER_HL TRUE - -#define BUTTON_ACTIVE_FG COLOR_WHITE -#define BUTTON_ACTIVE_BG COLOR_BLUE -#define BUTTON_ACTIVE_HL TRUE - -#define BUTTON_INACTIVE_FG COLOR_BLACK -#define BUTTON_INACTIVE_BG COLOR_WHITE -#define BUTTON_INACTIVE_HL FALSE - -#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE -#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE -#define BUTTON_KEY_ACTIVE_HL TRUE - -#define BUTTON_KEY_INACTIVE_FG COLOR_RED -#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE -#define BUTTON_KEY_INACTIVE_HL FALSE - -#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW -#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE -#define BUTTON_LABEL_ACTIVE_HL TRUE - -#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK -#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE -#define BUTTON_LABEL_INACTIVE_HL TRUE - -#define INPUTBOX_FG COLOR_BLACK -#define INPUTBOX_BG COLOR_WHITE -#define INPUTBOX_HL FALSE - -#define INPUTBOX_BORDER_FG COLOR_BLACK -#define INPUTBOX_BORDER_BG COLOR_WHITE -#define INPUTBOX_BORDER_HL FALSE - -#define SEARCHBOX_FG COLOR_BLACK -#define SEARCHBOX_BG COLOR_WHITE -#define SEARCHBOX_HL FALSE - -#define SEARCHBOX_TITLE_FG COLOR_YELLOW -#define SEARCHBOX_TITLE_BG COLOR_WHITE -#define SEARCHBOX_TITLE_HL TRUE - -#define SEARCHBOX_BORDER_FG COLOR_WHITE -#define SEARCHBOX_BORDER_BG COLOR_WHITE -#define SEARCHBOX_BORDER_HL TRUE - -#define POSITION_INDICATOR_FG COLOR_YELLOW -#define POSITION_INDICATOR_BG COLOR_WHITE -#define POSITION_INDICATOR_HL TRUE - -#define MENUBOX_FG COLOR_BLACK -#define MENUBOX_BG COLOR_WHITE -#define MENUBOX_HL FALSE - -#define MENUBOX_BORDER_FG COLOR_WHITE -#define MENUBOX_BORDER_BG COLOR_WHITE -#define MENUBOX_BORDER_HL TRUE - -#define ITEM_FG COLOR_BLACK -#define ITEM_BG COLOR_WHITE -#define ITEM_HL FALSE - -#define ITEM_SELECTED_FG COLOR_WHITE -#define ITEM_SELECTED_BG COLOR_BLUE -#define ITEM_SELECTED_HL TRUE - -#define TAG_FG COLOR_YELLOW -#define TAG_BG COLOR_WHITE -#define TAG_HL TRUE - -#define TAG_SELECTED_FG COLOR_YELLOW -#define TAG_SELECTED_BG COLOR_BLUE -#define TAG_SELECTED_HL TRUE - -#define TAG_KEY_FG COLOR_YELLOW -#define TAG_KEY_BG COLOR_WHITE -#define TAG_KEY_HL TRUE - -#define TAG_KEY_SELECTED_FG COLOR_YELLOW -#define TAG_KEY_SELECTED_BG COLOR_BLUE -#define TAG_KEY_SELECTED_HL TRUE - -#define CHECK_FG COLOR_BLACK -#define CHECK_BG COLOR_WHITE -#define CHECK_HL FALSE - -#define CHECK_SELECTED_FG COLOR_WHITE -#define CHECK_SELECTED_BG COLOR_BLUE -#define CHECK_SELECTED_HL TRUE - -#define UARROW_FG COLOR_GREEN -#define UARROW_BG COLOR_WHITE -#define UARROW_HL TRUE - -#define DARROW_FG COLOR_GREEN -#define DARROW_BG COLOR_WHITE -#define DARROW_HL TRUE - -/* End of default color definitions */ - -#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y))) -#define COLOR_NAME_LEN 10 -#define COLOR_COUNT 8 - -/* - * Global variables - */ - -typedef struct { - char name[COLOR_NAME_LEN]; - int value; -} color_names_st; - -extern color_names_st color_names[]; -extern int color_table[][3]; diff --git a/config/conf.c b/config/conf.c deleted file mode 100644 index 08e2895d8..000000000 --- a/config/conf.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -extern int output_mode; - -static void conf(struct menu *menu); -static void check_conf(struct menu *menu); - -enum { - ask_all, - ask_new, - ask_silent, - set_default, - set_yes, - set_mod, - ask_mod, - set_no, - set_random -} input_mode = ask_all; -char *defconfig_file; - -static int indent = 1; -static int valid_stdin = 1; -static int conf_cnt; -static int press_enter = 0; -static char line[128]; -static struct menu *rootEntry; - -static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; - -static void strip(char *str) -{ - char *p = str; - int l; - - while ((isspace(*p))) - p++; - l = strlen(p); - if (p != str) - memmove(str, p, l + 1); - if (!l) - return; - p = str + l - 1; - while ((isspace(*p))) - *p-- = 0; -} - -static void check_stdin(void) -{ - if (!valid_stdin && input_mode == ask_silent && !press_enter) { - printf("aborted!\n\n"); - printf("Console input/output is redirected. "); - printf("Run 'make oldconfig' to update configuration.\n\n"); - exit(1); - } -} - -static void conf_askvalue(struct symbol *sym, const char *def) -{ - enum symbol_type type = sym_get_type(sym); - tristate val; - - if (!sym_has_value(sym)) - printf("(NEW) "); - - line[0] = '\n'; - line[1] = 0; - - if (!sym_is_changable(sym)) { - printf("%s\n", def); - line[0] = '\n'; - line[1] = 0; - return; - } - - switch (input_mode) { - case ask_new: - case ask_silent: - if (sym_has_value(sym) || - (output_mode && !(sym->flags & SYMBOL_WRITE))) { - printf("%s\n", def); - return; - } - check_stdin(); - case ask_all: - fflush(stdout); - fgets(line, 128, stdin); - return; - case set_default: - printf("%s\n", def); - return; - default: - break; - } - - switch (type) { - case S_INT: - case S_HEX: - case S_STRING: - printf("%s\n", def); - return; - default: - ; - } - switch (input_mode) { - case set_yes: - if (sym_tristate_within_range(sym, yes)) { - line[0] = 'y'; - line[1] = '\n'; - line[2] = 0; - break; - } - case ask_mod: - case set_mod: - if (type == S_TRISTATE) { - if (sym_tristate_within_range(sym, mod)) { - line[0] = 'm'; - line[1] = '\n'; - line[2] = 0; - break; - } - } else { - if (sym_tristate_within_range(sym, yes)) { - line[0] = 'y'; - line[1] = '\n'; - line[2] = 0; - break; - } - } - case set_no: - if (sym_tristate_within_range(sym, no)) { - line[0] = 'n'; - line[1] = '\n'; - line[2] = 0; - break; - } - case set_random: - do { - val = (tristate)(random() % 3); - } while (!sym_tristate_within_range(sym, val)); - switch (val) { - case no: line[0] = 'n'; break; - case mod: line[0] = 'm'; break; - case yes: line[0] = 'y'; break; - } - line[1] = '\n'; - line[2] = 0; - break; - default: - break; - } - printf("%s", line); -} - -int conf_string(struct menu *menu) -{ - struct symbol *sym = menu->sym; - const char *def, *help; - - while (1) { - printf("%*s%s ", indent - 1, "", menu->prompt->text); - printf("(%s) ", sym->name); - def = sym_get_string_value(sym); - if (sym_get_string_value(sym)) - printf("[%s] ", def); - conf_askvalue(sym, def); - switch (line[0]) { - case '\n': - break; - case '?': - /* print help */ - if (line[1] == '\n') { - help = nohelp_text; - if (menu->sym->help) - help = menu->sym->help; - printf("\n%s\n", menu->sym->help); - def = NULL; - break; - } - default: - line[strlen(line)-1] = 0; - def = line; - } - if (def && sym_set_string_value(sym, def)) - return 0; - } -} - -static int conf_sym(struct menu *menu) -{ - struct symbol *sym = menu->sym; - int type; - tristate oldval, newval; - const char *help; - - while (1) { - printf("%*s%s ", indent - 1, "", menu->prompt->text); - if (sym->name) - printf("(%s) ", sym->name); - type = sym_get_type(sym); - putchar('['); - oldval = sym_get_tristate_value(sym); - switch (oldval) { - case no: - putchar('N'); - break; - case mod: - putchar('M'); - break; - case yes: - putchar('Y'); - break; - } - if (oldval != no && sym_tristate_within_range(sym, no)) - printf("/n"); - if (oldval != mod && sym_tristate_within_range(sym, mod)) - printf("/m"); - if (oldval != yes && sym_tristate_within_range(sym, yes)) - printf("/y"); - if (sym->help) - printf("/?"); - printf("] "); - conf_askvalue(sym, sym_get_string_value(sym)); - strip(line); - - switch (line[0]) { - case 'n': - case 'N': - newval = no; - if (!line[1] || !strcmp(&line[1], "o")) - break; - continue; - case 'm': - case 'M': - newval = mod; - if (!line[1]) - break; - continue; - case 'y': - case 'Y': - newval = yes; - if (!line[1] || !strcmp(&line[1], "es")) - break; - continue; - case 0: - newval = oldval; - break; - case '?': - goto help; - default: - continue; - } - if (sym_set_tristate_value(sym, newval)) - return 0; -help: - help = nohelp_text; - if (sym->help) - help = sym->help; - printf("\n%s\n", help); - } -} - -static int conf_choice(struct menu *menu) -{ - struct symbol *sym, *def_sym; - struct menu *child; - int type; - bool is_new; - - sym = menu->sym; - type = sym_get_type(sym); - is_new = !sym_has_value(sym); - if (sym_is_changable(sym)) { - conf_sym(menu); - sym_calc_value(sym); - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - return 0; - case yes: - break; - } - } else { - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); - return 0; - case yes: - break; - } - } - - while (1) { - int cnt, def; - - printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); - def_sym = sym_get_choice_value(sym); - cnt = def = 0; - line[0] = '0'; - line[1] = 0; - for (child = menu->list; child; child = child->next) { - if (!menu_is_visible(child)) - continue; - if (!child->sym) { - printf("%*c %s\n", indent, '*', menu_get_prompt(child)); - continue; - } - cnt++; - if (child->sym == def_sym) { - def = cnt; - printf("%*c", indent, '>'); - } else - printf("%*c", indent, ' '); - printf(" %d. %s", cnt, menu_get_prompt(child)); - if (child->sym->name) - printf(" (%s)", child->sym->name); - if (!sym_has_value(child->sym)) - printf(" (NEW)"); - printf("\n"); - } - printf("%*schoice", indent - 1, ""); - if (cnt == 1) { - printf("[1]: 1\n"); - goto conf_childs; - } - printf("[1-%d", cnt); - if (sym->help) - printf("?"); - printf("]: "); - switch (input_mode) { - case ask_new: - case ask_silent: - if (!is_new) { - cnt = def; - printf("%d\n", cnt); - break; - } - check_stdin(); - case ask_all: - fflush(stdout); - fgets(line, 128, stdin); - strip(line); - if (line[0] == '?') { - printf("\n%s\n", menu->sym->help ? - menu->sym->help : nohelp_text); - continue; - } - if (!line[0]) - cnt = def; - else if (isdigit(line[0])) - cnt = atoi(line); - else - continue; - break; - case set_random: - def = (random() % cnt) + 1; - case set_default: - case set_yes: - case set_mod: - case set_no: - case ask_mod: - cnt = def; - printf("%d\n", cnt); - break; - } - - conf_childs: - for (child = menu->list; child; child = child->next) { - if (!child->sym || !menu_is_visible(child)) - continue; - if (!--cnt) - break; - } - if (!child) - continue; - if (line[strlen(line) - 1] == '?') { - printf("\n%s\n", child->sym->help ? - child->sym->help : nohelp_text); - continue; - } - sym_set_choice_value(sym, child->sym); - if (child->list) { - indent += 2; - conf(child->list); - indent -= 2; - } - return 1; - } -} - -static void conf(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - prop = menu->prompt; - if (prop) { - const char *prompt; - - switch (prop->type) { - case P_MENU: - if (input_mode == ask_silent && rootEntry != menu) { - check_conf(menu); - return; - } - case P_COMMENT: - prompt = menu_get_prompt(menu); - if (prompt) - printf("%*c\n%*c %s\n%*c\n", - indent, '*', - indent, '*', prompt, - indent, '*'); - default: - ; - } - } - - if (!sym) - goto conf_childs; - - if (sym_is_choice(sym)) { - conf_choice(menu); - if (sym->curr.tri != mod) - return; - goto conf_childs; - } - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - conf_string(menu); - break; - default: - conf_sym(menu); - break; - } - -conf_childs: - if (sym) - indent += 2; - for (child = menu->list; child; child = child->next) - conf(child); - if (sym) - indent -= 2; -} - -static void check_conf(struct menu *menu) -{ - struct symbol *sym; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - if (sym) { - if (sym_is_changable(sym) && !sym_has_value(sym)) { - if (!conf_cnt++) - printf("*\n* Restart config...\n*\n"); - rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); - } - if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod) - return; - } - - for (child = menu->list; child; child = child->next) - check_conf(child); -} - -int main(int ac, char **av) -{ - int i = 1; - const char *name; - struct stat tmpstat; - - if (ac > i && av[i][0] == '-') { - switch (av[i++][1]) { - case 'A': - output_mode = 1; - /* FALLTHROUGH */ - case 'o': - input_mode = ask_new; - break; - case 'a': - input_mode = ask_new; - press_enter = 1; - break; - case 's': - input_mode = ask_silent; - valid_stdin = isatty(0) && isatty(1) && isatty(2); - break; - case 'd': - input_mode = set_default; - break; - case 'D': - input_mode = set_default; - defconfig_file = av[i++]; - if (!defconfig_file) { - printf("%s: No default config file specified\n", - av[0]); - exit(1); - } - break; - case 'n': - input_mode = set_no; - break; - case 'M': - input_mode = ask_mod; - break; - case 'm': - input_mode = set_mod; - break; - case 'y': - input_mode = set_yes; - break; - case 'r': - input_mode = set_random; - srandom(time(NULL)); - break; - case 'h': - case '?': - printf("%s [-o|-s] config\n", av[0]); - exit(0); - } - } - name = av[i]; - if (!name) { - printf("%s: configuration file missing\n", av[0]); - } - conf_parse(name); - //zconfdump(stdout); - switch (input_mode) { - case set_default: - if (!defconfig_file) - defconfig_file = conf_get_default_confname(); - if (conf_read(defconfig_file)) { - printf("***\n" - "*** Can't find default configuration \"%s\"!\n" - "***\n", defconfig_file); - exit(1); - } - break; - case ask_silent: - if (stat(".config", &tmpstat)) { - printf("***\n" - "*** You have not yet configured OpenADK!\n" - "***\n" - "*** Please run some configurator (e.g. \"make oldconfig\" or\n" - "*** \"make menuconfig\" or \"make config\").\n" - "***\n"); - exit(1); - } - case ask_all: - case ask_new: - case ask_mod: - conf_read(NULL); - break; - default: - break; - } - - if (input_mode != ask_silent) { - rootEntry = &rootmenu; - conf(&rootmenu); - if (input_mode == ask_all) { - input_mode = ask_silent; - valid_stdin = 1; - } - } - do { - conf_cnt = 0; - check_conf(&rootmenu); - } while (conf_cnt); - if (conf_write(NULL)) { - fprintf(stderr, "\n*** Error during writing of the OpenADK configuration.\n\n"); - return 1; - } - return 0; -} diff --git a/config/confdata.c b/config/confdata.c deleted file mode 100644 index 3bebe2c22..000000000 --- a/config/confdata.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -int output_mode = 0; - -const char conf_def_filename[] = ".config"; - -const char conf_defname[] = "Config.default"; - -const char *conf_confnames[] = { - ".config", - conf_defname, - NULL, -}; - -static char *conf_expand_value(const char *in) -{ - struct symbol *sym; - const char *src; - static char res_value[SYMBOL_MAXLENGTH]; - char *dst, name[SYMBOL_MAXLENGTH]; - - res_value[0] = 0; - dst = name; - while ((src = strchr(in, '$'))) { - strncat(res_value, in, src - in); - src++; - dst = name; - while (isalnum(*src) || *src == '_') - *dst++ = *src++; - *dst = 0; - sym = sym_lookup(name, 0); - sym_calc_value(sym); - strcat(res_value, sym_get_string_value(sym)); - in = src; - } - strcat(res_value, in); - - return res_value; -} - -char *conf_get_default_confname(void) -{ - struct stat buf; - static char fullname[PATH_MAX+1]; - char *env, *name; - - name = conf_expand_value(conf_defname); - env = getenv(SRCTREE); - if (env) { - sprintf(fullname, "%s/%s", env, name); - if (!stat(fullname, &buf)) - return fullname; - } - return name; -} - -int conf_read(const char *name) -{ - FILE *in = NULL; - char line[2048]; - char *p, *p2; - int lineno = 0; - struct symbol *sym; - struct property *prop; - struct expr *e; - int i; - - if (name) { - in = zconf_fopen(name); - } else { - const char **names = conf_confnames; - while ((name = *names++)) { - name = conf_expand_value(name); - in = zconf_fopen(name); - if (in) { - printf("#\n" - "# using defaults found in %s\n" - "#\n", name); - break; - } - } - } - - if (!in) - return 1; - - for_all_symbols(i, sym) { - sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; - sym->flags &= ~SYMBOL_VALID; - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - if (sym->user.val) - free(sym->user.val); - default: - sym->user.val = NULL; - sym->user.tri = no; - } - } - - while (fgets(line, sizeof(line), in)) { - lineno++; - sym = NULL; - switch (line[0]) { - case '#': - if (line[1]!=' ') - continue; - p = strchr(line + 2, ' '); - if (!p) - continue; - *p++ = 0; - if (strncmp(p, "is not set", 10)) - continue; - sym = sym_find(line + 2); - if (!sym) { - fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 2); - break; - } - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; - break; - default: - ; - } - break; - - case 'A' ... 'Z': - p = strchr(line, '='); - if (!p) - continue; - *p++ = 0; - p2 = strchr(p, '\n'); - if (p2) - *p2 = 0; - sym = sym_find(line); - if (!sym) { - fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line); - break; - } - switch (sym->type) { - case S_TRISTATE: - if (p[0] == 'm') { - sym->user.tri = mod; - sym->flags &= ~SYMBOL_NEW; - break; - } - case S_BOOLEAN: - if (p[0] == 'y') { - sym->user.tri = yes; - sym->flags &= ~SYMBOL_NEW; - break; - } - if (p[0] == 'n') { - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; - break; - } - break; - case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; - break; - } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - fprintf(stderr, "%s:%d: invalid string found\n", name, lineno); - exit(1); - } - case S_INT: - case S_HEX: - if (sym_string_valid(sym, p)) { - sym->user.val = strdup(p); - sym->flags &= ~SYMBOL_NEW; - } else { - fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name); - exit(1); - } - break; - default: - ; - } - break; - case '\n': - break; - default: - continue; - } - if (sym && sym_is_choice_value(sym)) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - switch (sym->user.tri) { - case no: - break; - case mod: - if (cs->user.tri == yes) - /* warn? */; - break; - case yes: - if (cs->user.tri != no) - /* warn? */; - cs->user.val = sym; - break; - } - cs->user.tri = E_OR(cs->user.tri, sym->user.tri); - cs->flags &= ~SYMBOL_NEW; - } - } - fclose(in); - - if (modules_sym) - sym_calc_value(modules_sym); - for_all_symbols(i, sym) { - sym_calc_value(sym); - if (sym_has_value(sym) && !sym_is_choice_value(sym)) { - if (sym->visible == no) - sym->flags |= SYMBOL_NEW; - switch (sym->type) { - case S_STRING: - case S_INT: - case S_HEX: - if (!sym_string_within_range(sym, sym->user.val)) - sym->flags |= SYMBOL_NEW; - default: - break; - } - } - if (!sym_is_choice(sym)) - continue; - prop = sym_get_choice_prop(sym); - for (e = prop->expr; e; e = e->left.expr) - if (e->right.sym->visible != no) - sym->flags |= e->right.sym->flags & SYMBOL_NEW; - } - - sym_change_count = 1; - - return 0; -} - -int conf_write(const char *name) -{ - FILE *out, *out_h; - struct symbol *sym; - struct menu *menu; - const char *basename; - char dirname[128], tmpname[128], newname[128]; - int type, l; - const char *str; - - dirname[0] = 0; - if (name && name[0]) { - struct stat st; - char *slash; - - if (!stat(name, &st) && S_ISDIR(st.st_mode)) { - strcpy(dirname, name); - strcat(dirname, "/"); - basename = conf_def_filename; - } else if ((slash = strrchr(name, '/'))) { - int size = slash - name + 1; - memcpy(dirname, name, size); - dirname[size] = 0; - if (slash[1]) - basename = slash + 1; - else - basename = conf_def_filename; - } else - basename = name; - } else - basename = conf_def_filename; - - sprintf(newname, "%s.tmpconfig.%d", dirname, getpid()); - out = fopen(newname, "w"); - if (!out) - return 1; - out_h = NULL; - if (!name) { - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) - return 1; - } - fprintf(out, "#\n" - "# Automatically generated make config: don't edit\n" - "#\n"); - if (out_h) { - fprintf(out_h, "/*\n" - " * Automatically generated header file: don't edit\n" - " */\n\n" - "#define AUTOCONF_INCLUDED\n\n" - "/* Version Number */\n" - "#define BB_VER \"%s\"\n" - "#define BB_BT \"%s\"\n", - getenv("VERSION"), - getenv("BUILDTIME")); - if (getenv("EXTRA_VERSION")) - fprintf(out_h, "#define BB_EXTRA_VERSION \"%s\"\n", - getenv("EXTRA_VERSION")); - fprintf(out_h, "\n"); - } - - if (!sym_change_count) - sym_clear_all_valid(); - - menu = rootmenu.list; - while (menu) { - sym = menu->sym; - if (!sym) { - if (!menu_is_visible(menu)) - goto next; - str = menu_get_prompt(menu); - fprintf(out, "\n" - "#\n" - "# %s\n" - "#\n", str); - if (out_h) - fprintf(out_h, "\n" - "/*\n" - " * %s\n" - " */\n", str); - } else if (!(sym->flags & SYMBOL_CHOICE)) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE) && !output_mode) - goto next; - sym->flags &= ~SYMBOL_WRITE; - type = sym->type; - if (type == S_TRISTATE) { - sym_calc_value(modules_sym); - if (modules_sym->curr.tri == no) - type = S_BOOLEAN; - } - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (sym_get_tristate_value(sym)) { - case no: - fprintf(out, "# %s is not set\n", sym->name); - if (out_h) - fprintf(out_h, "#undef %s\n", sym->name); - break; - case mod: - fprintf(out, "%s=m\n", sym->name); -#if 0 - if (out_h) - fprintf(out_h, "#define %s_MODULE 1\n", sym->name); -#endif - break; - case yes: - fprintf(out, "%s=y\n", sym->name); - if (out_h) - fprintf(out_h, "#define %s 1\n", sym->name); - break; - } - break; - case S_STRING: - // fix me - str = sym_get_string_value(sym); - fprintf(out, "%s=\"", sym->name); - if (out_h) - fprintf(out_h, "#define %s \"", sym->name); - do { - l = strcspn(str, "\"\\"); - if (l) { - fwrite(str, l, 1, out); - if (out_h) - fwrite(str, l, 1, out_h); - } - str += l; - while (*str == '\\' || *str == '"') { - fprintf(out, "\\%c", *str); - if (out_h) - fprintf(out_h, "\\%c", *str); - str++; - } - } while (*str); - fputs("\"\n", out); - if (out_h) - fputs("\"\n", out_h); - break; - case S_HEX: - str = sym_get_string_value(sym); - if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { - fprintf(out, "%s=%s\n", sym->name, str); - if (out_h) - fprintf(out_h, "#define %s 0x%s\n", sym->name, str); - break; - } - case S_INT: - str = sym_get_string_value(sym); - fprintf(out, "%s=%s\n", sym->name, str); - if (out_h) - fprintf(out_h, "#define %s %s\n", sym->name, str); - break; - } - } - - next: - if (menu->list) { - menu = menu->list; - continue; - } - if (menu->next) - menu = menu->next; - else while ((menu = menu->parent)) { - if (menu->next) { - menu = menu->next; - break; - } - } - } - fclose(out); - if (out_h) { - fclose(out_h); - rename(".tmpconfig.h", "include/config.h"); - file_write_dep(NULL); - } - if (!name || basename != conf_def_filename) { - if (!name) - name = conf_def_filename; - sprintf(tmpname, "%s.old", name); - rename(name, tmpname); - } - sprintf(tmpname, "%s%s", dirname, basename); - if (rename(newname, tmpname)) - return 1; - - sym_change_count = 0; - - return 0; -} diff --git a/config/dialog.h b/config/dialog.h deleted file mode 100644 index 6486cc8f7..000000000 --- a/config/dialog.h +++ /dev/null @@ -1,196 +0,0 @@ - -/* - * dialog.h -- common declarations for all dialog modules - * - * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef CURSES_LOC -#include CURSES_LOC - -/* - * Colors in ncurses 1.9.9e do not work properly since foreground and - * background colors are OR'd rather than separately masked. This version - * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible - * with standard curses. The simplest fix (to make this work with standard - * curses) uses the wbkgdset() function, not used in the original hack. - * Turn it off if we're building with 1.9.9e, since it just confuses things. - */ -#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) -#define OLD_NCURSES 1 -#undef wbkgdset -#define wbkgdset(w,p) /*nothing*/ -#else -#define OLD_NCURSES 0 -#endif - -#define TR(params) _tracef params - -#define ESC 27 -#define TAB 9 -#define MAX_LEN 2048 -#define BUF_SIZE (10*1024) -#define MIN(x,y) (x < y ? x : y) -#define MAX(x,y) (x > y ? x : y) - - -#ifndef ACS_ULCORNER -#define ACS_ULCORNER '+' -#endif -#ifndef ACS_LLCORNER -#define ACS_LLCORNER '+' -#endif -#ifndef ACS_URCORNER -#define ACS_URCORNER '+' -#endif -#ifndef ACS_LRCORNER -#define ACS_LRCORNER '+' -#endif -#ifndef ACS_HLINE -#define ACS_HLINE '-' -#endif -#ifndef ACS_VLINE -#define ACS_VLINE '|' -#endif -#ifndef ACS_LTEE -#define ACS_LTEE '+' -#endif -#ifndef ACS_RTEE -#define ACS_RTEE '+' -#endif -#ifndef ACS_UARROW -#define ACS_UARROW '^' -#endif -#ifndef ACS_DARROW -#define ACS_DARROW 'v' -#endif - -/* - * Attribute names - */ -#define screen_attr attributes[0] -#define shadow_attr attributes[1] -#define dialog_attr attributes[2] -#define title_attr attributes[3] -#define border_attr attributes[4] -#define button_active_attr attributes[5] -#define button_inactive_attr attributes[6] -#define button_key_active_attr attributes[7] -#define button_key_inactive_attr attributes[8] -#define button_label_active_attr attributes[9] -#define button_label_inactive_attr attributes[10] -#define inputbox_attr attributes[11] -#define inputbox_border_attr attributes[12] -#define searchbox_attr attributes[13] -#define searchbox_title_attr attributes[14] -#define searchbox_border_attr attributes[15] -#define position_indicator_attr attributes[16] -#define menubox_attr attributes[17] -#define menubox_border_attr attributes[18] -#define item_attr attributes[19] -#define item_selected_attr attributes[20] -#define tag_attr attributes[21] -#define tag_selected_attr attributes[22] -#define tag_key_attr attributes[23] -#define tag_key_selected_attr attributes[24] -#define check_attr attributes[25] -#define check_selected_attr attributes[26] -#define uarrow_attr attributes[27] -#define darrow_attr attributes[28] - -/* number of attributes */ -#define ATTRIBUTE_COUNT 29 - -/* - * Global variables - */ -extern bool use_colors; - -extern chtype attributes[]; -#endif - -extern char *backtitle; - -struct dialog_list_item { - char *name; - int namelen; - char *tag; - int selected; /* Set to 1 by dialog_*() function. */ -}; - -/* - * Function prototypes - */ - -void init_dialog (void); -void end_dialog (void); -void dialog_clear (void); -#ifdef CURSES_LOC -void attr_clear (WINDOW * win, int height, int width, chtype attr); -void color_setup (void); -void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x); -void print_button (WINDOW * win, const char *label, int y, int x, int selected); -void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box, - chtype border); -void draw_shadow (WINDOW * win, int y, int x, int height, int width); -#endif - -int first_alpha (const char *string, const char *exempt); -int dialog_yesno (const char *title, const char *prompt, int height, int width); -int dialog_msgbox (const char *title, const char *prompt, int height, - int width, int pause); -int dialog_textbox (const char *title, const char *file, int height, int width); -int dialog_menu (const char *title, const char *prompt, int height, int width, - int menu_height, const char *choice, int item_no, - struct dialog_list_item ** items); -int dialog_checklist (const char *title, const char *prompt, int height, - int width, int list_height, int item_no, - struct dialog_list_item ** items, int flag); -extern unsigned char dialog_input_result[]; -int dialog_inputbox (const char *title, const char *prompt, int height, - int width, const char *init); - -struct dialog_list_item *first_sel_item(int item_no, - struct dialog_list_item ** items); - -/* - * This is the base for fictitious keys, which activate - * the buttons. - * - * Mouse-generated keys are the following: - * -- the first 32 are used as numbers, in addition to '0'-'9' - * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') - * -- uppercase chars are used to invoke the button (M_EVENT + 'O') - */ -#ifdef CURSES_LOC -#define M_EVENT (KEY_MAX+1) -#endif - - -/* - * The `flag' parameter in checklist is used to select between - * radiolist and checklist - */ -#define FLAG_CHECK 1 -#define FLAG_RADIO 0 diff --git a/config/expr.c b/config/expr.c deleted file mode 100644 index 10f45232b..000000000 --- a/config/expr.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -#define DEBUG_EXPR 0 - -struct expr *expr_alloc_symbol(struct symbol *sym) -{ - struct expr *e = malloc(sizeof(*e)); - memset(e, 0, sizeof(*e)); - e->type = E_SYMBOL; - e->left.sym = sym; - return e; -} - -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) -{ - struct expr *e = malloc(sizeof(*e)); - memset(e, 0, sizeof(*e)); - e->type = type; - e->left.expr = ce; - return e; -} - -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) -{ - struct expr *e = malloc(sizeof(*e)); - memset(e, 0, sizeof(*e)); - e->type = type; - e->left.expr = e1; - e->right.expr = e2; - return e; -} - -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) -{ - struct expr *e = malloc(sizeof(*e)); - memset(e, 0, sizeof(*e)); - e->type = type; - e->left.sym = s1; - e->right.sym = s2; - return e; -} - -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; -} - -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; -} - -struct expr *expr_copy(struct expr *org) -{ - struct expr *e; - - if (!org) - return NULL; - - e = malloc(sizeof(*org)); - memcpy(e, org, sizeof(*org)); - switch (org->type) { - case E_SYMBOL: - e->left = org->left; - break; - case E_NOT: - e->left.expr = expr_copy(org->left.expr); - break; - case E_EQUAL: - case E_UNEQUAL: - e->left.sym = org->left.sym; - e->right.sym = org->right.sym; - break; - case E_AND: - case E_OR: - case E_CHOICE: - e->left.expr = expr_copy(org->left.expr); - e->right.expr = expr_copy(org->right.expr); - break; - default: - printf("can't copy type %d\n", e->type); - free(e); - e = NULL; - break; - } - - return e; -} - -void expr_free(struct expr *e) -{ - if (!e) - return; - - switch (e->type) { - case E_SYMBOL: - break; - case E_NOT: - expr_free(e->left.expr); - return; - case E_EQUAL: - case E_UNEQUAL: - break; - case E_OR: - case E_AND: - expr_free(e->left.expr); - expr_free(e->right.expr); - break; - default: - printf("how to free type %d?\n", e->type); - break; - } - free(e); -} - -static int trans_count; - -#define e1 (*ep1) -#define e2 (*ep2) - -static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ - if (e1->type == type) { - __expr_eliminate_eq(type, &e1->left.expr, &e2); - __expr_eliminate_eq(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - __expr_eliminate_eq(type, &e1, &e2->left.expr); - __expr_eliminate_eq(type, &e1, &e2->right.expr); - return; - } - if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO))) - return; - if (!expr_eq(e1, e2)) - return; - trans_count++; - expr_free(e1); expr_free(e2); - switch (type) { - case E_OR: - e1 = expr_alloc_symbol(&symbol_no); - e2 = expr_alloc_symbol(&symbol_no); - break; - case E_AND: - e1 = expr_alloc_symbol(&symbol_yes); - e2 = expr_alloc_symbol(&symbol_yes); - break; - default: - ; - } -} - -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) -{ - if (!e1 || !e2) - return; - switch (e1->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e1->type, ep1, ep2); - default: - ; - } - if (e1->type != e2->type) switch (e2->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e2->type, ep1, ep2); - default: - ; - } - e1 = expr_eliminate_yn(e1); - e2 = expr_eliminate_yn(e2); -} - -#undef e1 -#undef e2 - -int expr_eq(struct expr *e1, struct expr *e2) -{ - int res, old_count; - - if (e1->type != e2->type) - return 0; - switch (e1->type) { - case E_EQUAL: - case E_UNEQUAL: - return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; - case E_SYMBOL: - return e1->left.sym == e2->left.sym; - case E_NOT: - return expr_eq(e1->left.expr, e2->left.expr); - case E_AND: - case E_OR: - e1 = expr_copy(e1); - e2 = expr_copy(e2); - old_count = trans_count; - expr_eliminate_eq(&e1, &e2); - res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym); - expr_free(e1); - expr_free(e2); - trans_count = old_count; - return res; - case E_CHOICE: - case E_RANGE: - case E_NONE: - /* panic */; - } - - if (DEBUG_EXPR) { - expr_fprint(e1, stdout); - printf(" = "); - expr_fprint(e2, stdout); - printf(" ?\n"); - } - - return 0; -} - -struct expr *expr_eliminate_yn(struct expr *e) -{ - struct expr *tmp; - - if (e) switch (e->type) { - case E_AND: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } - } - break; - case E_OR: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - break; - default: - ; - } - return e; -} - -/* - * bool FOO!=n => FOO - */ -struct expr *expr_trans_bool(struct expr *e) -{ - if (!e) - return NULL; - switch (e->type) { - case E_AND: - case E_OR: - case E_NOT: - e->left.expr = expr_trans_bool(e->left.expr); - e->right.expr = expr_trans_bool(e->right.expr); - break; - case E_UNEQUAL: - // FOO!=n -> FOO - if (e->left.sym->type == S_TRISTATE) { - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - } - } - break; - default: - ; - } - return e; -} - -/* - * e1 || e2 -> ? - */ -struct expr *expr_join_or(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='m') -> (a!='n') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='n') -> (a!='m') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { - // (a='m') || (a='n') -> (a!='y') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); - } - } - if (sym1->type == S_BOOLEAN && sym1 == sym2) { - if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || - (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) - return expr_alloc_symbol(&symbol_yes); - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") || ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -struct expr *expr_join_and(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) - // (a) && (a='y') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) - // (a) && (a!='n') -> (a) - return expr_alloc_symbol(sym1); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) - // (a) && (a!='m') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e1->right.sym; - if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e2->right.sym; - if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='m') -> (a='n') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) - // (a!='m') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || - (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) - return NULL; - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") && ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ -#define e1 (*ep1) -#define e2 (*ep2) - struct expr *tmp; - - if (e1->type == type) { - expr_eliminate_dups1(type, &e1->left.expr, &e2); - expr_eliminate_dups1(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - expr_eliminate_dups1(type, &e1, &e2->left.expr); - expr_eliminate_dups1(type, &e1, &e2->right.expr); - return; - } - if (e1 == e2) - return; - - switch (e1->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e1->type, &e1, &e1); - default: - ; - } - - switch (type) { - case E_OR: - tmp = expr_join_or(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_no); - e2 = tmp; - trans_count++; - } - break; - case E_AND: - tmp = expr_join_and(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_yes); - e2 = tmp; - trans_count++; - } - break; - default: - ; - } -#undef e1 -#undef e2 -} - -static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ -#define e1 (*ep1) -#define e2 (*ep2) - struct expr *tmp, *tmp1, *tmp2; - - if (e1->type == type) { - expr_eliminate_dups2(type, &e1->left.expr, &e2); - expr_eliminate_dups2(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - expr_eliminate_dups2(type, &e1, &e2->left.expr); - expr_eliminate_dups2(type, &e1, &e2->right.expr); - } - if (e1 == e2) - return; - - switch (e1->type) { - case E_OR: - expr_eliminate_dups2(e1->type, &e1, &e1); - // (FOO || BAR) && (!FOO && !BAR) -> n - tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); - tmp2 = expr_copy(e2); - tmp = expr_extract_eq_and(&tmp1, &tmp2); - if (expr_is_yes(tmp1)) { - expr_free(e1); - e1 = expr_alloc_symbol(&symbol_no); - trans_count++; - } - expr_free(tmp2); - expr_free(tmp1); - expr_free(tmp); - break; - case E_AND: - expr_eliminate_dups2(e1->type, &e1, &e1); - // (FOO && BAR) || (!FOO || !BAR) -> y - tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); - tmp2 = expr_copy(e2); - tmp = expr_extract_eq_or(&tmp1, &tmp2); - if (expr_is_no(tmp1)) { - expr_free(e1); - e1 = expr_alloc_symbol(&symbol_yes); - trans_count++; - } - expr_free(tmp2); - expr_free(tmp1); - expr_free(tmp); - break; - default: - ; - } -#undef e1 -#undef e2 -} - -struct expr *expr_eliminate_dups(struct expr *e) -{ - int oldcount; - if (!e) - return e; - - oldcount = trans_count; - while (1) { - trans_count = 0; - switch (e->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e->type, &e, &e); - expr_eliminate_dups2(e->type, &e, &e); - default: - ; - } - if (!trans_count) - break; - e = expr_eliminate_yn(e); - } - trans_count = oldcount; - return e; -} - -struct expr *expr_transform(struct expr *e) -{ - struct expr *tmp; - - if (!e) - return NULL; - switch (e->type) { - case E_EQUAL: - case E_UNEQUAL: - case E_SYMBOL: - case E_CHOICE: - break; - default: - e->left.expr = expr_transform(e->left.expr); - e->right.expr = expr_transform(e->right.expr); - } - - switch (e->type) { - case E_EQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - break; - case E_UNEQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - break; - case E_NOT: - switch (e->left.expr->type) { - case E_NOT: - // !!a -> a - tmp = e->left.expr->left.expr; - free(e->left.expr); - free(e); - e = tmp; - e = expr_transform(e); - break; - case E_EQUAL: - case E_UNEQUAL: - // !a='x' -> a!='x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; - break; - case E_OR: - // !(a || b) -> !a && !b - tmp = e->left.expr; - e->type = E_AND; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_AND: - // !(a && b) -> !a || !b - tmp = e->left.expr; - e->type = E_OR; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_SYMBOL: - if (e->left.expr->left.sym == &symbol_yes) { - // !'y' -> 'n' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - break; - } - if (e->left.expr->left.sym == &symbol_mod) { - // !'m' -> 'm' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_mod; - break; - } - if (e->left.expr->left.sym == &symbol_no) { - // !'n' -> 'y' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - break; - } - break; - default: - ; - } - break; - default: - ; - } - return e; -} - -int expr_contains_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return 0; - - switch (dep->type) { - case E_AND: - case E_OR: - return expr_contains_symbol(dep->left.expr, sym) || - expr_contains_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - case E_UNEQUAL: - return dep->left.sym == sym || - dep->right.sym == sym; - case E_NOT: - return expr_contains_symbol(dep->left.expr, sym); - default: - ; - } - return 0; -} - -bool expr_depends_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return false; - - switch (dep->type) { - case E_AND: - return expr_depends_symbol(dep->left.expr, sym) || - expr_depends_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) - return true; - } - break; - case E_UNEQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_no) - return true; - } - break; - default: - ; - } - return false; -} - -struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) -{ - struct expr *tmp = NULL; - expr_extract_eq(E_AND, &tmp, ep1, ep2); - if (tmp) { - *ep1 = expr_eliminate_yn(*ep1); - *ep2 = expr_eliminate_yn(*ep2); - } - return tmp; -} - -struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) -{ - struct expr *tmp = NULL; - expr_extract_eq(E_OR, &tmp, ep1, ep2); - if (tmp) { - *ep1 = expr_eliminate_yn(*ep1); - *ep2 = expr_eliminate_yn(*ep2); - } - return tmp; -} - -void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) -{ -#define e1 (*ep1) -#define e2 (*ep2) - if (e1->type == type) { - expr_extract_eq(type, ep, &e1->left.expr, &e2); - expr_extract_eq(type, ep, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - expr_extract_eq(type, ep, ep1, &e2->left.expr); - expr_extract_eq(type, ep, ep1, &e2->right.expr); - return; - } - if (expr_eq(e1, e2)) { - *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; - expr_free(e2); - if (type == E_AND) { - e1 = expr_alloc_symbol(&symbol_yes); - e2 = expr_alloc_symbol(&symbol_yes); - } else if (type == E_OR) { - e1 = expr_alloc_symbol(&symbol_no); - e2 = expr_alloc_symbol(&symbol_no); - } - } -#undef e1 -#undef e2 -} - -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) -{ - struct expr *e1, *e2; - - if (!e) { - e = expr_alloc_symbol(sym); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - } - switch (e->type) { - case E_AND: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_AND, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_OR, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_OR: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_OR, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_AND, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_NOT: - return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); - case E_UNEQUAL: - case E_EQUAL: - if (type == E_EQUAL) { - if (sym == &symbol_yes) - return expr_copy(e); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_no); - if (sym == &symbol_no) - return expr_alloc_one(E_NOT, expr_copy(e)); - } else { - if (sym == &symbol_yes) - return expr_alloc_one(E_NOT, expr_copy(e)); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_yes); - if (sym == &symbol_no) - return expr_copy(e); - } - break; - case E_SYMBOL: - return expr_alloc_comp(type, e->left.sym, sym); - case E_CHOICE: - case E_RANGE: - case E_NONE: - /* panic */; - } - return NULL; -} - -tristate expr_calc_value(struct expr *e) -{ - tristate val1, val2; - const char *str1, *str2; - - if (!e) - return yes; - - switch (e->type) { - case E_SYMBOL: - sym_calc_value(e->left.sym); - return e->left.sym->curr.tri; - case E_AND: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return E_AND(val1, val2); - case E_OR: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return E_OR(val1, val2); - case E_NOT: - val1 = expr_calc_value(e->left.expr); - return E_NOT(val1); - case E_EQUAL: - sym_calc_value(e->left.sym); - sym_calc_value(e->right.sym); - str1 = sym_get_string_value(e->left.sym); - str2 = sym_get_string_value(e->right.sym); - return !strcmp(str1, str2) ? yes : no; - case E_UNEQUAL: - sym_calc_value(e->left.sym); - sym_calc_value(e->right.sym); - str1 = sym_get_string_value(e->left.sym); - str2 = sym_get_string_value(e->right.sym); - return !strcmp(str1, str2) ? no : yes; - default: - printf("expr_calc_value: %d?\n", e->type); - return no; - } -} - -int expr_compare_type(enum expr_type t1, enum expr_type t2) -{ -#if 0 - return 1; -#else - if (t1 == t2) - return 0; - switch (t1) { - case E_EQUAL: - case E_UNEQUAL: - if (t2 == E_NOT) - return 1; - case E_NOT: - if (t2 == E_AND) - return 1; - case E_AND: - if (t2 == E_OR) - return 1; - case E_OR: - if (t2 == E_CHOICE) - return 1; - case E_CHOICE: - if (t2 == 0) - return 1; - default: - return -1; - } - printf("[%dgt%d?]", t1, t2); - return 0; -#endif -} - -void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken) -{ - if (!e) { - fn(data, "y"); - return; - } - - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, "("); - switch (e->type) { - case E_SYMBOL: - if (e->left.sym->name) - fn(data, e->left.sym->name); - else - fn(data, ""); - break; - case E_NOT: - fn(data, "!"); - expr_print(e->left.expr, fn, data, E_NOT); - break; - case E_EQUAL: - fn(data, e->left.sym->name); - fn(data, "="); - fn(data, e->right.sym->name); - break; - case E_UNEQUAL: - fn(data, e->left.sym->name); - fn(data, "!="); - fn(data, e->right.sym->name); - break; - case E_OR: - expr_print(e->left.expr, fn, data, E_OR); - fn(data, " || "); - expr_print(e->right.expr, fn, data, E_OR); - break; - case E_AND: - expr_print(e->left.expr, fn, data, E_AND); - fn(data, " && "); - expr_print(e->right.expr, fn, data, E_AND); - break; - case E_CHOICE: - fn(data, e->right.sym->name); - if (e->left.expr) { - fn(data, " ^ "); - expr_print(e->left.expr, fn, data, E_CHOICE); - } - break; - case E_RANGE: - fn(data, "["); - fn(data, e->left.sym->name); - fn(data, " "); - fn(data, e->right.sym->name); - fn(data, "]"); - break; - default: - { - char buf[32]; - sprintf(buf, "", e->type); - fn(data, buf); - break; - } - } - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, ")"); -} - -static void expr_print_file_helper(void *data, const char *str) -{ - fwrite(str, strlen(str), 1, data); -} - -void expr_fprint(struct expr *e, FILE *out) -{ - expr_print(e, expr_print_file_helper, out, E_NONE); -} diff --git a/config/expr.h b/config/expr.h deleted file mode 100644 index 3010013b2..000000000 --- a/config/expr.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef EXPR_H -#define EXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#ifndef __cplusplus -#include -#endif - -struct file { - struct file *next; - struct file *parent; - char *name; - int lineno; - int flags; -}; - -#define FILE_BUSY 0x0001 -#define FILE_SCANNED 0x0002 -#define FILE_PRINTED 0x0004 - -typedef enum tristate { - no, mod, yes -} tristate; - -enum expr_type { - E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE -}; - -union expr_data { - struct expr *expr; - struct symbol *sym; -}; - -struct expr { - enum expr_type type; - union expr_data left, right; -}; - -#define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) -#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) -#define E_NOT(dep) (2-(dep)) - -struct expr_value { - struct expr *expr; - tristate tri; -}; - -struct symbol_value { - void *val; - tristate tri; -}; - -enum symbol_type { - S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER -}; - -struct symbol { - struct symbol *next; - char *name; - char *help; - enum symbol_type type; - struct symbol_value curr, user; - tristate visible; - int flags; - struct property *prop; - struct expr *dep, *dep2; - struct expr_value rev_dep; - struct expr_value rev_dep_inv; -}; - -#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) - -#define SYMBOL_YES 0x0001 -#define SYMBOL_MOD 0x0002 -#define SYMBOL_NO 0x0004 -#define SYMBOL_CONST 0x0007 -#define SYMBOL_CHECK 0x0008 -#define SYMBOL_CHOICE 0x0010 -#define SYMBOL_CHOICEVAL 0x0020 -#define SYMBOL_PRINTED 0x0040 -#define SYMBOL_VALID 0x0080 -#define SYMBOL_OPTIONAL 0x0100 -#define SYMBOL_WRITE 0x0200 -#define SYMBOL_CHANGED 0x0400 -#define SYMBOL_NEW 0x0800 -#define SYMBOL_AUTO 0x1000 -#define SYMBOL_CHECKED 0x2000 -#define SYMBOL_CHECK_DONE 0x4000 -#define SYMBOL_WARNED 0x8000 - -#define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 257 -#define SYMBOL_HASHMASK 0xff - -enum prop_type { - P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_SELECTNOT, P_RANGE -}; - -struct property { - struct property *next; - struct symbol *sym; - enum prop_type type; - const char *text; - struct expr_value visible; - struct expr *expr; - struct menu *menu; - struct file *file; - int lineno; -}; - -#define for_all_properties(sym, st, tok) \ - for (st = sym->prop; st; st = st->next) \ - if (st->type == (tok)) -#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) -#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) -#define for_all_prompts(sym, st) \ - for (st = sym->prop; st; st = st->next) \ - if (st->text) - -struct menu { - struct menu *next; - struct menu *parent; - struct menu *list; - struct symbol *sym; - struct property *prompt; - struct expr *dep; - unsigned int flags; - //char *help; - struct file *file; - int lineno; - void *data; -}; - -#define MENU_CHANGED 0x0001 -#define MENU_ROOT 0x0002 - -#ifndef SWIG - -extern struct file *file_list; -extern struct file *current_file; -struct file *lookup_file(const char *name); - -extern struct symbol symbol_yes, symbol_no, symbol_mod; -extern struct symbol *modules_sym; -extern int cdebug; -struct expr *expr_alloc_symbol(struct symbol *sym); -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); -struct expr *expr_copy(struct expr *org); -void expr_free(struct expr *e); -int expr_eq(struct expr *e1, struct expr *e2); -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); -tristate expr_calc_value(struct expr *e); -struct expr *expr_eliminate_yn(struct expr *e); -struct expr *expr_trans_bool(struct expr *e); -struct expr *expr_eliminate_dups(struct expr *e); -struct expr *expr_transform(struct expr *e); -int expr_contains_symbol(struct expr *dep, struct symbol *sym); -bool expr_depends_symbol(struct expr *dep, struct symbol *sym); -struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); -struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); -void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); - -void expr_fprint(struct expr *e, FILE *out); - -static inline int expr_is_yes(struct expr *e) -{ - return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); -} - -static inline int expr_is_no(struct expr *e) -{ - return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* EXPR_H */ diff --git a/config/glob.c b/config/glob.c deleted file mode 100644 index b8928b1b6..000000000 --- a/config/glob.c +++ /dev/null @@ -1,848 +0,0 @@ -/* $OpenBSD: glob.c,v 1.25 2005/08/08 08:05:34 espie Exp $ */ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * glob(3) -- a superset of the one defined in POSIX 1003.2. - * - * The [!...] convention to negate a range is supported (SysV, Posix, ksh). - * - * Optional extra services, controlled by flags not defined by POSIX: - * - * GLOB_QUOTE: - * Escaping convention: \ inhibits any special meaning the following - * character might have (except \ at end of string is retained). - * GLOB_MAGCHAR: - * Set in gl_flags if pattern contained a globbing character. - * GLOB_NOMAGIC: - * Same as GLOB_NOCHECK, but it will only append pattern if it did - * not contain any magic characters. [Used in csh style globbing] - * GLOB_ALTDIRFUNC: - * Use alternately specified directory access functions. - * GLOB_TILDE: - * expand ~user/foo to the /home/dir/of/user/foo - * GLOB_BRACE: - * expand {1,2}{a,b} to 1a 1b 2a 2b - * gl_matchc: - * Number of matches in the current invocation of glob. - */ - -#ifdef __APPLE__ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DOLLAR '$' -#define DOT '.' -#define EOS '\0' -#define LBRACKET '[' -#define NOT '!' -#define QUESTION '?' -#define QUOTE '\\' -#define RANGE '-' -#define RBRACKET ']' -#define SEP '/' -#define STAR '*' -#define TILDE '~' -#define UNDERSCORE '_' -#define LBRACE '{' -#define RBRACE '}' -#define SLASH '/' -#define COMMA ',' - -#ifndef DEBUG - -#define M_QUOTE 0x8000 -#define M_PROTECT 0x4000 -#define M_MASK 0xffff -#define M_ASCII 0x00ff - -typedef u_short Char; - -#else - -#define M_QUOTE 0x80 -#define M_PROTECT 0x40 -#define M_MASK 0xff -#define M_ASCII 0x7f - -typedef char Char; - -#endif - - -#define CHAR(c) ((Char)((c)&M_ASCII)) -#define META(c) ((Char)((c)|M_QUOTE)) -#define M_ALL META('*') -#define M_END META(']') -#define M_NOT META('!') -#define M_ONE META('?') -#define M_RNG META('-') -#define M_SET META('[') -#define ismeta(c) (((c)&M_QUOTE) != 0) - - -static int compare(const void *, const void *); -static int g_Ctoc(const Char *, char *, u_int); -static int g_lstat(Char *, struct stat *, glob_t *); -static DIR *g_opendir(Char *, glob_t *); -static const Char *g_strchr(const Char *, int); -static int g_stat(Char *, struct stat *, glob_t *); -static int glob0(const Char *, glob_t *); -static int glob1(Char *, Char *, glob_t *, size_t *); -static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, - glob_t *, size_t *); -static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, - Char *, Char *, glob_t *, size_t *); -static int globextend(const Char *, glob_t *, size_t *); -static const Char * - globtilde(const Char *, Char *, size_t, glob_t *); -static int globexp1(const Char *, glob_t *); -static int globexp2(const Char *, const Char *, glob_t *, int *); -static int match(Char *, Char *, Char *); -#ifdef DEBUG -static void qprintf(const char *, Char *); -#endif - -int -glob(const char *pattern, int flags, int (*errfunc)(const char *, int), - glob_t *pglob) -{ - const u_char *patnext; - int c; - Char *bufnext, *bufend, patbuf[MAXPATHLEN]; - - patnext = (const u_char *) pattern; - if (!(flags & GLOB_APPEND)) { - pglob->gl_pathc = 0; - pglob->gl_pathv = NULL; - if (!(flags & GLOB_DOOFFS)) - pglob->gl_offs = 0; - } - pglob->gl_flags = flags & ~GLOB_MAGCHAR; - pglob->gl_errfunc = errfunc; - pglob->gl_matchc = 0; - - bufnext = patbuf; - bufend = bufnext + MAXPATHLEN - 1; - if (flags & GLOB_NOESCAPE) - while (bufnext < bufend && (c = *patnext++) != EOS) - *bufnext++ = c; - else { - /* Protect the quoted characters. */ - while (bufnext < bufend && (c = *patnext++) != EOS) - if (c == QUOTE) { - if ((c = *patnext++) == EOS) { - c = QUOTE; - --patnext; - } - *bufnext++ = c | M_PROTECT; - } else - *bufnext++ = c; - } - *bufnext = EOS; - - if (flags & GLOB_BRACE) - return globexp1(patbuf, pglob); - else - return glob0(patbuf, pglob); -} - -/* - * Expand recursively a glob {} pattern. When there is no more expansion - * invoke the standard globbing routine to glob the rest of the magic - * characters - */ -static int -globexp1(const Char *pattern, glob_t *pglob) -{ - const Char* ptr = pattern; - int rv; - - /* Protect a single {}, for find(1), like csh */ - if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) - return glob0(pattern, pglob); - - while ((ptr = g_strchr(ptr, LBRACE)) != NULL) - if (!globexp2(ptr, pattern, pglob, &rv)) - return rv; - - return glob0(pattern, pglob); -} - - -/* - * Recursive brace globbing helper. Tries to expand a single brace. - * If it succeeds then it invokes globexp1 with the new pattern. - * If it fails then it tries to glob the rest of the pattern and returns. - */ -static int -globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv) -{ - int i; - Char *lm, *ls; - const Char *pe, *pm, *pl; - Char patbuf[MAXPATHLEN]; - - /* copy part up to the brace */ - for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) - ; - *lm = EOS; - ls = lm; - - /* Find the balanced brace */ - for (i = 0, pe = ++ptr; *pe; pe++) - if (*pe == LBRACKET) { - /* Ignore everything between [] */ - for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) - ; - if (*pe == EOS) { - /* - * We could not find a matching RBRACKET. - * Ignore and just look for RBRACE - */ - pe = pm; - } - } else if (*pe == LBRACE) - i++; - else if (*pe == RBRACE) { - if (i == 0) - break; - i--; - } - - /* Non matching braces; just glob the pattern */ - if (i != 0 || *pe == EOS) { - *rv = glob0(patbuf, pglob); - return 0; - } - - for (i = 0, pl = pm = ptr; pm <= pe; pm++) { - switch (*pm) { - case LBRACKET: - /* Ignore everything between [] */ - for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) - ; - if (*pm == EOS) { - /* - * We could not find a matching RBRACKET. - * Ignore and just look for RBRACE - */ - pm = pl; - } - break; - - case LBRACE: - i++; - break; - - case RBRACE: - if (i) { - i--; - break; - } - /* FALLTHROUGH */ - case COMMA: - if (i && *pm == COMMA) - break; - else { - /* Append the current string */ - for (lm = ls; (pl < pm); *lm++ = *pl++) - ; - - /* - * Append the rest of the pattern after the - * closing brace - */ - for (pl = pe + 1; (*lm++ = *pl++) != EOS; ) - ; - - /* Expand the current pattern */ -#ifdef DEBUG - qprintf("globexp2:", patbuf); -#endif - *rv = globexp1(patbuf, pglob); - - /* move after the comma, to the next string */ - pl = pm + 1; - } - break; - - default: - break; - } - } - *rv = 0; - return 0; -} - - - -/* - * expand tilde from the passwd file. - */ -static const Char * -globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) -{ - struct passwd *pwd; - char *h; - const Char *p; - Char *b, *eb; - - if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) - return pattern; - - /* Copy up to the end of the string or / */ - eb = &patbuf[patbuf_len - 1]; - for (p = pattern + 1, h = (char *) patbuf; - h < (char *)eb && *p && *p != SLASH; *h++ = *p++) - ; - - *h = EOS; - -#if 0 - if (h == (char *)eb) - return what; -#endif - - if (((char *) patbuf)[0] == EOS) { - /* - * handle a plain ~ or ~/ by expanding $HOME - * first and then trying the password file - */ - if (issetugid() != 0 || (h = getenv("HOME")) == NULL) { - if ((pwd = getpwuid(getuid())) == NULL) - return pattern; - else - h = pwd->pw_dir; - } - } else { - /* - * Expand a ~user - */ - if ((pwd = getpwnam((char*) patbuf)) == NULL) - return pattern; - else - h = pwd->pw_dir; - } - - /* Copy the home directory */ - for (b = patbuf; b < eb && *h; *b++ = *h++) - ; - - /* Append the rest of the pattern */ - while (b < eb && (*b++ = *p++) != EOS) - ; - *b = EOS; - - return patbuf; -} - - -/* - * The main glob() routine: compiles the pattern (optionally processing - * quotes), calls glob1() to do the real pattern matching, and finally - * sorts the list (unless unsorted operation is requested). Returns 0 - * if things went well, nonzero if errors occurred. It is not an error - * to find no matches. - */ -static int -glob0(const Char *pattern, glob_t *pglob) -{ - const Char *qpatnext; - int c, err, oldpathc; - Char *bufnext, patbuf[MAXPATHLEN]; - size_t limit = 0; - - qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); - oldpathc = pglob->gl_pathc; - bufnext = patbuf; - - /* We don't need to check for buffer overflow any more. */ - while ((c = *qpatnext++) != EOS) { - switch (c) { - case LBRACKET: - c = *qpatnext; - if (c == NOT) - ++qpatnext; - if (*qpatnext == EOS || - g_strchr(qpatnext+1, RBRACKET) == NULL) { - *bufnext++ = LBRACKET; - if (c == NOT) - --qpatnext; - break; - } - *bufnext++ = M_SET; - if (c == NOT) - *bufnext++ = M_NOT; - c = *qpatnext++; - do { - *bufnext++ = CHAR(c); - if (*qpatnext == RANGE && - (c = qpatnext[1]) != RBRACKET) { - *bufnext++ = M_RNG; - *bufnext++ = CHAR(c); - qpatnext += 2; - } - } while ((c = *qpatnext++) != RBRACKET); - pglob->gl_flags |= GLOB_MAGCHAR; - *bufnext++ = M_END; - break; - case QUESTION: - pglob->gl_flags |= GLOB_MAGCHAR; - *bufnext++ = M_ONE; - break; - case STAR: - pglob->gl_flags |= GLOB_MAGCHAR; - /* collapse adjacent stars to one, - * to avoid exponential behavior - */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) - *bufnext++ = M_ALL; - break; - default: - *bufnext++ = CHAR(c); - break; - } - } - *bufnext = EOS; -#ifdef DEBUG - qprintf("glob0:", patbuf); -#endif - - if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0) - return(err); - - /* - * If there was no match we are going to append the pattern - * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified - * and the pattern did not contain any magic characters - * GLOB_NOMAGIC is there just for compatibility with csh. - */ - if (pglob->gl_pathc == oldpathc) { - if ((pglob->gl_flags & GLOB_NOCHECK) || - ((pglob->gl_flags & GLOB_NOMAGIC) && - !(pglob->gl_flags & GLOB_MAGCHAR))) - return(globextend(pattern, pglob, &limit)); - else - return(GLOB_NOMATCH); - } - if (!(pglob->gl_flags & GLOB_NOSORT)) - qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, - pglob->gl_pathc - oldpathc, sizeof(char *), compare); - return(0); -} - -static int -compare(const void *p, const void *q) -{ - return(strcmp(*(char *const *)p, *(char *const *)q)); -} - -static int -glob1(Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp) -{ - Char pathbuf[MAXPATHLEN]; - - /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ - if (*pattern == EOS) - return(0); - return(glob2(pathbuf, pathbuf+MAXPATHLEN-1, - pathbuf, pathbuf+MAXPATHLEN-1, - pattern, pattern_last, pglob, limitp)); -} - -/* - * The functions glob2 and glob3 are mutually recursive; there is one level - * of recursion for each segment in the pattern that contains one or more - * meta characters. - */ -static int -glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, - Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp) -{ - struct stat sb; - Char *p, *q; - int anymeta; - - /* - * Loop over pattern segments until end of pattern or until - * segment with meta character found. - */ - for (anymeta = 0;;) { - if (*pattern == EOS) { /* End of pattern? */ - *pathend = EOS; - if (g_lstat(pathbuf, &sb, pglob)) - return(0); - - if (((pglob->gl_flags & GLOB_MARK) && - pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || - (S_ISLNK(sb.st_mode) && - (g_stat(pathbuf, &sb, pglob) == 0) && - S_ISDIR(sb.st_mode)))) { - if (pathend+1 > pathend_last) - return (1); - *pathend++ = SEP; - *pathend = EOS; - } - ++pglob->gl_matchc; - return(globextend(pathbuf, pglob, limitp)); - } - - /* Find end of next segment, copy tentatively to pathend. */ - q = pathend; - p = pattern; - while (*p != EOS && *p != SEP) { - if (ismeta(*p)) - anymeta = 1; - if (q+1 > pathend_last) - return (1); - *q++ = *p++; - } - - if (!anymeta) { /* No expansion, do next segment. */ - pathend = q; - pattern = p; - while (*pattern == SEP) { - if (pathend+1 > pathend_last) - return (1); - *pathend++ = *pattern++; - } - } else - /* Need expansion, recurse. */ - return(glob3(pathbuf, pathbuf_last, pathend, - pathend_last, pattern, pattern_last, - p, pattern_last, pglob, limitp)); - } - /* NOTREACHED */ -} - -static int -glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, - Char *pattern, Char *pattern_last __attribute__((unused)), Char *restpattern, - Char *restpattern_last, glob_t *pglob, size_t *limitp) -{ - struct dirent *dp; - DIR *dirp; - int err; - char buf[MAXPATHLEN]; - - /* - * The readdirfunc declaration can't be prototyped, because it is - * assigned, below, to two functions which are prototyped in glob.h - * and dirent.h as taking pointers to differently typed opaque - * structures. - */ - struct dirent *(*readdirfunc)(void *); - - if (pathend > pathend_last) - return (1); - *pathend = EOS; - errno = 0; - - if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { - /* TODO: don't call for ENOENT or ENOTDIR? */ - if (pglob->gl_errfunc) { - if (g_Ctoc(pathbuf, buf, sizeof(buf))) - return(GLOB_ABORTED); - if (pglob->gl_errfunc(buf, errno) || - pglob->gl_flags & GLOB_ERR) - return(GLOB_ABORTED); - } - return(0); - } - - err = 0; - - /* Search directory for matching names. */ - if (pglob->gl_flags & GLOB_ALTDIRFUNC) - readdirfunc = pglob->gl_readdir; - else - readdirfunc = (struct dirent *(*)(void *))readdir; - while ((dp = (*readdirfunc)(dirp))) { - u_char *sc; - Char *dc; - - /* Initial DOT must be matched literally. */ - if (dp->d_name[0] == DOT && *pattern != DOT) - continue; - dc = pathend; - sc = (u_char *) dp->d_name; - while (dc < pathend_last && (*dc++ = *sc++) != EOS) - ; - if (dc >= pathend_last) { - *dc = EOS; - err = 1; - break; - } - - if (!match(pathend, pattern, restpattern)) { - *pathend = EOS; - continue; - } - err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, - restpattern, restpattern_last, pglob, limitp); - if (err) - break; - } - - if (pglob->gl_flags & GLOB_ALTDIRFUNC) - (*pglob->gl_closedir)(dirp); - else - closedir(dirp); - return(err); -} - - -/* - * Extend the gl_pathv member of a glob_t structure to accommodate a new item, - * add the new item, and update gl_pathc. - * - * This assumes the BSD realloc, which only copies the block when its size - * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic - * behavior. - * - * Return 0 if new item added, error code if memory couldn't be allocated. - * - * Invariant of the glob_t structure: - * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and - * gl_pathv points to (gl_offs + gl_pathc + 1) items. - */ -static int -globextend(const Char *path, glob_t *pglob, size_t *limitp) -{ - char **pathv; - int i; - u_int newsize, len; - char *copy; - const Char *p; - - newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) : - malloc(newsize); - if (pathv == NULL) { - if (pglob->gl_pathv) { - free(pglob->gl_pathv); - pglob->gl_pathv = NULL; - } - return(GLOB_NOSPACE); - } - - if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { - /* first time around -- clear initial gl_offs items */ - pathv += pglob->gl_offs; - for (i = pglob->gl_offs; --i >= 0; ) - *--pathv = NULL; - } - pglob->gl_pathv = pathv; - - for (p = path; *p++;) - ; - len = (size_t)(p - path); - *limitp += len; - if ((copy = malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { - free(copy); - return(GLOB_NOSPACE); - } - pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; - } - pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - - if ((pglob->gl_flags & GLOB_LIMIT) && - newsize + *limitp >= ARG_MAX) { - errno = 0; - return(GLOB_NOSPACE); - } - - return(copy == NULL ? GLOB_NOSPACE : 0); -} - - -/* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. - */ -static int -match(Char *name, Char *pat, Char *patend) -{ - int ok, negate_range; - Char c, k; - - while (pat < patend) { - c = *pat++; - switch (c & M_MASK) { - case M_ALL: - if (pat == patend) - return(1); - do { - if (match(name, pat, patend)) - return(1); - } while (*name++ != EOS); - return(0); - case M_ONE: - if (*name++ == EOS) - return(0); - break; - case M_SET: - ok = 0; - if ((k = *name++) == EOS) - return(0); - if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) - ++pat; - while (((c = *pat++) & M_MASK) != M_END) - if ((*pat & M_MASK) == M_RNG) { - if (c <= k && k <= pat[1]) - ok = 1; - pat += 2; - } else if (c == k) - ok = 1; - if (ok == negate_range) - return(0); - break; - default: - if (*name++ != c) - return(0); - break; - } - } - return(*name == EOS); -} - -/* Free allocated data belonging to a glob_t structure. */ -void -globfree(glob_t *pglob) -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) - if (*pp) - free(*pp); - free(pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} - -static DIR * -g_opendir(Char *str, glob_t *pglob) -{ - char buf[MAXPATHLEN]; - - if (!*str) - strlcpy(buf, ".", sizeof buf); - else { - if (g_Ctoc(str, buf, sizeof(buf))) - return(NULL); - } - - if (pglob->gl_flags & GLOB_ALTDIRFUNC) - return((*pglob->gl_opendir)(buf)); - - return(opendir(buf)); -} - -static int -g_lstat(Char *fn, struct stat *sb, glob_t *pglob) -{ - char buf[MAXPATHLEN]; - - if (g_Ctoc(fn, buf, sizeof(buf))) - return(-1); - if (pglob->gl_flags & GLOB_ALTDIRFUNC) - return((*pglob->gl_lstat)(buf, sb)); - return(lstat(buf, sb)); -} - -static int -g_stat(Char *fn, struct stat *sb, glob_t *pglob) -{ - char buf[MAXPATHLEN]; - - if (g_Ctoc(fn, buf, sizeof(buf))) - return(-1); - if (pglob->gl_flags & GLOB_ALTDIRFUNC) - return((*pglob->gl_stat)(buf, sb)); - return(stat(buf, sb)); -} - -static const Char * -g_strchr(const Char *str, int ch) -{ - do { - if (*str == ch) - return (str); - } while (*str++); - return (NULL); -} - -static int -g_Ctoc(const Char *str, char *buf, u_int len) -{ - - while (len--) { - if ((*buf++ = *str++) == EOS) - return (0); - } - return (1); -} - -#ifdef DEBUG -static void -qprintf(const char *str, Char *s) -{ - Char *p; - - (void)printf("%s:\n", str); - for (p = s; *p; p++) - (void)printf("%c", CHAR(*p)); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", *p & M_PROTECT ? '"' : ' '); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", ismeta(*p) ? '_' : ' '); - (void)printf("\n"); -} -#endif -#endif diff --git a/config/glob.h b/config/glob.h deleted file mode 100644 index 15ade2a04..000000000 --- a/config/glob.h +++ /dev/null @@ -1,100 +0,0 @@ -/* $OpenBSD: glob.h,v 1.9 2004/10/07 16:56:11 millert Exp $ */ -/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef __APPLE__ -#include_next -#else -#ifndef _GLOB_H_ -#define _GLOB_H_ - -#include - -struct stat; -typedef struct { - int gl_pathc; /* Count of total paths so far. */ - int gl_matchc; /* Count of paths matching pattern. */ - int gl_offs; /* Reserved at beginning of gl_pathv. */ - int gl_flags; /* Copy of flags parameter to glob. */ - char **gl_pathv; /* List of paths matching pattern. */ - /* Copy of errfunc parameter to glob. */ - int (*gl_errfunc)(const char *, int); - - /* - * Alternate filesystem access methods for glob; replacement - * versions of closedir(3), readdir(3), opendir(3), stat(2) - * and lstat(2). - */ - void (*gl_closedir)(void *); - struct dirent *(*gl_readdir)(void *); - void *(*gl_opendir)(const char *); - int (*gl_lstat)(const char *, struct stat *); - int (*gl_stat)(const char *, struct stat *); -} glob_t; - -/* Flags */ -#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ -#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ -#define GLOB_ERR 0x0004 /* Return on error. */ -#define GLOB_MARK 0x0008 /* Append / to matching directories. */ -#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ -#define GLOB_NOSORT 0x0020 /* Don't sort. */ -#define GLOB_NOESCAPE 0x1000 /* Disable backslash escaping. */ - -#ifndef _POSIX_SOURCE -#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ -#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ -#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ -#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ -#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ -#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ -#define GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */ -#endif - -/* Error values returned by glob(3) */ -#define GLOB_NOSPACE (-1) /* Malloc call failed. */ -#define GLOB_ABORTED (-2) /* Unignored error. */ -#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ -#define GLOB_NOSYS (-4) /* Function not supported. */ -#define GLOB_ABEND GLOB_ABORTED - -__BEGIN_DECLS -int glob(const char *, int, int (*)(const char *, int), glob_t *); -void globfree(glob_t *); -__END_DECLS - -#endif /* !_GLOB_H_ */ -#endif diff --git a/config/inputbox.c b/config/inputbox.c deleted file mode 100644 index 8c4c1ce99..000000000 --- a/config/inputbox.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * inputbox.c -- implements the input box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - -unsigned char dialog_input_result[MAX_LEN + 1]; - -/* - * Print the termination buttons - */ -static void -print_buttons(WINDOW *dialog, int height, int width, int selected) -{ - int x = width / 2 - 11; - int y = height - 2; - - print_button (dialog, " Ok ", y, x, selected==0); - print_button (dialog, " Help ", y, x + 14, selected==1); - - wmove(dialog, y, x+1+14*selected); - wrefresh(dialog); -} - -/* - * Display a dialog box for inputing a string - */ -int -dialog_inputbox (const char *title, const char *prompt, int height, int width, - const char *init) -{ - int i, x, y, box_y, box_x, box_width; - int input_x = 0, scroll = 0, key = 0, button = -1; - char *instr = (char*)dialog_input_result; - WINDOW *dialog; - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - wattrset (dialog, border_attr); - mvwaddch (dialog, height-3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - waddch (dialog, ACS_RTEE); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - - wattrset (dialog, dialog_attr); - print_autowrap (dialog, prompt, width - 2, 1, 3); - - /* Draw the input field box */ - box_width = width - 6; - getyx (dialog, y, x); - box_y = y + 2; - box_x = (width - box_width) / 2; - draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2, - border_attr, dialog_attr); - - print_buttons(dialog, height, width, 0); - - /* Set up the initial value */ - wmove (dialog, box_y, box_x); - wattrset (dialog, inputbox_attr); - - if (!init) - instr[0] = '\0'; - else - strcpy (instr, init); - - input_x = strlen (instr); - - if (input_x >= box_width) { - scroll = input_x - box_width + 1; - input_x = box_width - 1; - for (i = 0; i < box_width - 1; i++) - waddch (dialog, instr[scroll + i]); - } else - waddstr (dialog, instr); - - wmove (dialog, box_y, box_x + input_x); - - wrefresh (dialog); - - while (key != ESC) { - key = wgetch (dialog); - - if (button == -1) { /* Input box selected */ - switch (key) { - case TAB: - case KEY_UP: - case KEY_DOWN: - break; - case KEY_LEFT: - continue; - case KEY_RIGHT: - continue; - case KEY_BACKSPACE: - case 127: - if (input_x || scroll) { - wattrset (dialog, inputbox_attr); - if (!input_x) { - scroll = scroll < box_width - 1 ? - 0 : scroll - (box_width - 1); - wmove (dialog, box_y, box_x); - for (i = 0; i < box_width; i++) - waddch (dialog, instr[scroll + input_x + i] ? - instr[scroll + input_x + i] : ' '); - input_x = strlen (instr) - scroll; - } else - input_x--; - instr[scroll + input_x] = '\0'; - mvwaddch (dialog, box_y, input_x + box_x, ' '); - wmove (dialog, box_y, input_x + box_x); - wrefresh (dialog); - } - continue; - default: - if (key < 0x100 && isprint (key)) { - if (scroll + input_x < MAX_LEN) { - wattrset (dialog, inputbox_attr); - instr[scroll + input_x] = key; - instr[scroll + input_x + 1] = '\0'; - if (input_x == box_width - 1) { - scroll++; - wmove (dialog, box_y, box_x); - for (i = 0; i < box_width - 1; i++) - waddch (dialog, instr[scroll + i]); - } else { - wmove (dialog, box_y, input_x++ + box_x); - waddch (dialog, key); - } - wrefresh (dialog); - } else - flash (); /* Alarm user about overflow */ - continue; - } - } - } - switch (key) { - case 'O': - case 'o': - delwin (dialog); - return 0; - case 'H': - case 'h': - delwin (dialog); - return 1; - case KEY_UP: - case KEY_LEFT: - switch (button) { - case -1: - button = 1; /* Indicates "Cancel" button is selected */ - print_buttons(dialog, height, width, 1); - break; - case 0: - button = -1; /* Indicates input box is selected */ - print_buttons(dialog, height, width, 0); - wmove (dialog, box_y, box_x + input_x); - wrefresh (dialog); - break; - case 1: - button = 0; /* Indicates "OK" button is selected */ - print_buttons(dialog, height, width, 0); - break; - } - break; - case TAB: - case KEY_DOWN: - case KEY_RIGHT: - switch (button) { - case -1: - button = 0; /* Indicates "OK" button is selected */ - print_buttons(dialog, height, width, 0); - break; - case 0: - button = 1; /* Indicates "Cancel" button is selected */ - print_buttons(dialog, height, width, 1); - break; - case 1: - button = -1; /* Indicates input box is selected */ - print_buttons(dialog, height, width, 0); - wmove (dialog, box_y, box_x + input_x); - wrefresh (dialog); - break; - } - break; - case ' ': - case '\n': - delwin (dialog); - return (button == -1 ? 0 : button); - case 'X': - case 'x': - key = ESC; - case ESC: - break; - } - } - - delwin (dialog); - return -1; /* ESC pressed */ -} diff --git a/config/lex.backup b/config/lex.backup deleted file mode 100644 index afb1b53c7..000000000 --- a/config/lex.backup +++ /dev/null @@ -1 +0,0 @@ -No backing up. diff --git a/config/lkc.h b/config/lkc.h deleted file mode 100644 index dd040f7a8..000000000 --- a/config/lkc.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef LKC_H -#define LKC_H - -#include "expr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef LKC_DIRECT_LINK -#define P(name,type,arg) extern type name arg -#else -#include "lkc_defs.h" -#define P(name,type,arg) extern type (*name ## _p) arg -#endif -#include "lkc_proto.h" -#undef P - -#define SRCTREE "srctree" - -int zconfparse(void); -void zconfdump(FILE *out); - -extern int zconfdebug; -void zconf_starthelp(void); -FILE *zconf_fopen(const char *name); -void zconf_initscan(const char *name); -void zconf_nextfile(const char *name); -int zconf_lineno(void); -char *zconf_curname(void); - -/* confdata.c */ -extern const char conf_def_filename[]; -extern char conf_filename[]; - -char *conf_get_default_confname(void); - -/* kconfig_load.c */ -void kconfig_load(void); - -/* menu.c */ -void menu_init(void); -void menu_add_menu(void); -void menu_end_menu(void); -void menu_add_entry(struct symbol *sym); -void menu_end_entry(void); -void menu_add_dep(struct expr *dep); -struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); -void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_finalize(struct menu *parent); -void menu_set_type(int type); -struct file *file_lookup(const char *name); -int file_write_dep(const char *name); - -extern struct menu *current_entry; -extern struct menu *current_menu; - -/* symbol.c */ -void sym_init(void); -void sym_clear_all_valid(void); -void sym_set_changed(struct symbol *sym); -struct symbol *sym_check_deps(struct symbol *sym); -struct property *prop_alloc(enum prop_type type, struct symbol *sym); -struct symbol *prop_get_symbol(struct property *prop); - -static inline tristate sym_get_tristate_value(struct symbol *sym) -{ - return sym->curr.tri; -} - - -static inline struct symbol *sym_get_choice_value(struct symbol *sym) -{ - return (struct symbol *)sym->curr.val; -} - -static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) -{ - return sym_set_tristate_value(chval, yes); -} - -static inline bool sym_is_choice(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICE ? true : false; -} - -static inline bool sym_is_choice_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICEVAL ? true : false; -} - -static inline bool sym_is_optional(struct symbol *sym) -{ - return sym->flags & SYMBOL_OPTIONAL ? true : false; -} - -static inline bool sym_has_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_NEW ? false : true; -} - -#ifdef __cplusplus -} -#endif - -#endif /* LKC_H */ diff --git a/config/lkc_proto.h b/config/lkc_proto.h deleted file mode 100644 index 97c79178e..000000000 --- a/config/lkc_proto.h +++ /dev/null @@ -1,39 +0,0 @@ - -/* confdata.c */ -P(conf_parse,void,(const char *name)); -P(conf_read,int,(const char *name)); -P(conf_write,int,(const char *name)); - -/* menu.c */ -P(rootmenu,struct menu,); - -P(menu_is_visible,bool,(struct menu *menu)); -P(menu_get_prompt,const char *,(struct menu *menu)); -P(menu_get_root_menu,struct menu *,(struct menu *menu)); -P(menu_get_parent_menu,struct menu *,(struct menu *menu)); - -/* symbol.c */ -P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); -P(sym_change_count,int,); - -P(sym_lookup,struct symbol *,(const char *name, int isconst)); -P(sym_find,struct symbol *,(const char *name)); -P(sym_type_name,const char *,(enum symbol_type type)); -P(sym_calc_value,void,(struct symbol *sym)); -P(sym_get_type,enum symbol_type,(struct symbol *sym)); -P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); -P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); -P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); -P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); -P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); -P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); -P(sym_is_changable,bool,(struct symbol *sym)); -P(sym_get_choice_prop,struct property *,(struct symbol *sym)); -P(sym_get_default_prop,struct property *,(struct symbol *sym)); -P(sym_get_string_value,const char *,(struct symbol *sym)); - -P(prop_get_type_name,const char *,(enum prop_type type)); - -/* expr.c */ -P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); -P(expr_print,void,(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)); diff --git a/config/mconf.c b/config/mconf.c deleted file mode 100644 index 878554245..000000000 --- a/config/mconf.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - * - * Introduced single menu mode (show all sub-menus in one large tree). - * 2002-11-06 Petr Baudis - * - * Directly use liblxdialog library routines. - * 2002-11-14 Petr Baudis - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dialog.h" - -#define LKC_DIRECT_LINK -#include "lkc.h" - -static char menu_backtitle[128]; -static const char menu_instructions[] = - "Arrow keys navigate the menu. " - " selects submenus --->. " - "Highlighted letters are hotkeys. " - "Pressing selectes a feature, while will exclude a feature. " - "Press to exit, for Help. " - "Legend: [*] feature is selected [ ] feature is excluded", -radiolist_instructions[] = - "Use the arrow keys to navigate this window or " - "press the hotkey of the item you wish to select " - "followed by the . " - "Press for additional information about this option.", -inputbox_instructions_int[] = - "Please enter a decimal value. " - "Fractions will not be accepted. " - "Use the key to move from the input field to the buttons below it.", -inputbox_instructions_hex[] = - "Please enter a hexadecimal value. " - "Use the key to move from the input field to the buttons below it.", -inputbox_instructions_string[] = - "Please enter a string value. " - "Use the key to move from the input field to the buttons below it.", -setmod_text[] = - "This feature depends on another which has been configured as a module.\n" - "As a result, this feature will be built as a module.", -nohelp_text[] = - "There is no help available for this option.\n", -load_config_text[] = - "Enter the name of the configuration file you wish to load. " - "Accept the name shown to restore the configuration you " - "last retrieved. Leave blank to abort.", -load_config_help[] = - "\n" - "For various reasons, one may wish to keep several different OpenADK\n" - "configurations available on a single machine.\n" - "\n" - "If you have saved a previous configuration in a file other than the\n" - "OpenADK's default, entering the name of the file here will allow you\n" - "to modify that configuration.\n" - "\n" - "If you are uncertain, then you have probably never used alternate\n" - "configuration files. You should therefor leave this blank to abort.\n", -save_config_text[] = - "Enter a filename to which this configuration should be saved " - "as an alternate. Leave blank to abort.", -save_config_help[] = - "\n" - "For various reasons, one may wish to keep different OpenADK\n" - "configurations available on a single machine.\n" - "\n" - "Entering a file name here will allow you to later retrieve, modify\n" - "and use the current configuration as an alternate to whatever\n" - "configuration options you have selected at that time.\n" - "\n" - "If you are uncertain what all this means then you should probably\n" - "leave this blank.\n", -top_menu_help[] = - "\n" - "Use the Up/Down arrow keys (cursor keys) to highlight the item\n" - "you wish to change or submenu wish to select and press .\n" - "Submenus are designated by \"--->\".\n" - "\n" - "Shortcut: Press the option's highlighted letter (hotkey).\n" - "\n" - "You may also use the and keys to scroll\n" - "unseen options into view.\n" -; - -static char filename[PATH_MAX+1] = ".config"; -static int indent = 0; -static struct termios ios_org; -static int rows, cols; -struct menu *current_menu; -static int child_count; -static int single_menu_mode; - -static struct dialog_list_item *items[16384]; /* FIXME: This ought to be dynamic. */ -static int item_no; - -static void conf(struct menu *menu); -static void conf_choice(struct menu *menu); -static void conf_string(struct menu *menu); -static void conf_load(void); -static void conf_save(void); -static void show_textbox(const char *title, const char *text, int r, int c); -static void show_helptext(const char *title, const char *text); -static void show_help(struct menu *menu); -static void show_readme(void); - -static void init_wsize(void) -{ - struct winsize ws; - char *env; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1) { - rows = 24; - cols = 80; - } else { - rows = ws.ws_row; - cols = ws.ws_col; - if (!rows) { - env = getenv("LINES"); - if (env) - rows = atoi(env); - if (!rows) - rows = 24; - } - if (!cols) { - env = getenv("COLUMNS"); - if (env) - cols = atoi(env); - if (!cols) - cols = 80; - } - } - - if (rows < 19 || cols < 80) { - fprintf(stderr, "Your display is too small to run Menuconfig!\n"); - fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); - exit(1); - } - - rows -= 4; - cols -= 5; -} - -static void cinit(void) -{ - item_no = 0; -} - -static void cmake(void) -{ - items[item_no] = malloc(sizeof(struct dialog_list_item)); - memset(items[item_no], 0, sizeof(struct dialog_list_item)); - items[item_no]->tag = malloc(32); items[item_no]->tag[0] = 0; - items[item_no]->name = malloc(512); items[item_no]->name[0] = 0; - items[item_no]->namelen = 0; - item_no++; -} - -static int cprint_name(const char *fmt, ...) -{ - va_list ap; - int res; - - if (!item_no) - cmake(); - va_start(ap, fmt); - res = vsnprintf(items[item_no - 1]->name + items[item_no - 1]->namelen, - 512 - items[item_no - 1]->namelen, fmt, ap); - if (res > 0) - items[item_no - 1]->namelen += res; - va_end(ap); - - return res; -} - -static int cprint_tag(const char *fmt, ...) -{ - va_list ap; - int res; - - if (!item_no) - cmake(); - va_start(ap, fmt); - res = vsnprintf(items[item_no - 1]->tag, 32, fmt, ap); - va_end(ap); - - return res; -} - -static void cdone(void) -{ - int i; - - for (i = 0; i < item_no; i++) { - free(items[i]->tag); - free(items[i]->name); - free(items[i]); - } - - item_no = 0; -} - -static void build_conf(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - int type, tmp, doint = 2; - tristate val; - char ch; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - prop = menu->prompt; - if (!sym) { - if (prop && menu != current_menu) { - const char *prompt = menu_get_prompt(menu); - switch (prop->type) { - case P_MENU: - child_count++; - cmake(); - cprint_tag("m%p", menu); - - if (single_menu_mode) { - cprint_name("%s%*c%s", - menu->data ? "-->" : "++>", - indent + 1, ' ', prompt); - } else { - cprint_name(" %*c%s --->", indent + 1, ' ', prompt); - } - - if (single_menu_mode && menu->data) - goto conf_childs; - return; - default: - if (prompt) { - child_count++; - cmake(); - cprint_tag(":%p", menu); - cprint_name("---%*c%s", indent + 1, ' ', prompt); - } - } - } else - doint = 0; - goto conf_childs; - } - - cmake(); - type = sym_get_type(sym); - if (sym_is_choice(sym)) { - struct symbol *def_sym = sym_get_choice_value(sym); - struct menu *def_menu = NULL; - - child_count++; - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child) && child->sym == def_sym) - def_menu = child; - } - - val = sym_get_tristate_value(sym); - if (sym_is_changable(sym)) { - cprint_tag("t%p", menu); - switch (type) { - case S_BOOLEAN: - cprint_name("[%c]", val == no ? ' ' : '*'); - break; - case S_TRISTATE: - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - cprint_name("<%c>", ch); - break; - } - } else { - cprint_tag("%c%p", def_menu ? 't' : ':', menu); - cprint_name(" "); - } - - cprint_name("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); - if (val == yes) { - if (def_menu) { - cprint_name(" (%s)", menu_get_prompt(def_menu)); - cprint_name(" --->"); - if (def_menu->list) { - indent += 2; - build_conf(def_menu); - indent -= 2; - } - } - return; - } - } else { - if (menu == current_menu) { - cprint_tag(":%p", menu); - cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); - goto conf_childs; - } - - child_count++; - val = sym_get_tristate_value(sym); - if (sym_is_choice_value(sym) && val == yes) { - cprint_tag(":%p", menu); - cprint_name(" "); - } else { - switch (type) { - case S_BOOLEAN: - cprint_tag("t%p", menu); - if (sym_is_changable(sym)) - cprint_name("[%c]", val == no ? ' ' : '*'); - else - cprint_name(val == no ? "_ _" : "-+-"); - break; - case S_TRISTATE: - cprint_tag("t%p", menu); - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - if (sym_is_changable(sym)) - cprint_name("<%c>", ch); - else - cprint_name(val == no ? "_ _" : "-+-"); - break; - default: - cprint_tag("s%p", menu); - tmp = cprint_name("(%s)", sym_get_string_value(sym)); - tmp = indent - tmp + 4; - if (tmp < 0) - tmp = 0; - cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu), - (sym_has_value(sym) || !sym_is_changable(sym)) ? - "" : " (NEW)"); - goto conf_childs; - } - } - cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), - (sym_has_value(sym) || !sym_is_changable(sym)) ? - "" : " (NEW)"); - if (menu->prompt->type == P_MENU) { - cprint_name(" --->"); - return; - } - } - -conf_childs: - indent += doint; - for (child = menu->list; child; child = child->next) - build_conf(child); - indent -= doint; -} - -static void conf(struct menu *menu) -{ - struct dialog_list_item *active_item = NULL; - struct menu *submenu; - const char *prompt = menu_get_prompt(menu); - struct symbol *sym; - char active_entry[40]; - int stat, type; - - unlink("lxdialog.scrltmp"); - active_entry[0] = 0; - while (1) { - indent = 0; - child_count = 0; - current_menu = menu; - cdone(); cinit(); - build_conf(menu); - if (!child_count) - break; - if (menu == &rootmenu) { - cmake(); cprint_tag(":"); cprint_name("--- "); - cmake(); cprint_tag("L"); cprint_name("Load an Alternate Configuration File"); - cmake(); cprint_tag("S"); cprint_name("Save Configuration to an Alternate File"); - } - dialog_clear(); - stat = dialog_menu(prompt ? prompt : "Main Menu", - menu_instructions, rows, cols, rows - 10, - active_entry, item_no, items); - if (stat < 0) - return; - - if (stat == 1 || stat == 255) - break; - - active_item = first_sel_item(item_no, items); - if (!active_item) - continue; - active_item->selected = 0; - strncpy(active_entry, active_item->tag, sizeof(active_entry)); - active_entry[sizeof(active_entry)-1] = 0; - type = active_entry[0]; - if (!type) - continue; - - sym = NULL; - submenu = NULL; - if (sscanf(active_entry + 1, "%p", &submenu) == 1) - sym = submenu->sym; - - switch (stat) { - case 0: - switch (type) { - case 'm': - if (single_menu_mode) - submenu->data = (void *) (long) !submenu->data; - else - conf(submenu); - break; - case 't': - if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) - conf_choice(submenu); - else if (submenu->prompt->type == P_MENU) - conf(submenu); - break; - case 's': - conf_string(submenu); - break; - case 'L': - conf_load(); - break; - case 'S': - conf_save(); - break; - } - break; - case 2: - if (sym) - show_help(submenu); - else - show_readme(); - break; - case 3: - if (type == 't') { - if (sym_set_tristate_value(sym, yes)) - break; - if (sym_set_tristate_value(sym, mod)) - show_textbox(NULL, setmod_text, 6, 74); - } - break; - case 4: - if (type == 't') - sym_set_tristate_value(sym, no); - break; - case 5: - if (type == 't') - sym_set_tristate_value(sym, mod); - break; - case 6: - if (type == 't') - sym_toggle_tristate_value(sym); - else if (type == 'm') - conf(submenu); - break; - } - } -} - -static void show_textbox(const char *title, const char *text, int r, int c) -{ - int fd; - - fd = creat(".help.tmp", 0777); - write(fd, text, strlen(text)); - close(fd); - while (dialog_textbox(title, ".help.tmp", r, c) < 0) - ; - unlink(".help.tmp"); -} - -static void show_helptext(const char *title, const char *text) -{ - show_textbox(title, text, rows, cols); -} - -static void show_help(struct menu *menu) -{ - const char *help; - char *helptext; - struct symbol *sym = menu->sym; - - help = sym->help; - if (!help) - help = nohelp_text; - if (sym->name) { - helptext = malloc(strlen(sym->name) + strlen(help) + 16); - sprintf(helptext, "%s:\n\n%s", sym->name, help); - show_helptext(menu_get_prompt(menu), helptext); - free(helptext); - } else - show_helptext(menu_get_prompt(menu), help); -} - -static void show_readme(void) -{ - show_helptext("Help", top_menu_help); -} - -static void conf_choice(struct menu *menu) -{ - const char *prompt = menu_get_prompt(menu); - struct menu *child; - struct symbol *active; - - active = sym_get_choice_value(menu->sym); - while (1) { - current_menu = menu; - cdone(); cinit(); - for (child = menu->list; child; child = child->next) { - if (!menu_is_visible(child)) - continue; - cmake(); - cprint_tag("%p", child); - cprint_name("%s", menu_get_prompt(child)); - if (child->sym == sym_get_choice_value(menu->sym)) - items[item_no - 1]->selected = 1; /* ON */ - else if (child->sym == active) - items[item_no - 1]->selected = 2; /* SELECTED */ - else - items[item_no - 1]->selected = 0; /* OFF */ - } - - switch (dialog_checklist(prompt ? prompt : "Main Menu", - radiolist_instructions, 15, 70, 6, - item_no, items, FLAG_RADIO)) { - case 0: - if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) != 1) - break; - sym_set_tristate_value(child->sym, yes); - return; - case 1: - if (sscanf(first_sel_item(item_no, items)->tag, "%p", &child) == 1) { - show_help(child); - active = child->sym; - } else - show_help(menu); - break; - case 255: - return; - } - } -} - -static void conf_string(struct menu *menu) -{ - const char *prompt = menu_get_prompt(menu); - - while (1) { - char *heading; - - switch (sym_get_type(menu->sym)) { - case S_INT: - heading = (char *) inputbox_instructions_int; - break; - case S_HEX: - heading = (char *) inputbox_instructions_hex; - break; - case S_STRING: - heading = (char *) inputbox_instructions_string; - break; - default: - heading = "Internal mconf error!"; - /* panic? */; - } - - switch (dialog_inputbox(prompt ? prompt : "Main Menu", - heading, 10, 75, - sym_get_string_value(menu->sym))) { - case 0: - if (sym_set_string_value(menu->sym, (const char*)dialog_input_result)) - return; - show_textbox(NULL, "You have made an invalid entry.", 5, 43); - break; - case 1: - show_help(menu); - break; - case 255: - return; - } - } -} - -static void conf_load(void) -{ - while (1) { - switch (dialog_inputbox(NULL, load_config_text, 11, 55, - filename)) { - case 0: - if (!dialog_input_result[0]) - return; - if (!conf_read((const char*)dialog_input_result)) - return; - show_textbox(NULL, "File does not exist!", 5, 38); - break; - case 1: - show_helptext("Load Alternate Configuration", load_config_help); - break; - case 255: - return; - } - } -} - -static void conf_save(void) -{ - while (1) { - switch (dialog_inputbox(NULL, save_config_text, 11, 55, - filename)) { - case 0: - if (!dialog_input_result[0]) - return; - if (!conf_write((const char*)dialog_input_result)) - return; - show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60); - break; - case 1: - show_helptext("Save Alternate Configuration", save_config_help); - break; - case 255: - return; - } - } -} - -static void conf_cleanup(void) -{ - tcsetattr(1, TCSAFLUSH, &ios_org); - unlink(".help.tmp"); -} - -static void winch_handler(int sig) -{ - struct winsize ws; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1) { - rows = 24; - cols = 80; - } else { - rows = ws.ws_row; - cols = ws.ws_col; - } - - if (rows < 19 || cols < 80) { - end_dialog(); - fprintf(stderr, "Your display is too small to run Menuconfig!\n"); - fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); - exit(1); - } - - rows -= 4; - cols -= 5; - -} - -int main(int ac, char **av) -{ - int stat; - char *mode; - struct symbol *sym; - - conf_parse(av[1]); - conf_read(NULL); - - sym = sym_lookup("VERSION", 0); - sym_calc_value(sym); - snprintf(menu_backtitle, 128, "OpenADK v%s Configuration", - sym_get_string_value(sym)); - - mode = getenv("MENUCONFIG_MODE"); - if (mode) { - if (!strcasecmp(mode, "single_menu")) - single_menu_mode = 1; - } - - tcgetattr(1, &ios_org); - atexit(conf_cleanup); - init_wsize(); - init_dialog(); - signal(SIGWINCH, winch_handler); - conf(&rootmenu); - end_dialog(); - - /* Restart dialog to act more like when lxdialog was still separate */ - init_dialog(); - do { - stat = dialog_yesno(NULL, - "Do you wish to save your new OpenADK configuration?", 5, 60); - } while (stat < 0); - end_dialog(); - - if (stat == 0) { - conf_write(NULL); - printf("\n\n*** End of OpenADK configuration.\n"); - } else - printf("\n\nYour OpenADK configuration changes were NOT saved.\n\n"); - - return 0; -} diff --git a/config/menu.c b/config/menu.c deleted file mode 100644 index f6e6200ce..000000000 --- a/config/menu.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -struct menu rootmenu; -struct menu *current_menu, *current_entry; -static struct menu **last_entry_ptr; - -struct file *file_list; -struct file *current_file; - -static void menu_warn(struct menu *menu, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -static void prop_warn(struct property *prop, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -void menu_init(void) -{ - current_entry = current_menu = &rootmenu; - last_entry_ptr = &rootmenu.list; -} - -void menu_add_entry(struct symbol *sym) -{ - struct menu *menu; - - menu = malloc(sizeof(*menu)); - memset(menu, 0, sizeof(*menu)); - menu->sym = sym; - menu->parent = current_menu; - menu->file = current_file; - menu->lineno = zconf_lineno(); - - *last_entry_ptr = menu; - last_entry_ptr = &menu->next; - current_entry = menu; -} - -void menu_end_entry(void) -{ -} - -void menu_add_menu(void) -{ - current_menu = current_entry; - last_entry_ptr = ¤t_entry->list; -} - -void menu_end_menu(void) -{ - last_entry_ptr = ¤t_menu->next; - current_menu = current_menu->parent; -} - -struct expr *menu_check_dep(struct expr *e) -{ - if (!e) - return e; - - switch (e->type) { - case E_NOT: - e->left.expr = menu_check_dep(e->left.expr); - break; - case E_OR: - case E_AND: - e->left.expr = menu_check_dep(e->left.expr); - e->right.expr = menu_check_dep(e->right.expr); - break; - case E_SYMBOL: - /* change 'm' into 'm' && MODULES */ - if (e->left.sym == &symbol_mod) - return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); - break; - default: - break; - } - return e; -} - -void menu_add_dep(struct expr *dep) -{ - current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); -} - -void menu_set_type(int type) -{ - struct symbol *sym = current_entry->sym; - - if (sym->type == type) - return; - if (sym->type == S_UNKNOWN) { - sym->type = type; - return; - } - menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n", - sym->name ? sym->name : "", - sym_type_name(sym->type), sym_type_name(type)); -} - -struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) -{ - struct property *prop = prop_alloc(type, current_entry->sym); - - prop->menu = current_entry; - prop->text = prompt; - prop->expr = expr; - prop->visible.expr = menu_check_dep(dep); - - if (prompt) { - if (current_entry->prompt) - menu_warn(current_entry, "prompt redefined\n"); - current_entry->prompt = prop; - } - - return prop; -} - -void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) -{ - menu_add_prop(type, prompt, NULL, dep); -} - -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) -{ - menu_add_prop(type, NULL, expr, dep); -} - -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) -{ - menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); -} - -void sym_check_prop(struct symbol *sym) -{ - struct property *prop; - struct symbol *sym2; - for (prop = sym->prop; prop; prop = prop->next) { - switch (prop->type) { - case P_DEFAULT: - if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && - prop->expr->type != E_SYMBOL) - prop_warn(prop, - "default for config symbol '%'" - " must be a single symbol", sym->name); - break; - case P_SELECT: - case P_SELECTNOT: - sym2 = prop_get_symbol(prop); - if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) - prop_warn(prop, - "config symbol '%s' uses select, but is " - "not boolean or tristate", sym->name); - else if (sym2->type == S_UNKNOWN) - prop_warn(prop, - "'select' used by config symbol '%s' " - "refer to undefined symbol '%s'", - sym->name, sym2->name); - else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE) - prop_warn(prop, - "'%s' has wrong type. 'select' only " - "accept arguments of boolean and " - "tristate type", sym2->name); - break; - case P_RANGE: - if (sym->type != S_INT && sym->type != S_HEX) - prop_warn(prop, "range is only allowed " - "for int or hex symbols"); - if (!sym_string_valid(sym, prop->expr->left.sym->name) || - !sym_string_valid(sym, prop->expr->right.sym->name)) - prop_warn(prop, "range is invalid"); - break; - default: - ; - } - } -} - -void menu_finalize(struct menu *parent) -{ - struct menu *menu, *last_menu; - struct symbol *sym; - struct property *prop; - struct expr *parentdep, *basedep, *dep, *dep2, **ep; - - sym = parent->sym; - if (parent->list) { - if (sym && sym_is_choice(sym)) { - /* find the first choice value and find out choice type */ - for (menu = parent->list; menu; menu = menu->next) { - if (menu->sym) { - current_entry = parent; - menu_set_type(menu->sym->type); - current_entry = menu; - menu_set_type(sym->type); - break; - } - } - parentdep = expr_alloc_symbol(sym); - } else if (parent->prompt) - parentdep = parent->prompt->visible.expr; - else - parentdep = parent->dep; - - for (menu = parent->list; menu; menu = menu->next) { - basedep = expr_transform(menu->dep); - basedep = expr_alloc_and(expr_copy(parentdep), basedep); - basedep = expr_eliminate_dups(basedep); - menu->dep = basedep; - if (menu->sym) - prop = menu->sym->prop; - else - prop = menu->prompt; - for (; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - dep = expr_transform(prop->visible.expr); - dep = expr_alloc_and(expr_copy(basedep), dep); - dep = expr_eliminate_dups(dep); - if (menu->sym && menu->sym->type != S_TRISTATE) - dep = expr_trans_bool(dep); - prop->visible.expr = dep; - if (prop->type == P_SELECT) { - struct symbol *es = prop_get_symbol(prop); - es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); - } else if (prop->type == P_SELECTNOT) { - struct symbol *es = prop_get_symbol(prop); - es->rev_dep_inv.expr = expr_alloc_or(es->rev_dep_inv.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); - } - } - } - for (menu = parent->list; menu; menu = menu->next) - menu_finalize(menu); - } else if (sym) { - basedep = parent->prompt ? parent->prompt->visible.expr : NULL; - basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); - basedep = expr_eliminate_dups(expr_transform(basedep)); - last_menu = NULL; - for (menu = parent->next; menu; menu = menu->next) { - dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; - if (!expr_contains_symbol(dep, sym)) - break; - if (expr_depends_symbol(dep, sym)) - goto next; - dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); - dep = expr_eliminate_dups(expr_transform(dep)); - dep2 = expr_copy(basedep); - expr_eliminate_eq(&dep, &dep2); - expr_free(dep); - if (!expr_is_yes(dep2)) { - expr_free(dep2); - break; - } - expr_free(dep2); - next: - menu_finalize(menu); - menu->parent = parent; - last_menu = menu; - } - if (last_menu) { - parent->list = parent->next; - parent->next = last_menu->next; - last_menu->next = NULL; - } - } - for (menu = parent->list; menu; menu = menu->next) { - if (sym && sym_is_choice(sym) && menu->sym) { - menu->sym->flags |= SYMBOL_CHOICEVAL; - if (!menu->prompt) - menu_warn(menu, "choice value must have a prompt"); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->type == P_PROMPT && prop->menu != menu) { - prop_warn(prop, "choice values " - "currently only support a " - "single prompt"); - } - if (prop->type == P_DEFAULT) - prop_warn(prop, "defaults for choice " - "values not supported"); - } - current_entry = menu; - menu_set_type(sym->type); - menu_add_symbol(P_CHOICE, sym, NULL); - prop = sym_get_choice_prop(sym); - for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) - ; - *ep = expr_alloc_one(E_CHOICE, NULL); - (*ep)->right.sym = menu->sym; - } - if (menu->list && (!menu->prompt || !menu->prompt->text)) { - for (last_menu = menu->list; ; last_menu = last_menu->next) { - last_menu->parent = parent; - if (!last_menu->next) - break; - } - last_menu->next = menu->next; - menu->next = menu->list; - menu->list = NULL; - } - } - - if (sym && !(sym->flags & SYMBOL_WARNED)) { - if (sym->type == S_UNKNOWN) - menu_warn(parent, "config symbol defined " - "without type\n"); - - if (sym_is_choice(sym) && !parent->prompt) - menu_warn(parent, "choice must have a prompt\n"); - - /* Check properties connected to this symbol */ - sym_check_prop(sym); - sym->flags |= SYMBOL_WARNED; - } - - if (sym && !sym_is_optional(sym) && parent->prompt) { - sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, - expr_alloc_and(parent->prompt->visible.expr, - expr_alloc_symbol(&symbol_mod))); - } -} - -bool menu_is_visible(struct menu *menu) -{ - struct menu *child; - struct symbol *sym; - tristate visible; - - if (!menu->prompt) - return false; - sym = menu->sym; - if (sym) { - sym_calc_value(sym); - visible = menu->prompt->visible.tri; - } else - visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); - - if (visible != no) - return true; - if (!sym || sym_get_tristate_value(menu->sym) == no) - return false; - - for (child = menu->list; child; child = child->next) - if (menu_is_visible(child)) - return true; - return false; -} - -const char *menu_get_prompt(struct menu *menu) -{ - if (menu->prompt) - return menu->prompt->text; - else if (menu->sym) - return menu->sym->name; - return NULL; -} - -struct menu *menu_get_root_menu(struct menu *menu) -{ - return &rootmenu; -} - -struct menu *menu_get_parent_menu(struct menu *menu) -{ - enum prop_type type; - - for (; menu != &rootmenu; menu = menu->parent) { - type = menu->prompt ? menu->prompt->type : 0; - if (type == P_MENU) - break; - } - return menu; -} - -struct file *file_lookup(const char *name) -{ - struct file *file; - - for (file = file_list; file; file = file->next) { - if (!strcmp(name, file->name)) - return file; - } - - file = malloc(sizeof(*file)); - memset(file, 0, sizeof(*file)); - file->name = strdup(name); - file->next = file_list; - file_list = file; - return file; -} - -int file_write_dep(const char *name) -{ - struct file *file; - FILE *out; - - if (!name) - name = ".config.cmd"; - out = fopen(".config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); - } - fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n"); - fclose(out); - rename(".config.tmp", name); - return 0; -} - diff --git a/config/menubox.c b/config/menubox.c deleted file mode 100644 index c2fd755b4..000000000 --- a/config/menubox.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * menubox.c -- implements the menu box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Changes by Clifford Wolf (god@clifford.at) - * - * [ 1998-06-13 ] - * - * *) A bugfix for the Page-Down problem - * - * *) Formerly when I used Page Down and Page Up, the cursor would be set - * to the first position in the menu box. Now lxdialog is a bit - * smarter and works more like other menu systems (just have a look at - * it). - * - * *) Formerly if I selected something my scrolling would be broken because - * lxdialog is re-invoked by the Menuconfig shell script, can't - * remember the last scrolling position, and just sets it so that the - * cursor is at the bottom of the box. Now it writes the temporary file - * lxdialog.scrltmp which contains this information. The file is - * deleted by lxdialog if the user leaves a submenu or enters a new - * one, but it would be nice if Menuconfig could make another "rm -f" - * just to be sure. Just try it out - you will recognise a difference! - * - * [ 1998-06-14 ] - * - * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files - * and menus change their size on the fly. - * - * *) If for some reason the last scrolling position is not saved by - * lxdialog, it sets the scrolling so that the selected item is in the - * middle of the menu box, not at the bottom. - * - * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) - * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. - * This fixes a bug in Menuconfig where using ' ' to descend into menus - * would leave mis-synchronized lxdialog.scrltmp files lying around, - * fscanf would read in 'scroll', and eventually that value would get used. - */ - -#include "dialog.h" - -static int menu_width, item_x; - -/* - * Print menu item - */ -static void -print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey) -{ - int j; - char menu_item[menu_width+1]; - - strncpy(menu_item, item, menu_width); - menu_item[menu_width] = 0; - j = first_alpha(menu_item, "YyNnMm"); - - /* Clear 'residue' of last item */ - wattrset (win, menubox_attr); - wmove (win, choice, 0); -#if OLD_NCURSES - { - int i; - for (i = 0; i < menu_width; i++) - waddch (win, ' '); - } -#else - wclrtoeol(win); -#endif - wattrset (win, selected ? item_selected_attr : item_attr); - mvwaddstr (win, choice, item_x, menu_item); -#if 0 - if (hotkey) { - wattrset (win, selected ? tag_key_selected_attr : tag_key_attr); - mvwaddch(win, choice, item_x+j, menu_item[j]); - } -#endif - if (selected) { - wmove (win, choice, item_x+1); - wrefresh (win); - } -} - -/* - * Print the scroll indicators. - */ -static void -print_arrows (WINDOW * win, int item_no, int scroll, - int y, int x, int height) -{ - int cur_y, cur_x; - - getyx(win, cur_y, cur_x); - - wmove(win, y, x); - - if (scroll > 0) { - wattrset (win, uarrow_attr); - waddch (win, ACS_UARROW); - waddstr (win, "(-)"); - } - else { - wattrset (win, menubox_attr); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - } - - y = y + height + 1; - wmove(win, y, x); - - if ((height < item_no) && (scroll + height < item_no)) { - wattrset (win, darrow_attr); - waddch (win, ACS_DARROW); - waddstr (win, "(+)"); - } - else { - wattrset (win, menubox_border_attr); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - waddch (win, ACS_HLINE); - } - - wmove(win, cur_y, cur_x); -} - -/* - * Display the termination buttons. - */ -static void -print_buttons (WINDOW *win, int height, int width, int selected) -{ - int x = width / 2 - 16; - int y = height - 2; - - print_button (win, "Select", y, x, selected == 0); - print_button (win, " Exit ", y, x + 12, selected == 1); - print_button (win, " Help ", y, x + 24, selected == 2); - - wmove(win, y, x+1+12*selected); - wrefresh (win); -} - -/* - * Display a menu for choosing among a number of options - */ -int -dialog_menu (const char *title, const char *prompt, int height, int width, - int menu_height, const char *current, int item_no, - struct dialog_list_item ** items) -{ - int i, j, x, y, box_x, box_y; - int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice; - WINDOW *dialog, *menu; - FILE *f; - - max_choice = MIN (menu_height, item_no); - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - wattrset (dialog, border_attr); - mvwaddch (dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - wbkgdset (dialog, dialog_attr & A_COLOR); - waddch (dialog, ACS_RTEE); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - - wattrset (dialog, dialog_attr); - print_autowrap (dialog, prompt, width - 2, 1, 3); - - menu_width = width - 6; - box_y = height - menu_height - 5; - box_x = (width - menu_width) / 2 - 1; - - /* create new window for the menu */ - menu = subwin (dialog, menu_height, menu_width, - y + box_y + 1, x + box_x + 1); - keypad (menu, TRUE); - - /* draw a box around the menu items */ - draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2, - menubox_border_attr, menubox_attr); - - /* - * Find length of longest item in order to center menu. - * Set 'choice' to default item. - */ - item_x = 0; - for (i = 0; i < item_no; i++) { - item_x = MAX (item_x, MIN(menu_width, strlen (items[i]->name) + 2)); - if (strcmp(current, items[i]->tag) == 0) choice = i; - } - - item_x = (menu_width - item_x) / 2; - - /* get the scroll info from the temp file */ - if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) { - if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) && - (scroll+max_choice > choice) && (scroll >= 0) && - (scroll+max_choice <= item_no) ) { - first_item = scroll; - choice = choice - scroll; - fclose(f); - } else { - scroll=0; - remove("lxdialog.scrltmp"); - fclose(f); - f=NULL; - } - } - if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) { - if (choice >= item_no-max_choice/2) - scroll = first_item = item_no-max_choice; - else - scroll = first_item = choice - max_choice/2; - choice = choice - scroll; - } - - /* Print the menu */ - for (i=0; i < max_choice; i++) { - print_item (menu, items[first_item + i]->name, i, i == choice, - (items[first_item + i]->tag[0] != ':')); - } - - wnoutrefresh (menu); - - print_arrows(dialog, item_no, scroll, - box_y, box_x+item_x+1, menu_height); - - print_buttons (dialog, height, width, 0); - wmove (menu, choice, item_x+1); - wrefresh (menu); - - while (key != ESC) { - key = wgetch(menu); - - if (key < 256 && isalpha(key)) key = tolower(key); - - if (strchr("ynm", key)) - i = max_choice; - else { - for (i = choice+1; i < max_choice; i++) { - j = first_alpha(items[scroll + i]->name, "YyNnMm>"); - if (key == tolower(items[scroll + i]->name[j])) - break; - } - if (i == max_choice) - for (i = 0; i < max_choice; i++) { - j = first_alpha(items[scroll + i]->name, "YyNnMm>"); - if (key == tolower(items[scroll + i]->name[j])) - break; - } - } - - if (i < max_choice || - key == KEY_UP || key == KEY_DOWN || - key == '-' || key == '+' || - key == KEY_PPAGE || key == KEY_NPAGE) { - - print_item (menu, items[scroll + choice]->name, choice, FALSE, - (items[scroll + choice]->tag[0] != ':')); - - if (key == KEY_UP || key == '-') { - if (choice < 2 && scroll) { - /* Scroll menu down */ - scrollok (menu, TRUE); - wscrl (menu, -1); - scrollok (menu, FALSE); - - scroll--; - - print_item (menu, items[scroll]->name, 0, FALSE, - (items[scroll]->tag[0] != ':')); - } else - choice = MAX(choice - 1, 0); - - } else if (key == KEY_DOWN || key == '+') { - - print_item (menu, items[scroll + choice]->name, choice, FALSE, - (items[scroll + choice]->tag[0] != ':')); - - if ((choice > max_choice-3) && - (scroll + max_choice < item_no) - ) { - /* Scroll menu up */ - scrollok (menu, TRUE); - scroll (menu); - scrollok (menu, FALSE); - - scroll++; - - print_item (menu, items[scroll + max_choice - 1]->name, - max_choice-1, FALSE, - (items[scroll + max_choice - 1]->tag[0] != ':')); - } else - choice = MIN(choice+1, max_choice-1); - - } else if (key == KEY_PPAGE) { - scrollok (menu, TRUE); - for (i=0; (i < max_choice); i++) { - if (scroll > 0) { - wscrl (menu, -1); - scroll--; - print_item (menu, items[scroll]->name, 0, FALSE, - (items[scroll]->tag[0] != ':')); - } else { - if (choice > 0) - choice--; - } - } - scrollok (menu, FALSE); - - } else if (key == KEY_NPAGE) { - for (i=0; (i < max_choice); i++) { - if (scroll+max_choice < item_no) { - scrollok (menu, TRUE); - scroll(menu); - scrollok (menu, FALSE); - scroll++; - print_item (menu, items[scroll + max_choice - 1]->name, - max_choice-1, FALSE, - (items[scroll + max_choice - 1]->tag[0] != ':')); - } else { - if (choice+1 < max_choice) - choice++; - } - } - - } else - choice = i; - - print_item (menu, items[scroll + choice]->name, choice, TRUE, - (items[scroll + choice]->tag[0] != ':')); - - print_arrows(dialog, item_no, scroll, - box_y, box_x+item_x+1, menu_height); - - wnoutrefresh (dialog); - wrefresh (menu); - - continue; /* wait for another key press */ - } - - switch (key) { - case KEY_LEFT: - case TAB: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 2 : (button > 2 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh (menu); - break; - case ' ': - case 's': - case 'y': - case 'n': - case 'm': - /* save scroll info */ - if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) { - fprintf(f,"%d\n",scroll); - fclose(f); - } - delwin (dialog); - items[scroll + choice]->selected = 1; - switch (key) { - case 's': return 3; - case 'y': return 3; - case 'n': return 4; - case 'm': return 5; - case ' ': return 6; - } - return 0; - case 'h': - case '?': - button = 2; - case '\n': - delwin (dialog); - items[scroll + choice]->selected = 1; - - remove("lxdialog.scrltmp"); - return button; - case 'e': - case 'x': - key = ESC; - case ESC: - break; - } - } - - delwin (dialog); - remove("lxdialog.scrltmp"); - return -1; /* ESC pressed */ -} diff --git a/config/msgbox.c b/config/msgbox.c deleted file mode 100644 index 93692e1fb..000000000 --- a/config/msgbox.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * msgbox.c -- implements the message box and info box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - -/* - * Display a message box. Program will pause and display an "OK" button - * if the parameter 'pause' is non-zero. - */ -int -dialog_msgbox (const char *title, const char *prompt, int height, int width, - int pause) -{ - int i, x, y, key = 0; - WINDOW *dialog; - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - wattrset (dialog, dialog_attr); - print_autowrap (dialog, prompt, width - 2, 1, 2); - - if (pause) { - wattrset (dialog, border_attr); - mvwaddch (dialog, height - 3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - waddch (dialog, ACS_RTEE); - - print_button (dialog, " Ok ", - height - 2, width / 2 - 4, TRUE); - - wrefresh (dialog); - while (key != ESC && key != '\n' && key != ' ' && - key != 'O' && key != 'o' && key != 'X' && key != 'x') - key = wgetch (dialog); - } else { - key = '\n'; - wrefresh (dialog); - } - - delwin (dialog); - return key == ESC ? -1 : 0; -} diff --git a/config/symbol.c b/config/symbol.c deleted file mode 100644 index b9d2c3d2a..000000000 --- a/config/symbol.c +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -extern int output_mode; - -struct symbol symbol_yes = { - .name = "y", - .curr = { "y", yes }, - .flags = SYMBOL_YES|SYMBOL_VALID, -}, symbol_mod = { - .name = "m", - .curr = { "m", mod }, - .flags = SYMBOL_MOD|SYMBOL_VALID, -}, symbol_no = { - .name = "n", - .curr = { "n", no }, - .flags = SYMBOL_NO|SYMBOL_VALID, -}, symbol_empty = { - .name = "", - .curr = { "", no }, - .flags = SYMBOL_VALID, -}; - -int sym_change_count; -struct symbol *modules_sym; -tristate modules_val; - -void sym_add_default(struct symbol *sym, const char *def) -{ - struct property *prop = prop_alloc(P_DEFAULT, sym); - - prop->expr = expr_alloc_symbol(sym_lookup(def, 1)); -} - -void sym_init(void) -{ - struct symbol *sym; - char *p; - static bool inited = false; - - if (inited) - return; - inited = true; - - sym = sym_lookup("VERSION", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - p = getenv("VERSION"); - if (p) - sym_add_default(sym, p); - - sym = sym_lookup("TARGET_ARCH", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - p = getenv("TARGET_ARCH"); - if (p) - sym_add_default(sym, p); - -} - -enum symbol_type sym_get_type(struct symbol *sym) -{ - enum symbol_type type = sym->type; - - if (type == S_TRISTATE) { - if (sym_is_choice_value(sym) && sym->visible == yes) - type = S_BOOLEAN; - else if (modules_val == no) - type = S_BOOLEAN; - } - return type; -} - -const char *sym_type_name(enum symbol_type type) -{ - switch (type) { - case S_BOOLEAN: - return "boolean"; - case S_TRISTATE: - return "tristate"; - case S_INT: - return "integer"; - case S_HEX: - return "hex"; - case S_STRING: - return "string"; - case S_UNKNOWN: - return "unknown"; - case S_OTHER: - break; - } - return "???"; -} - -struct property *sym_get_choice_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_choices(sym, prop) - return prop; - return NULL; -} - -struct property *sym_get_default_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no || output_mode) - return prop; - } - return NULL; -} - -struct property *sym_get_range_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_RANGE) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no) - return prop; - } - return NULL; -} - -static void sym_calc_visibility(struct symbol *sym) -{ - struct property *prop; - tristate tri; - bool deselected = false; - - /* any prompt visible? */ - tri = no; - for_all_prompts(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - tri = E_OR(tri, prop->visible.tri); - } - if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) - tri = yes; - if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) { - tri = no; - deselected = true; - } - if (sym->visible != tri) { - sym->visible = tri; - sym_set_changed(sym); - } - if (sym_is_choice_value(sym) || deselected) - return; - tri = no; - if (sym->rev_dep.expr) - tri = expr_calc_value(sym->rev_dep.expr); - if (tri == mod && sym_get_type(sym) == S_BOOLEAN) - tri = yes; - if (sym->rev_dep.tri != tri) { - sym->rev_dep.tri = tri; - sym_set_changed(sym); - } -} - -static struct symbol *sym_calc_choice(struct symbol *sym) -{ - struct symbol *def_sym; - struct property *prop; - struct expr *e; - - /* is the user choice visible? */ - def_sym = sym->user.val; - if (def_sym) { - sym_calc_visibility(def_sym); - if (def_sym->visible != no) - return def_sym; - } - - /* any of the defaults visible? */ - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri == no) - continue; - def_sym = prop_get_symbol(prop); - sym_calc_visibility(def_sym); - if (def_sym->visible != no) - return def_sym; - } - - /* just get the first visible value */ - prop = sym_get_choice_prop(sym); - for (e = prop->expr; e; e = e->left.expr) { - def_sym = e->right.sym; - sym_calc_visibility(def_sym); - if (def_sym->visible != no) - return def_sym; - } - - /* no choice? reset tristate value */ - sym->curr.tri = no; - return NULL; -} - -void sym_calc_value(struct symbol *sym) -{ - struct symbol_value newval, oldval; - struct property *prop; - struct expr *e; - - if (!sym) - return; - - if (sym->flags & SYMBOL_VALID) - return; - sym->flags |= SYMBOL_VALID; - - oldval = sym->curr; - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - newval = symbol_empty.curr; - break; - case S_BOOLEAN: - case S_TRISTATE: - newval = symbol_no.curr; - break; - default: - sym->curr.val = sym->name; - sym->curr.tri = no; - return; - } - if (!sym_is_choice_value(sym)) - sym->flags &= ~SYMBOL_WRITE; - - sym_calc_visibility(sym); - - /* set default if recursively called */ - sym->curr = newval; - - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_is_choice_value(sym) && sym->visible == yes) { - prop = sym_get_choice_prop(sym); - newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; - } else if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) { - newval.tri = no; - } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) - newval.tri = sym->user.tri; - else if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) - newval.tri = expr_calc_value(prop->expr); - } - newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri); - } else if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) { - sym->flags |= SYMBOL_WRITE; - newval.tri = expr_calc_value(prop->expr); - } - } - if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) - newval.tri = yes; - break; - case S_STRING: - case S_HEX: - case S_INT: - if (sym->visible != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) { - newval.val = sym->user.val; - break; - } - } - prop = sym_get_default_prop(sym); - if (prop) { - struct symbol *ds = prop_get_symbol(prop); - if (ds) { - sym->flags |= SYMBOL_WRITE; - sym_calc_value(ds); - newval.val = ds->curr.val; - } - } - break; - default: - ; - } - - sym->curr = newval; - if (sym_is_choice(sym) && newval.tri == yes) - sym->curr.val = sym_calc_choice(sym); - - if (memcmp(&oldval, &sym->curr, sizeof(oldval))) - sym_set_changed(sym); - if (modules_sym == sym) - modules_val = modules_sym->curr.tri; - - if (sym_is_choice(sym)) { - int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); - prop = sym_get_choice_prop(sym); - for (e = prop->expr; e; e = e->left.expr) { - e->right.sym->flags |= flags; - if (flags & SYMBOL_CHANGED) - sym_set_changed(e->right.sym); - } - } -} - -void sym_clear_all_valid(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym->flags &= ~SYMBOL_VALID; - sym_change_count++; - if (modules_sym) - sym_calc_value(modules_sym); -} - -void sym_set_changed(struct symbol *sym) -{ - struct property *prop; - - sym->flags |= SYMBOL_CHANGED; - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu) - prop->menu->flags |= MENU_CHANGED; - } -} - -void sym_set_all_changed(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym_set_changed(sym); -} - -bool sym_tristate_within_range(struct symbol *sym, tristate val) -{ - int type = sym_get_type(sym); - - if (sym->visible == no) - return false; - - if (type != S_BOOLEAN && type != S_TRISTATE) - return false; - - if (type == S_BOOLEAN && val == mod) - return false; - if (sym->visible <= sym->rev_dep.tri) - return false; - if (sym_is_choice_value(sym) && sym->visible == yes) - return val == yes; - return val >= sym->rev_dep.tri && val <= sym->visible; -} - -bool sym_set_tristate_value(struct symbol *sym, tristate val) -{ - tristate oldval = sym_get_tristate_value(sym); - - if (oldval != val && !sym_tristate_within_range(sym, val)) - return false; - - if (sym->flags & SYMBOL_NEW) { - sym->flags &= ~SYMBOL_NEW; - sym_set_changed(sym); - } - if (sym_is_choice_value(sym) && val == yes) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - - cs->user.val = sym; - cs->flags &= ~SYMBOL_NEW; - } - - sym->user.tri = val; - if (oldval != val) { - sym_clear_all_valid(); - if (sym == modules_sym) - sym_set_all_changed(); - } - - return true; -} - -tristate sym_toggle_tristate_value(struct symbol *sym) -{ - tristate oldval, newval; - - oldval = newval = sym_get_tristate_value(sym); - do { - switch (newval) { - case no: - newval = mod; - break; - case mod: - newval = yes; - break; - case yes: - newval = no; - break; - } - if (sym_set_tristate_value(sym, newval)) - break; - } while (oldval != newval); - return newval; -} - -bool sym_string_valid(struct symbol *sym, const char *str) -{ - char ch; - - switch (sym->type) { - case S_STRING: - return true; - case S_INT: - ch = *str++; - if (ch == '-') - ch = *str++; - if (!isdigit(ch)) - return false; - if (ch == '0' && *str != 0) - return false; - while ((ch = *str++)) { - if (!isdigit(ch)) - return false; - } - return true; - case S_HEX: - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - str += 2; - ch = *str++; - do { - if (!isxdigit(ch)) - return false; - } while ((ch = *str++)); - return true; - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - case 'm': case 'M': - case 'n': case 'N': - return true; - } - return false; - default: - return false; - } -} - -bool sym_string_within_range(struct symbol *sym, const char *str) -{ - struct property *prop; - int val; - - switch (sym->type) { - case S_STRING: - return sym_string_valid(sym, str); - case S_INT: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtol(str, NULL, 10); - return val >= strtol(prop->expr->left.sym->name, NULL, 10) && - val <= strtol(prop->expr->right.sym->name, NULL, 10); - case S_HEX: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtol(str, NULL, 16); - return val >= strtol(prop->expr->left.sym->name, NULL, 16) && - val <= strtol(prop->expr->right.sym->name, NULL, 16); - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - return sym_tristate_within_range(sym, yes); - case 'm': case 'M': - return sym_tristate_within_range(sym, mod); - case 'n': case 'N': - return sym_tristate_within_range(sym, no); - } - return false; - default: - return false; - } -} - -bool sym_set_string_value(struct symbol *sym, const char *newval) -{ - const char *oldval; - char *val; - int size; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (newval[0]) { - case 'y': case 'Y': - return sym_set_tristate_value(sym, yes); - case 'm': case 'M': - return sym_set_tristate_value(sym, mod); - case 'n': case 'N': - return sym_set_tristate_value(sym, no); - } - return false; - default: - ; - } - - if (!sym_string_within_range(sym, newval)) - return false; - - if (sym->flags & SYMBOL_NEW) { - sym->flags &= ~SYMBOL_NEW; - sym_set_changed(sym); - } - - oldval = sym->user.val; - size = strlen(newval) + 1; - if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { - size += 2; - sym->user.val = val = malloc(size); - *val++ = '0'; - *val++ = 'x'; - } else if (!oldval || strcmp(oldval, newval)) - sym->user.val = val = malloc(size); - else - return true; - - strcpy(val, newval); - free((void *)oldval); - sym_clear_all_valid(); - - return true; -} - -const char *sym_get_string_value(struct symbol *sym) -{ - tristate val; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - val = sym_get_tristate_value(sym); - switch (val) { - case no: - return "n"; - case mod: - return "m"; - case yes: - return "y"; - } - break; - default: - ; - } - return (const char *)sym->curr.val; -} - -bool sym_is_changable(struct symbol *sym) -{ - return sym->visible > sym->rev_dep.tri; -} - -struct symbol *sym_lookup(const char *name, int isconst) -{ - struct symbol *symbol; - const char *ptr; - char *new_name; - int hash = 0; - - if (name) { - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name)) { - if ((isconst && symbol->flags & SYMBOL_CONST) || - (!isconst && !(symbol->flags & SYMBOL_CONST))) - return symbol; - } - } - new_name = strdup(name); - } else { - new_name = NULL; - hash = 256; - } - - symbol = malloc(sizeof(*symbol)); - memset(symbol, 0, sizeof(*symbol)); - symbol->name = new_name; - symbol->type = S_UNKNOWN; - symbol->flags = SYMBOL_NEW; - if (isconst) - symbol->flags |= SYMBOL_CONST; - - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; - - return symbol; -} - -struct symbol *sym_find(const char *name) -{ - struct symbol *symbol = NULL; - const char *ptr; - int hash = 0; - - if (!name) - return NULL; - - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name) && - !(symbol->flags & SYMBOL_CONST)) - break; - } - - return symbol; -} - -struct symbol *sym_check_deps(struct symbol *sym); - -static struct symbol *sym_check_expr_deps(struct expr *e) -{ - struct symbol *sym; - - if (!e) - return NULL; - switch (e->type) { - case E_OR: - case E_AND: - sym = sym_check_expr_deps(e->left.expr); - if (sym) - return sym; - return sym_check_expr_deps(e->right.expr); - case E_NOT: - return sym_check_expr_deps(e->left.expr); - case E_EQUAL: - case E_UNEQUAL: - sym = sym_check_deps(e->left.sym); - if (sym) - return sym; - return sym_check_deps(e->right.sym); - case E_SYMBOL: - return sym_check_deps(e->left.sym); - default: - break; - } - printf("Oops! How to check %d?\n", e->type); - return NULL; -} - -struct symbol *sym_check_deps(struct symbol *sym) -{ - struct symbol *sym2; - struct property *prop; - - if (sym->flags & SYMBOL_CHECK_DONE) - return NULL; - if (sym->flags & SYMBOL_CHECK) { - printf("Warning! Found recursive dependency: %s", sym->name); - return sym; - } - - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - sym2 = sym_check_expr_deps(sym->rev_dep.expr); - if (sym2) - goto out; - - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT || prop->type == P_SELECTNOT) - continue; - sym2 = sym_check_expr_deps(prop->visible.expr); - if (sym2) - goto out; - if (prop->type != P_DEFAULT || sym_is_choice(sym)) - continue; - sym2 = sym_check_expr_deps(prop->expr); - if (sym2) - goto out; - } -out: - if (sym2) - printf(" %s", sym->name); - sym->flags &= ~SYMBOL_CHECK; - return sym2; -} - -struct property *prop_alloc(enum prop_type type, struct symbol *sym) -{ - struct property *prop; - struct property **propp; - - prop = malloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->sym = sym; - prop->file = current_file; - prop->lineno = zconf_lineno(); - - /* append property to the prop list of symbol */ - if (sym) { - for (propp = &sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; - } - - return prop; -} - -struct symbol *prop_get_symbol(struct property *prop) -{ - if (prop->expr && (prop->expr->type == E_SYMBOL || - prop->expr->type == E_CHOICE)) - return prop->expr->left.sym; - return NULL; -} - -const char *prop_get_type_name(enum prop_type type) -{ - switch (type) { - case P_PROMPT: - return "prompt"; - case P_COMMENT: - return "comment"; - case P_MENU: - return "menu"; - case P_DEFAULT: - return "default"; - case P_CHOICE: - return "choice"; - case P_SELECT: - case P_SELECTNOT: - return "select"; - case P_RANGE: - return "range"; - case P_UNKNOWN: - break; - } - return "unknown"; -} diff --git a/config/textbox.c b/config/textbox.c deleted file mode 100644 index a5a460b5c..000000000 --- a/config/textbox.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * textbox.c -- implements the text box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - -static void back_lines (int n); -static void print_page (WINDOW * win, int height, int width); -static void print_line (WINDOW * win, int row, int width); -static char *get_line (void); -static void print_position (WINDOW * win, int height, int width); - -static int hscroll, fd, file_size, bytes_read; -static int begin_reached = 1, end_reached, page_length; -static char *buf, *page; - -/* - * Display text from a file in a dialog box. - */ -int -dialog_textbox (const char *title, const char *file, int height, int width) -{ - int i, x, y, cur_x, cur_y, fpos, key = 0; - int passed_end; - char search_term[MAX_LEN + 1]; - WINDOW *dialog, *text; - - search_term[0] = '\0'; /* no search term entered yet */ - - /* Open input file for reading */ - if ((fd = open (file, O_RDONLY)) == -1) { - endwin (); - fprintf (stderr, - "\nCan't open input file in dialog_textbox().\n"); - exit (-1); - } - /* Get file size. Actually, 'file_size' is the real file size - 1, - since it's only the last byte offset from the beginning */ - if ((file_size = lseek (fd, 0, SEEK_END)) == -1) { - endwin (); - fprintf (stderr, "\nError getting file size in dialog_textbox().\n"); - exit (-1); - } - /* Restore file pointer to beginning of file after getting file size */ - if (lseek (fd, 0, SEEK_SET) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n"); - exit (-1); - } - /* Allocate space for read buffer */ - if ((buf = malloc (BUF_SIZE + 1)) == NULL) { - endwin (); - fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n"); - exit (-1); - } - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, "\nError reading file in dialog_textbox().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; /* mark end of valid data */ - page = buf; /* page is pointer to start of page to be displayed */ - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - /* Create window for text region, used for scrolling text */ - text = subwin (dialog, height - 4, width - 2, y + 1, x + 1); - wattrset (text, dialog_attr); - wbkgdset (text, dialog_attr & A_COLOR); - - keypad (text, TRUE); - - /* register the new window, along with its borders */ - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - - wattrset (dialog, border_attr); - mvwaddch (dialog, height-3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - wbkgdset (dialog, dialog_attr & A_COLOR); - waddch (dialog, ACS_RTEE); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE); - wnoutrefresh (dialog); - getyx (dialog, cur_y, cur_x); /* Save cursor position */ - - /* Print first page of text */ - attr_clear (text, height - 4, width - 2, dialog_attr); - print_page (text, height - 4, width - 2); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh (dialog); - - while ((key != ESC) && (key != '\n')) { - key = wgetch (dialog); - switch (key) { - case 'E': /* Exit */ - case 'e': - case 'X': - case 'x': - delwin (dialog); - free (buf); - close (fd); - return 0; - case 'g': /* First page */ - case KEY_HOME: - if (!begin_reached) { - begin_reached = 1; - /* First page not in buffer? */ - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, - "\nError moving file pointer in dialog_textbox().\n"); - exit (-1); - } - if (fpos > bytes_read) { /* Yes, we have to read it in */ - if (lseek (fd, 0, SEEK_SET) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in " - "dialog_textbox().\n"); - exit (-1); - } - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, - "\nError reading file in dialog_textbox().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; - } - page = buf; - print_page (text, height - 4, width - 2); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh (dialog); - } - break; - case 'G': /* Last page */ - case KEY_END: - - end_reached = 1; - /* Last page not in buffer? */ - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, - "\nError moving file pointer in dialog_textbox().\n"); - exit (-1); - } - if (fpos < file_size) { /* Yes, we have to read it in */ - if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) { - endwin (); - fprintf (stderr, - "\nError moving file pointer in dialog_textbox().\n"); - exit (-1); - } - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, - "\nError reading file in dialog_textbox().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; - } - page = buf + bytes_read; - back_lines (height - 4); - print_page (text, height - 4, width - 2); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh (dialog); - break; - case 'K': /* Previous line */ - case 'k': - case KEY_UP: - if (!begin_reached) { - back_lines (page_length + 1); - - /* We don't call print_page() here but use scrolling to ensure - faster screen update. However, 'end_reached' and - 'page_length' should still be updated, and 'page' should - point to start of next page. This is done by calling - get_line() in the following 'for' loop. */ - scrollok (text, TRUE); - wscrl (text, -1); /* Scroll text region down one line */ - scrollok (text, FALSE); - page_length = 0; - passed_end = 0; - for (i = 0; i < height - 4; i++) { - if (!i) { - /* print first line of page */ - print_line (text, 0, width - 2); - wnoutrefresh (text); - } else - /* Called to update 'end_reached' and 'page' */ - get_line (); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } - - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh (dialog); - } - break; - case 'B': /* Previous page */ - case 'b': - case KEY_PPAGE: - if (begin_reached) - break; - back_lines (page_length + height - 4); - print_page (text, height - 4, width - 2); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); - wrefresh (dialog); - break; - case 'J': /* Next line */ - case 'j': - case KEY_DOWN: - if (!end_reached) { - begin_reached = 0; - scrollok (text, TRUE); - scroll (text); /* Scroll text region up one line */ - scrollok (text, FALSE); - print_line (text, height - 5, width - 2); - wnoutrefresh (text); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh (dialog); - } - break; - case KEY_NPAGE: /* Next page */ - case ' ': - if (end_reached) - break; - - begin_reached = 0; - print_page (text, height - 4, width - 2); - print_position (dialog, height, width); - wmove (dialog, cur_y, cur_x); - wrefresh (dialog); - break; - case '0': /* Beginning of line */ - case 'H': /* Scroll left */ - case 'h': - case KEY_LEFT: - if (hscroll <= 0) - break; - - if (key == '0') - hscroll = 0; - else - hscroll--; - /* Reprint current page to scroll horizontally */ - back_lines (page_length); - print_page (text, height - 4, width - 2); - wmove (dialog, cur_y, cur_x); - wrefresh (dialog); - break; - case 'L': /* Scroll right */ - case 'l': - case KEY_RIGHT: - if (hscroll >= MAX_LEN) - break; - hscroll++; - /* Reprint current page to scroll horizontally */ - back_lines (page_length); - print_page (text, height - 4, width - 2); - wmove (dialog, cur_y, cur_x); - wrefresh (dialog); - break; - case ESC: - break; - } - } - - delwin (dialog); - free (buf); - close (fd); - return 1; /* ESC pressed */ -} - -/* - * Go back 'n' lines in text file. Called by dialog_textbox(). - * 'page' will be updated to point to the desired line in 'buf'. - */ -static void -back_lines (int n) -{ - int i, fpos; - - begin_reached = 0; - /* We have to distinguish between end_reached and !end_reached - since at end of file, the line is not ended by a '\n'. - The code inside 'if' basically does a '--page' to move one - character backward so as to skip '\n' of the previous line */ - if (!end_reached) { - /* Either beginning of buffer or beginning of file reached? */ - if (page == buf) { - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in " - "back_lines().\n"); - exit (-1); - } - if (fpos > bytes_read) { /* Not beginning of file yet */ - /* We've reached beginning of buffer, but not beginning of - file yet, so read previous part of file into buffer. - Note that we only move backward for BUF_SIZE/2 bytes, - but not BUF_SIZE bytes to avoid re-reading again in - print_page() later */ - /* Really possible to move backward BUF_SIZE/2 bytes? */ - if (fpos < BUF_SIZE / 2 + bytes_read) { - /* No, move less then */ - if (lseek (fd, 0, SEEK_SET) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in " - "back_lines().\n"); - exit (-1); - } - page = buf + fpos - bytes_read; - } else { /* Move backward BUF_SIZE/2 bytes */ - if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) - == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer " - "in back_lines().\n"); - exit (-1); - } - page = buf + BUF_SIZE / 2; - } - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, "\nError reading file in back_lines().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; - } else { /* Beginning of file reached */ - begin_reached = 1; - return; - } - } - if (*(--page) != '\n') { /* '--page' here */ - /* Something's wrong... */ - endwin (); - fprintf (stderr, "\nInternal error in back_lines().\n"); - exit (-1); - } - } - /* Go back 'n' lines */ - for (i = 0; i < n; i++) - do { - if (page == buf) { - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, - "\nError moving file pointer in back_lines().\n"); - exit (-1); - } - if (fpos > bytes_read) { - /* Really possible to move backward BUF_SIZE/2 bytes? */ - if (fpos < BUF_SIZE / 2 + bytes_read) { - /* No, move less then */ - if (lseek (fd, 0, SEEK_SET) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer " - "in back_lines().\n"); - exit (-1); - } - page = buf + fpos - bytes_read; - } else { /* Move backward BUF_SIZE/2 bytes */ - if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), - SEEK_CUR) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer" - " in back_lines().\n"); - exit (-1); - } - page = buf + BUF_SIZE / 2; - } - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, "\nError reading file in " - "back_lines().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; - } else { /* Beginning of file reached */ - begin_reached = 1; - return; - } - } - } while (*(--page) != '\n'); - page++; -} - -/* - * Print a new page of text. Called by dialog_textbox(). - */ -static void -print_page (WINDOW * win, int height, int width) -{ - int i, passed_end = 0; - - page_length = 0; - for (i = 0; i < height; i++) { - print_line (win, i, width); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } - wnoutrefresh (win); -} - -/* - * Print a new line of text. Called by dialog_textbox() and print_page(). - */ -static void -print_line (WINDOW * win, int row, int width) -{ - int y, x; - char *line; - - line = get_line (); - line += MIN (strlen (line), hscroll); /* Scroll horizontally */ - wmove (win, row, 0); /* move cursor to correct line */ - waddch (win, ' '); - waddnstr (win, line, MIN (strlen (line), width - 2)); - - getyx (win, y, x); - /* Clear 'residue' of previous line */ -#if OLD_NCURSES - { - int i; - for (i = 0; i < width - x; i++) - waddch (win, ' '); - } -#else - wclrtoeol(win); -#endif -} - -/* - * Return current line of text. Called by dialog_textbox() and print_line(). - * 'page' should point to start of current line before calling, and will be - * updated to point to start of next line. - */ -static char * -get_line (void) -{ - int i = 0, fpos; - static char line[MAX_LEN + 1]; - - end_reached = 0; - while (*page != '\n') { - if (*page == '\0') { - /* Either end of file or end of buffer reached */ - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in " - "get_line().\n"); - exit (-1); - } - if (fpos < file_size) { /* Not end of file yet */ - /* We've reached end of buffer, but not end of file yet, - so read next part of file into buffer */ - if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { - endwin (); - fprintf (stderr, "\nError reading file in get_line().\n"); - exit (-1); - } - buf[bytes_read] = '\0'; - page = buf; - } else { - if (!end_reached) - end_reached = 1; - break; - } - } else if (i < MAX_LEN) - line[i++] = *(page++); - else { - /* Truncate lines longer than MAX_LEN characters */ - if (i == MAX_LEN) - line[i++] = '\0'; - page++; - } - } - if (i <= MAX_LEN) - line[i] = '\0'; - if (!end_reached) - page++; /* move pass '\n' */ - - return line; -} - -/* - * Print current position - */ -static void -print_position (WINDOW * win, int height, int width) -{ - int fpos, percent; - - if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { - endwin (); - fprintf (stderr, "\nError moving file pointer in print_position().\n"); - exit (-1); - } - wattrset (win, position_indicator_attr); - wbkgdset (win, position_indicator_attr & A_COLOR); - percent = !file_size ? - 100 : ((fpos - bytes_read + page - buf) * 100) / file_size; - wmove (win, height - 3, width - 9); - wprintw (win, "(%3d%%)", percent); -} diff --git a/config/util.c b/config/util.c deleted file mode 100644 index 0a2f82757..000000000 --- a/config/util.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * util.c - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - - -/* use colors by default? */ -bool use_colors = 1; - -char *backtitle = NULL; - -const char *dialog_result; - -/* - * Attribute values, default is for mono display - */ -chtype attributes[] = -{ - A_NORMAL, /* screen_attr */ - A_NORMAL, /* shadow_attr */ - A_NORMAL, /* dialog_attr */ - A_BOLD, /* title_attr */ - A_NORMAL, /* border_attr */ - A_REVERSE, /* button_active_attr */ - A_DIM, /* button_inactive_attr */ - A_REVERSE, /* button_key_active_attr */ - A_BOLD, /* button_key_inactive_attr */ - A_REVERSE, /* button_label_active_attr */ - A_NORMAL, /* button_label_inactive_attr */ - A_NORMAL, /* inputbox_attr */ - A_NORMAL, /* inputbox_border_attr */ - A_NORMAL, /* searchbox_attr */ - A_BOLD, /* searchbox_title_attr */ - A_NORMAL, /* searchbox_border_attr */ - A_BOLD, /* position_indicator_attr */ - A_NORMAL, /* menubox_attr */ - A_NORMAL, /* menubox_border_attr */ - A_NORMAL, /* item_attr */ - A_REVERSE, /* item_selected_attr */ - A_BOLD, /* tag_attr */ - A_REVERSE, /* tag_selected_attr */ - A_BOLD, /* tag_key_attr */ - A_REVERSE, /* tag_key_selected_attr */ - A_BOLD, /* check_attr */ - A_REVERSE, /* check_selected_attr */ - A_BOLD, /* uarrow_attr */ - A_BOLD /* darrow_attr */ -}; - - -#include "colors.h" - -/* - * Table of color values - */ -int color_table[][3] = -{ - {SCREEN_FG, SCREEN_BG, SCREEN_HL}, - {SHADOW_FG, SHADOW_BG, SHADOW_HL}, - {DIALOG_FG, DIALOG_BG, DIALOG_HL}, - {TITLE_FG, TITLE_BG, TITLE_HL}, - {BORDER_FG, BORDER_BG, BORDER_HL}, - {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL}, - {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL}, - {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL}, - {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL}, - {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL}, - {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG, - BUTTON_LABEL_INACTIVE_HL}, - {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL}, - {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL}, - {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL}, - {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL}, - {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL}, - {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL}, - {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL}, - {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL}, - {ITEM_FG, ITEM_BG, ITEM_HL}, - {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL}, - {TAG_FG, TAG_BG, TAG_HL}, - {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL}, - {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL}, - {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL}, - {CHECK_FG, CHECK_BG, CHECK_HL}, - {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL}, - {UARROW_FG, UARROW_BG, UARROW_HL}, - {DARROW_FG, DARROW_BG, DARROW_HL}, -}; /* color_table */ - -/* - * Set window to attribute 'attr' - */ -void -attr_clear (WINDOW * win, int height, int width, chtype attr) -{ - int i, j; - - wattrset (win, attr); - for (i = 0; i < height; i++) { - wmove (win, i, 0); - for (j = 0; j < width; j++) - waddch (win, ' '); - } - touchwin (win); -} - -void dialog_clear (void) -{ - attr_clear (stdscr, LINES, COLS, screen_attr); - /* Display background title if it exists ... - SLH */ - if (backtitle != NULL) { - int i; - - wattrset (stdscr, screen_attr); - mvwaddstr (stdscr, 0, 1, (char *)backtitle); - wmove (stdscr, 1, 1); - for (i = 1; i < COLS - 1; i++) - waddch (stdscr, ACS_HLINE); - } - wnoutrefresh (stdscr); -} - -/* - * Do some initialization for dialog - */ -void -init_dialog (void) -{ - initscr (); /* Init curses */ - keypad (stdscr, TRUE); - cbreak (); - noecho (); - - - if (use_colors) /* Set up colors */ - color_setup (); - - - dialog_clear (); -} - -/* - * Setup for color display - */ -void -color_setup (void) -{ - int i; - - if (has_colors ()) { /* Terminal supports color? */ - start_color (); - - /* Initialize color pairs */ - for (i = 0; i < ATTRIBUTE_COUNT; i++) - init_pair (i + 1, color_table[i][0], color_table[i][1]); - - /* Setup color attributes */ - for (i = 0; i < ATTRIBUTE_COUNT; i++) - attributes[i] = C_ATTR (color_table[i][2], i + 1); - } -} - -/* - * End using dialog functions. - */ -void -end_dialog (void) -{ - endwin (); -} - - -/* - * Print a string of text in a window, automatically wrap around to the - * next line if the string is too long to fit on one line. Newline - * characters '\n' are replaced by spaces. We start on a new line - * if there is no room for at least 4 nonblanks following a double-space. - */ -void -print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x) -{ - int newl, cur_x, cur_y; - int i, prompt_len, room, wlen; - char tempstr[MAX_LEN + 1], *word, *sp, *sp2; - - strcpy (tempstr, prompt); - - prompt_len = strlen(tempstr); - - /* - * Remove newlines - */ - for(i=0; i room || - (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room - && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) { - cur_y++; - cur_x = x; - } - wmove (win, cur_y, cur_x); - waddstr (win, word); - getyx (win, cur_y, cur_x); - cur_x++; - if (sp && *sp == ' ') { - cur_x++; /* double space */ - while (*++sp == ' '); - newl = 1; - } else - newl = 0; - word = sp; - } - } -} - -/* - * Print a button - */ -void -print_button (WINDOW * win, const char *label, int y, int x, int selected) -{ - int i, temp; - - wmove (win, y, x); - wattrset (win, selected ? button_active_attr : button_inactive_attr); - waddstr (win, "<"); - temp = strspn (label, " "); - label += temp; - wattrset (win, selected ? button_label_active_attr - : button_label_inactive_attr); - for (i = 0; i < temp; i++) - waddch (win, ' '); - wattrset (win, selected ? button_key_active_attr - : button_key_inactive_attr); - waddch (win, label[0]); - wattrset (win, selected ? button_label_active_attr - : button_label_inactive_attr); - waddstr (win, (char *)label + 1); - wattrset (win, selected ? button_active_attr : button_inactive_attr); - waddstr (win, ">"); - wmove (win, y, x + temp + 1); -} - -/* - * Draw a rectangular box with line drawing characters - */ -void -draw_box (WINDOW * win, int y, int x, int height, int width, - chtype box, chtype border) -{ - int i, j; - - wattrset (win, 0); - for (i = 0; i < height; i++) { - wmove (win, y + i, x); - for (j = 0; j < width; j++) - if (!i && !j) - waddch (win, border | ACS_ULCORNER); - else if (i == height - 1 && !j) - waddch (win, border | ACS_LLCORNER); - else if (!i && j == width - 1) - waddch (win, box | ACS_URCORNER); - else if (i == height - 1 && j == width - 1) - waddch (win, box | ACS_LRCORNER); - else if (!i) - waddch (win, border | ACS_HLINE); - else if (i == height - 1) - waddch (win, box | ACS_HLINE); - else if (!j) - waddch (win, border | ACS_VLINE); - else if (j == width - 1) - waddch (win, box | ACS_VLINE); - else - waddch (win, box | ' '); - } -} - -/* - * Draw shadows along the right and bottom edge to give a more 3D look - * to the boxes - */ -void -draw_shadow (WINDOW * win, int y, int x, int height, int width) -{ - int i; - - if (has_colors ()) { /* Whether terminal supports color? */ - wattrset (win, shadow_attr); - wmove (win, y + height, x + 2); - for (i = 0; i < width; i++) - waddch (win, winch (win) & A_CHARTEXT); - for (i = y + 1; i < y + height + 1; i++) { - wmove (win, i, x + width); - waddch (win, winch (win) & A_CHARTEXT); - waddch (win, winch (win) & A_CHARTEXT); - } - wnoutrefresh (win); - } -} - -/* - * Return the position of the first alphabetic character in a string. - */ -int -first_alpha(const char *string, const char *exempt) -{ - int i, in_paren=0, c; - - for (i = 0; i < strlen(string); i++) { - c = tolower(string[i]); - - if (strchr("<[(", c)) ++in_paren; - if (strchr(">])", c) && in_paren > 0) --in_paren; - - if ((! in_paren) && isalpha(c) && - strchr(exempt, c) == 0) - return i; - } - - return 0; -} - -/* - * Get the first selected item in the dialog_list_item list. - */ -struct dialog_list_item * -first_sel_item(int item_no, struct dialog_list_item ** items) -{ - int i; - - for (i = 0; i < item_no; i++) { - if (items[i]->selected) - return items[i]; - } - - return NULL; -} diff --git a/config/yesno.c b/config/yesno.c deleted file mode 100644 index 11fcc25f5..000000000 --- a/config/yesno.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * yesno.c -- implements the yes/no box - * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "dialog.h" - -/* - * Display termination buttons - */ -static void -print_buttons(WINDOW *dialog, int height, int width, int selected) -{ - int x = width / 2 - 10; - int y = height - 2; - - print_button (dialog, " Yes ", y, x, selected == 0); - print_button (dialog, " No ", y, x + 13, selected == 1); - - wmove(dialog, y, x+1 + 13*selected ); - wrefresh (dialog); -} - -/* - * Display a dialog box with two buttons - Yes and No - */ -int -dialog_yesno (const char *title, const char *prompt, int height, int width) -{ - int i, x, y, key = 0, button = 0; - WINDOW *dialog; - - /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; - - draw_shadow (stdscr, y, x, height, width); - - dialog = newwin (height, width, y, x); - keypad (dialog, TRUE); - - draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); - wattrset (dialog, border_attr); - mvwaddch (dialog, height-3, 0, ACS_LTEE); - for (i = 0; i < width - 2; i++) - waddch (dialog, ACS_HLINE); - wattrset (dialog, dialog_attr); - waddch (dialog, ACS_RTEE); - - if (title != NULL && strlen(title) >= width-2 ) { - /* truncate long title -- mec */ - char * title2 = malloc(width-2+1); - memcpy( title2, title, width-2 ); - title2[width-2] = '\0'; - title = title2; - } - - if (title != NULL) { - wattrset (dialog, title_attr); - mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); - waddstr (dialog, (char *)title); - waddch (dialog, ' '); - } - - wattrset (dialog, dialog_attr); - print_autowrap (dialog, prompt, width - 2, 1, 3); - - print_buttons(dialog, height, width, 0); - - while (key != ESC) { - key = wgetch (dialog); - switch (key) { - case 'Y': - case 'y': - delwin (dialog); - return 0; - case 'N': - case 'n': - delwin (dialog); - return 1; - - case TAB: - case KEY_LEFT: - case KEY_RIGHT: - button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 1 : (button > 1 ? 0 : button); - - print_buttons(dialog, height, width, button); - wrefresh (dialog); - break; - case ' ': - case '\n': - delwin (dialog); - return button; - case ESC: - break; - } - } - - delwin (dialog); - return -1; /* ESC pressed */ -} diff --git a/config/zconf.l b/config/zconf.l deleted file mode 100644 index 3a4947a88..000000000 --- a/config/zconf.l +++ /dev/null @@ -1,387 +0,0 @@ -%option backup nostdinit noyywrap never-interactive full ecs -%option 8bit backup nodefault perf-report perf-report -%x COMMAND HELP STRING PARAM -%{ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#define LKC_DIRECT_LINK -#include "lkc.h" - -#define START_STRSIZE 16 - -char *text; -static char *text_ptr; -static int text_size, text_asize; - -struct buffer { - struct buffer *parent; - YY_BUFFER_STATE state; -}; - -struct buffer *current_buf; - -static int last_ts, first_ts; - -static void zconf_endhelp(void); -static struct buffer *zconf_endfile(void); - -void new_string(void) -{ - text = malloc(START_STRSIZE); - text_asize = START_STRSIZE; - text_ptr = text; - text_size = 0; - *text_ptr = 0; -} - -void append_string(const char *str, int size) -{ - int new_size = text_size + size + 1; - if (new_size > text_asize) { - text = realloc(text, new_size); - text_asize = new_size; - text_ptr = text + text_size; - } - memcpy(text_ptr, str, size); - text_ptr += size; - text_size += size; - *text_ptr = 0; -} - -void alloc_string(const char *str, int size) -{ - text = malloc(size + 1); - memcpy(text, str, size); - text[size] = 0; -} -%} - -ws [ \n\t] -n [A-Za-z0-9_] - -%% - int str = 0; - int ts, i; - -[ \t]*#.*\n current_file->lineno++; -[ \t]*#.* - -[ \t]*\n current_file->lineno++; return T_EOL; - -[ \t]+ { - BEGIN(COMMAND); -} - -. { - unput(yytext[0]); - BEGIN(COMMAND); -} - - -{ - "mainmenu" BEGIN(PARAM); return T_MAINMENU; - "menu" BEGIN(PARAM); return T_MENU; - "endmenu" BEGIN(PARAM); return T_ENDMENU; - "source" BEGIN(PARAM); return T_SOURCE; - "choice" BEGIN(PARAM); return T_CHOICE; - "endchoice" BEGIN(PARAM); return T_ENDCHOICE; - "comment" BEGIN(PARAM); return T_COMMENT; - "config" BEGIN(PARAM); return T_CONFIG; - "menuconfig" BEGIN(PARAM); return T_MENUCONFIG; - "help" BEGIN(PARAM); return T_HELP; - "if" BEGIN(PARAM); return T_IF; - "endif" BEGIN(PARAM); return T_ENDIF; - "depends" BEGIN(PARAM); return T_DEPENDS; - "requires" BEGIN(PARAM); return T_REQUIRES; - "optional" BEGIN(PARAM); return T_OPTIONAL; - "default" BEGIN(PARAM); return T_DEFAULT; - "prompt" BEGIN(PARAM); return T_PROMPT; - "tristate" BEGIN(PARAM); return T_TRISTATE; - "def_tristate" BEGIN(PARAM); return T_DEF_TRISTATE; - "bool" BEGIN(PARAM); return T_BOOLEAN; - "boolean" BEGIN(PARAM); return T_BOOLEAN; - "def_bool" BEGIN(PARAM); return T_DEF_BOOLEAN; - "def_boolean" BEGIN(PARAM); return T_DEF_BOOLEAN; - "int" BEGIN(PARAM); return T_INT; - "hex" BEGIN(PARAM); return T_HEX; - "string" BEGIN(PARAM); return T_STRING; - "select" BEGIN(PARAM); return T_SELECT; - "enable" BEGIN(PARAM); return T_SELECT; - "range" BEGIN(PARAM); return T_RANGE; - {n}+ { - alloc_string(yytext, yyleng); - zconflval.string = text; - return T_WORD; - } - . - \n current_file->lineno++; BEGIN(INITIAL); -} - -{ - "&&" return T_AND; - "||" return T_OR; - "(" return T_OPEN_PAREN; - ")" return T_CLOSE_PAREN; - "!" return T_NOT; - "=" return T_EQUAL; - "!=" return T_UNEQUAL; - "if" return T_IF; - "on" return T_ON; - \"|\' { - str = yytext[0]; - new_string(); - BEGIN(STRING); - } - \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; - --- /* ignore */ - ({n}|[-/.])+ { - alloc_string(yytext, yyleng); - zconflval.string = text; - return T_WORD; - } - #.* /* comment */ - \\\n current_file->lineno++; - . - <> { - BEGIN(INITIAL); - } -} - -{ - [^'"\\\n]+/\n { - append_string(yytext, yyleng); - zconflval.string = text; - return T_WORD_QUOTE; - } - [^'"\\\n]+ { - append_string(yytext, yyleng); - } - \\.?/\n { - append_string(yytext + 1, yyleng - 1); - zconflval.string = text; - return T_WORD_QUOTE; - } - \\.? { - append_string(yytext + 1, yyleng - 1); - } - \'|\" { - if (str == yytext[0]) { - BEGIN(PARAM); - zconflval.string = text; - return T_WORD_QUOTE; - } else - append_string(yytext, 1); - } - \n { - printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); - current_file->lineno++; - BEGIN(INITIAL); - return T_EOL; - } - <> { - BEGIN(INITIAL); - } -} - -{ - [ \t]+ { - ts = 0; - for (i = 0; i < yyleng; i++) { - if (yytext[i] == '\t') - ts = (ts & ~7) + 8; - else - ts++; - } - last_ts = ts; - if (first_ts) { - if (ts < first_ts) { - zconf_endhelp(); - return T_HELPTEXT; - } - ts -= first_ts; - while (ts > 8) { - append_string(" ", 8); - ts -= 8; - } - append_string(" ", ts); - } - } - [ \t]*\n/[^ \t\n] { - current_file->lineno++; - zconf_endhelp(); - return T_HELPTEXT; - } - [ \t]*\n { - current_file->lineno++; - append_string("\n", 1); - } - [^ \t\n].* { - append_string(yytext, yyleng); - if (!first_ts) - first_ts = last_ts; - } - <> { - zconf_endhelp(); - return T_HELPTEXT; - } -} - -<> { - if (current_buf) { - zconf_endfile(); - return T_EOF; - } - fclose(yyin); - yyterminate(); -} - -%% -void zconf_starthelp(void) -{ - new_string(); - last_ts = first_ts = 0; - BEGIN(HELP); -} - -static void zconf_endhelp(void) -{ - zconflval.string = text; - BEGIN(INITIAL); -} - - -/* - * Try to open specified file with following names: - * ./name - * $(srctree)/name - * The latter is used when srctree is separate from objtree - * when compiling the kernel. - * Return NULL if file is not found. - */ -FILE *zconf_fopen(const char *name) -{ - char *env, fullname[PATH_MAX+1]; - FILE *f; - - f = fopen(name, "r"); - if (!f && name[0] != '/') { - env = getenv(SRCTREE); - if (env) { - sprintf(fullname, "%s/%s", env, name); - f = fopen(fullname, "r"); - } - } - return f; -} - -void zconf_initscan(const char *name) -{ - yyin = zconf_fopen(name); - if (!yyin) { - printf("can't find file %s\n", name); - exit(1); - } - - current_buf = malloc(sizeof(*current_buf)); - memset(current_buf, 0, sizeof(*current_buf)); - - current_file = file_lookup(name); - current_file->lineno = 1; - current_file->flags = FILE_BUSY; -} - -void zconf_nextfile(const char *name) -{ - size_t i; - int retval; - glob_t files; - char *filename; - struct file *file; - struct buffer *buf; - - retval = glob(name, GLOB_ERR | GLOB_MARK, NULL, &files); - if (retval == GLOB_NOSPACE || retval == GLOB_ABORTED || retval == GLOB_NOMATCH) { - printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(), - retval == GLOB_NOSPACE ? "failed to allocate memory" : - retval == GLOB_ABORTED ? "read error" : "no match", - name); - exit(1); - } - - for (i = files.gl_pathc-1; i != (size_t)-1; --i) { - filename = files.gl_pathv[i]; - - file = file_lookup(filename); - buf = malloc(sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); - current_buf->state = YY_CURRENT_BUFFER; - zconfin = zconf_fopen(filename); - if (!zconfin) { - printf("%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), filename); - exit(1); - } - zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); - buf->parent = current_buf; - current_buf = buf; - - if (file->flags & FILE_BUSY) { - printf("recursive scan (%s)?\n", filename); - exit(1); - } - if (file->flags & FILE_SCANNED) { - printf("file %s already scanned?\n", filename); - exit(1); - } - file->flags |= FILE_BUSY; - file->lineno = 1; - file->parent = current_file; - current_file = file; - } -} - -static struct buffer *zconf_endfile(void) -{ - struct buffer *parent; - - current_file->flags |= FILE_SCANNED; - current_file->flags &= ~FILE_BUSY; - current_file = current_file->parent; - - parent = current_buf->parent; - if (parent) { - fclose(yyin); - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(parent->state); - } - free(current_buf); - current_buf = parent; - - return parent; -} - -int zconf_lineno(void) -{ - if (current_buf) - return current_file->lineno - 1; - else - return 0; -} - -char *zconf_curname(void) -{ - if (current_buf) - return current_file->name; - else - return ""; -} diff --git a/config/zconf.output b/config/zconf.output deleted file mode 100644 index a4d86e975..000000000 --- a/config/zconf.output +++ /dev/null @@ -1,2133 +0,0 @@ -State 52 conflicts: 1 shift/reduce -State 53 conflicts: 1 shift/reduce -State 54 conflicts: 1 shift/reduce -State 55 conflicts: 10 shift/reduce -State 56 conflicts: 12 shift/reduce -State 57 conflicts: 1 shift/reduce -State 58 conflicts: 13 shift/reduce -State 59 conflicts: 1 shift/reduce - - -Grammar - - 0 $accept: input $end - - 1 input: /* empty */ - 2 | input block - - 3 block: common_block - 4 | choice_stmt - 5 | menu_stmt - 6 | T_MAINMENU prompt nl_or_eof - 7 | T_ENDMENU - 8 | T_ENDIF - 9 | T_ENDCHOICE - 10 | error nl_or_eof - - 11 common_block: if_stmt - 12 | comment_stmt - 13 | config_stmt - 14 | menuconfig_stmt - 15 | source_stmt - 16 | nl_or_eof - - 17 config_entry_start: T_CONFIG T_WORD T_EOL - - 18 config_stmt: config_entry_start config_option_list - - 19 menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL - - 20 menuconfig_stmt: menuconfig_entry_start config_option_list - - 21 config_option_list: /* empty */ - 22 | config_option_list config_option - 23 | config_option_list depends - 24 | config_option_list help - 25 | config_option_list T_EOL - - 26 config_option: T_TRISTATE prompt_stmt_opt T_EOL - 27 | T_DEF_TRISTATE expr if_expr T_EOL - 28 | T_BOOLEAN prompt_stmt_opt T_EOL - 29 | T_DEF_BOOLEAN expr if_expr T_EOL - 30 | T_INT prompt_stmt_opt T_EOL - 31 | T_HEX prompt_stmt_opt T_EOL - 32 | T_STRING prompt_stmt_opt T_EOL - 33 | T_PROMPT prompt if_expr T_EOL - 34 | T_DEFAULT expr if_expr T_EOL - 35 | T_SELECT T_WORD if_expr T_EOL - 36 | T_SELECT T_NOT T_WORD if_expr T_EOL - 37 | T_RANGE symbol symbol if_expr T_EOL - - 38 choice: T_CHOICE T_EOL - - 39 choice_entry: choice choice_option_list - - 40 choice_end: end - - 41 choice_stmt: choice_entry choice_block choice_end - 42 | choice_entry choice_block - - 43 choice_option_list: /* empty */ - 44 | choice_option_list choice_option - 45 | choice_option_list depends - 46 | choice_option_list help - 47 | choice_option_list T_EOL - - 48 choice_option: T_PROMPT prompt if_expr T_EOL - 49 | T_TRISTATE prompt_stmt_opt T_EOL - 50 | T_BOOLEAN prompt_stmt_opt T_EOL - 51 | T_OPTIONAL T_EOL - 52 | T_DEFAULT T_WORD if_expr T_EOL - - 53 choice_block: /* empty */ - 54 | choice_block common_block - - 55 if: T_IF expr T_EOL - - 56 if_end: end - - 57 if_stmt: if if_block if_end - 58 | if if_block - - 59 if_block: /* empty */ - 60 | if_block common_block - 61 | if_block menu_stmt - 62 | if_block choice_stmt - - 63 menu: T_MENU prompt T_EOL - - 64 menu_entry: menu depends_list - - 65 menu_end: end - - 66 menu_stmt: menu_entry menu_block menu_end - 67 | menu_entry menu_block - - 68 menu_block: /* empty */ - 69 | menu_block common_block - 70 | menu_block menu_stmt - 71 | menu_block choice_stmt - 72 | menu_block error T_EOL - - 73 source: T_SOURCE prompt T_EOL - - 74 source_stmt: source - - 75 comment: T_COMMENT prompt T_EOL - - 76 comment_stmt: comment depends_list - - 77 help_start: T_HELP T_EOL - - 78 help: help_start T_HELPTEXT - - 79 depends_list: /* empty */ - 80 | depends_list depends - 81 | depends_list T_EOL - - 82 depends: T_DEPENDS T_ON expr T_EOL - 83 | T_DEPENDS expr T_EOL - 84 | T_REQUIRES expr T_EOL - - 85 prompt_stmt_opt: /* empty */ - 86 | prompt if_expr - - 87 prompt: T_WORD - 88 | T_WORD_QUOTE - - 89 end: T_ENDMENU nl_or_eof - 90 | T_ENDCHOICE nl_or_eof - 91 | T_ENDIF nl_or_eof - - 92 nl_or_eof: T_EOL - 93 | T_EOF - - 94 if_expr: /* empty */ - 95 | T_IF expr - - 96 expr: symbol - 97 | symbol T_EQUAL symbol - 98 | symbol T_UNEQUAL symbol - 99 | T_OPEN_PAREN expr T_CLOSE_PAREN - 100 | T_NOT expr - 101 | expr T_OR expr - 102 | expr T_AND expr - - 103 symbol: T_WORD - 104 | T_WORD_QUOTE - - -Terminals, with rules where they appear - -$end (0) 0 -error (256) 10 72 -T_MAINMENU (258) 6 -T_MENU (259) 63 -T_ENDMENU (260) 7 89 -T_SOURCE (261) 73 -T_CHOICE (262) 38 -T_ENDCHOICE (263) 9 90 -T_COMMENT (264) 75 -T_CONFIG (265) 17 -T_MENUCONFIG (266) 19 -T_HELP (267) 77 -T_HELPTEXT (268) 78 -T_IF (269) 55 95 -T_ENDIF (270) 8 91 -T_DEPENDS (271) 82 83 -T_REQUIRES (272) 84 -T_OPTIONAL (273) 51 -T_PROMPT (274) 33 48 -T_DEFAULT (275) 34 52 -T_TRISTATE (276) 26 49 -T_DEF_TRISTATE (277) 27 -T_BOOLEAN (278) 28 50 -T_DEF_BOOLEAN (279) 29 -T_STRING (280) 32 -T_INT (281) 30 -T_HEX (282) 31 -T_WORD (283) 17 19 35 36 52 87 103 -T_WORD_QUOTE (284) 88 104 -T_UNEQUAL (285) 98 -T_EOF (286) 93 -T_EOL (287) 17 19 25 26 27 28 29 30 31 32 33 34 35 36 37 38 47 48 49 - 50 51 52 55 63 72 73 75 77 81 82 83 84 92 -T_CLOSE_PAREN (288) 99 -T_OPEN_PAREN (289) 99 -T_ON (290) 82 -T_SELECT (291) 35 36 -T_RANGE (292) 37 -T_OR (293) 101 -T_AND (294) 102 -T_EQUAL (295) 97 -T_NOT (296) 36 100 - - -Nonterminals, with rules where they appear - -$accept (42) - on left: 0 -input (43) - on left: 1 2, on right: 0 2 -block (44) - on left: 3 4 5 6 7 8 9 10, on right: 2 -common_block (45) - on left: 11 12 13 14 15 16, on right: 3 54 60 69 -config_entry_start (46) - on left: 17, on right: 18 -config_stmt (47) - on left: 18, on right: 13 -menuconfig_entry_start (48) - on left: 19, on right: 20 -menuconfig_stmt (49) - on left: 20, on right: 14 -config_option_list (50) - on left: 21 22 23 24 25, on right: 18 20 22 23 24 25 -config_option (51) - on left: 26 27 28 29 30 31 32 33 34 35 36 37, on right: 22 -choice (52) - on left: 38, on right: 39 -choice_entry (53) - on left: 39, on right: 41 42 -choice_end (54) - on left: 40, on right: 41 -choice_stmt (55) - on left: 41 42, on right: 4 62 71 -choice_option_list (56) - on left: 43 44 45 46 47, on right: 39 44 45 46 47 -choice_option (57) - on left: 48 49 50 51 52, on right: 44 -choice_block (58) - on left: 53 54, on right: 41 42 54 -if (59) - on left: 55, on right: 57 58 -if_end (60) - on left: 56, on right: 57 -if_stmt (61) - on left: 57 58, on right: 11 -if_block (62) - on left: 59 60 61 62, on right: 57 58 60 61 62 -menu (63) - on left: 63, on right: 64 -menu_entry (64) - on left: 64, on right: 66 67 -menu_end (65) - on left: 65, on right: 66 -menu_stmt (66) - on left: 66 67, on right: 5 61 70 -menu_block (67) - on left: 68 69 70 71 72, on right: 66 67 69 70 71 72 -source (68) - on left: 73, on right: 74 -source_stmt (69) - on left: 74, on right: 15 -comment (70) - on left: 75, on right: 76 -comment_stmt (71) - on left: 76, on right: 12 -help_start (72) - on left: 77, on right: 78 -help (73) - on left: 78, on right: 24 46 -depends_list (74) - on left: 79 80 81, on right: 64 76 80 81 -depends (75) - on left: 82 83 84, on right: 23 45 80 -prompt_stmt_opt (76) - on left: 85 86, on right: 26 28 30 31 32 49 50 -prompt (77) - on left: 87 88, on right: 6 33 48 63 73 75 86 -end (78) - on left: 89 90 91, on right: 40 56 65 -nl_or_eof (79) - on left: 92 93, on right: 6 10 16 89 90 91 -if_expr (80) - on left: 94 95, on right: 27 29 33 34 35 36 37 48 52 86 -expr (81) - on left: 96 97 98 99 100 101 102, on right: 27 29 34 55 82 83 84 - 95 99 100 101 102 -symbol (82) - on left: 103 104, on right: 37 96 97 98 - - -state 0 - - 0 $accept: . input $end - - $default reduce using rule 1 (input) - - input go to state 1 - - -state 1 - - 0 $accept: input . $end - 2 input: input . block - - $end shift, and go to state 2 - error shift, and go to state 3 - T_MAINMENU shift, and go to state 4 - T_MENU shift, and go to state 5 - T_ENDMENU shift, and go to state 6 - T_SOURCE shift, and go to state 7 - T_CHOICE shift, and go to state 8 - T_ENDCHOICE shift, and go to state 9 - T_COMMENT shift, and go to state 10 - T_CONFIG shift, and go to state 11 - T_MENUCONFIG shift, and go to state 12 - T_IF shift, and go to state 13 - T_ENDIF shift, and go to state 14 - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - block go to state 17 - common_block go to state 18 - config_entry_start go to state 19 - config_stmt go to state 20 - menuconfig_entry_start go to state 21 - menuconfig_stmt go to state 22 - choice go to state 23 - choice_entry go to state 24 - choice_stmt go to state 25 - if go to state 26 - if_stmt go to state 27 - menu go to state 28 - menu_entry go to state 29 - menu_stmt go to state 30 - source go to state 31 - source_stmt go to state 32 - comment go to state 33 - comment_stmt go to state 34 - nl_or_eof go to state 35 - - -state 2 - - 0 $accept: input $end . - - $default accept - - -state 3 - - 10 block: error . nl_or_eof - - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - nl_or_eof go to state 36 - - -state 4 - - 6 block: T_MAINMENU . prompt nl_or_eof - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 39 - - -state 5 - - 63 menu: T_MENU . prompt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 40 - - -state 6 - - 7 block: T_ENDMENU . - - $default reduce using rule 7 (block) - - -state 7 - - 73 source: T_SOURCE . prompt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 41 - - -state 8 - - 38 choice: T_CHOICE . T_EOL - - T_EOL shift, and go to state 42 - - -state 9 - - 9 block: T_ENDCHOICE . - - $default reduce using rule 9 (block) - - -state 10 - - 75 comment: T_COMMENT . prompt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 43 - - -state 11 - - 17 config_entry_start: T_CONFIG . T_WORD T_EOL - - T_WORD shift, and go to state 44 - - -state 12 - - 19 menuconfig_entry_start: T_MENUCONFIG . T_WORD T_EOL - - T_WORD shift, and go to state 45 - - -state 13 - - 55 if: T_IF . expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 50 - symbol go to state 51 - - -state 14 - - 8 block: T_ENDIF . - - $default reduce using rule 8 (block) - - -state 15 - - 93 nl_or_eof: T_EOF . - - $default reduce using rule 93 (nl_or_eof) - - -state 16 - - 92 nl_or_eof: T_EOL . - - $default reduce using rule 92 (nl_or_eof) - - -state 17 - - 2 input: input block . - - $default reduce using rule 2 (input) - - -state 18 - - 3 block: common_block . - - $default reduce using rule 3 (block) - - -state 19 - - 18 config_stmt: config_entry_start . config_option_list - - $default reduce using rule 21 (config_option_list) - - config_option_list go to state 52 - - -state 20 - - 13 common_block: config_stmt . - - $default reduce using rule 13 (common_block) - - -state 21 - - 20 menuconfig_stmt: menuconfig_entry_start . config_option_list - - $default reduce using rule 21 (config_option_list) - - config_option_list go to state 53 - - -state 22 - - 14 common_block: menuconfig_stmt . - - $default reduce using rule 14 (common_block) - - -state 23 - - 39 choice_entry: choice . choice_option_list - - $default reduce using rule 43 (choice_option_list) - - choice_option_list go to state 54 - - -state 24 - - 41 choice_stmt: choice_entry . choice_block choice_end - 42 | choice_entry . choice_block - - $default reduce using rule 53 (choice_block) - - choice_block go to state 55 - - -state 25 - - 4 block: choice_stmt . - - $default reduce using rule 4 (block) - - -state 26 - - 57 if_stmt: if . if_block if_end - 58 | if . if_block - - $default reduce using rule 59 (if_block) - - if_block go to state 56 - - -state 27 - - 11 common_block: if_stmt . - - $default reduce using rule 11 (common_block) - - -state 28 - - 64 menu_entry: menu . depends_list - - $default reduce using rule 79 (depends_list) - - depends_list go to state 57 - - -state 29 - - 66 menu_stmt: menu_entry . menu_block menu_end - 67 | menu_entry . menu_block - - $default reduce using rule 68 (menu_block) - - menu_block go to state 58 - - -state 30 - - 5 block: menu_stmt . - - $default reduce using rule 5 (block) - - -state 31 - - 74 source_stmt: source . - - $default reduce using rule 74 (source_stmt) - - -state 32 - - 15 common_block: source_stmt . - - $default reduce using rule 15 (common_block) - - -state 33 - - 76 comment_stmt: comment . depends_list - - $default reduce using rule 79 (depends_list) - - depends_list go to state 59 - - -state 34 - - 12 common_block: comment_stmt . - - $default reduce using rule 12 (common_block) - - -state 35 - - 16 common_block: nl_or_eof . - - $default reduce using rule 16 (common_block) - - -state 36 - - 10 block: error nl_or_eof . - - $default reduce using rule 10 (block) - - -state 37 - - 87 prompt: T_WORD . - - $default reduce using rule 87 (prompt) - - -state 38 - - 88 prompt: T_WORD_QUOTE . - - $default reduce using rule 88 (prompt) - - -state 39 - - 6 block: T_MAINMENU prompt . nl_or_eof - - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - nl_or_eof go to state 60 - - -state 40 - - 63 menu: T_MENU prompt . T_EOL - - T_EOL shift, and go to state 61 - - -state 41 - - 73 source: T_SOURCE prompt . T_EOL - - T_EOL shift, and go to state 62 - - -state 42 - - 38 choice: T_CHOICE T_EOL . - - $default reduce using rule 38 (choice) - - -state 43 - - 75 comment: T_COMMENT prompt . T_EOL - - T_EOL shift, and go to state 63 - - -state 44 - - 17 config_entry_start: T_CONFIG T_WORD . T_EOL - - T_EOL shift, and go to state 64 - - -state 45 - - 19 menuconfig_entry_start: T_MENUCONFIG T_WORD . T_EOL - - T_EOL shift, and go to state 65 - - -state 46 - - 103 symbol: T_WORD . - - $default reduce using rule 103 (symbol) - - -state 47 - - 104 symbol: T_WORD_QUOTE . - - $default reduce using rule 104 (symbol) - - -state 48 - - 99 expr: T_OPEN_PAREN . expr T_CLOSE_PAREN - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 66 - symbol go to state 51 - - -state 49 - - 100 expr: T_NOT . expr - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 67 - symbol go to state 51 - - -state 50 - - 55 if: T_IF expr . T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_EOL shift, and go to state 68 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - -state 51 - - 96 expr: symbol . - 97 | symbol . T_EQUAL symbol - 98 | symbol . T_UNEQUAL symbol - - T_UNEQUAL shift, and go to state 71 - T_EQUAL shift, and go to state 72 - - $default reduce using rule 96 (expr) - - -state 52 - - 18 config_stmt: config_entry_start config_option_list . - 22 config_option_list: config_option_list . config_option - 23 | config_option_list . depends - 24 | config_option_list . help - 25 | config_option_list . T_EOL - - T_HELP shift, and go to state 73 - T_DEPENDS shift, and go to state 74 - T_REQUIRES shift, and go to state 75 - T_PROMPT shift, and go to state 76 - T_DEFAULT shift, and go to state 77 - T_TRISTATE shift, and go to state 78 - T_DEF_TRISTATE shift, and go to state 79 - T_BOOLEAN shift, and go to state 80 - T_DEF_BOOLEAN shift, and go to state 81 - T_STRING shift, and go to state 82 - T_INT shift, and go to state 83 - T_HEX shift, and go to state 84 - T_EOL shift, and go to state 85 - T_SELECT shift, and go to state 86 - T_RANGE shift, and go to state 87 - - T_EOL [reduce using rule 18 (config_stmt)] - $default reduce using rule 18 (config_stmt) - - config_option go to state 88 - help_start go to state 89 - help go to state 90 - depends go to state 91 - - -state 53 - - 20 menuconfig_stmt: menuconfig_entry_start config_option_list . - 22 config_option_list: config_option_list . config_option - 23 | config_option_list . depends - 24 | config_option_list . help - 25 | config_option_list . T_EOL - - T_HELP shift, and go to state 73 - T_DEPENDS shift, and go to state 74 - T_REQUIRES shift, and go to state 75 - T_PROMPT shift, and go to state 76 - T_DEFAULT shift, and go to state 77 - T_TRISTATE shift, and go to state 78 - T_DEF_TRISTATE shift, and go to state 79 - T_BOOLEAN shift, and go to state 80 - T_DEF_BOOLEAN shift, and go to state 81 - T_STRING shift, and go to state 82 - T_INT shift, and go to state 83 - T_HEX shift, and go to state 84 - T_EOL shift, and go to state 85 - T_SELECT shift, and go to state 86 - T_RANGE shift, and go to state 87 - - T_EOL [reduce using rule 20 (menuconfig_stmt)] - $default reduce using rule 20 (menuconfig_stmt) - - config_option go to state 88 - help_start go to state 89 - help go to state 90 - depends go to state 91 - - -state 54 - - 39 choice_entry: choice choice_option_list . - 44 choice_option_list: choice_option_list . choice_option - 45 | choice_option_list . depends - 46 | choice_option_list . help - 47 | choice_option_list . T_EOL - - T_HELP shift, and go to state 73 - T_DEPENDS shift, and go to state 74 - T_REQUIRES shift, and go to state 75 - T_OPTIONAL shift, and go to state 92 - T_PROMPT shift, and go to state 93 - T_DEFAULT shift, and go to state 94 - T_TRISTATE shift, and go to state 95 - T_BOOLEAN shift, and go to state 96 - T_EOL shift, and go to state 97 - - T_EOL [reduce using rule 39 (choice_entry)] - $default reduce using rule 39 (choice_entry) - - choice_option go to state 98 - help_start go to state 89 - help go to state 99 - depends go to state 100 - - -state 55 - - 41 choice_stmt: choice_entry choice_block . choice_end - 42 | choice_entry choice_block . - 54 choice_block: choice_block . common_block - - T_ENDMENU shift, and go to state 101 - T_SOURCE shift, and go to state 7 - T_ENDCHOICE shift, and go to state 102 - T_COMMENT shift, and go to state 10 - T_CONFIG shift, and go to state 11 - T_MENUCONFIG shift, and go to state 12 - T_IF shift, and go to state 13 - T_ENDIF shift, and go to state 103 - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - T_ENDMENU [reduce using rule 42 (choice_stmt)] - T_SOURCE [reduce using rule 42 (choice_stmt)] - T_ENDCHOICE [reduce using rule 42 (choice_stmt)] - T_COMMENT [reduce using rule 42 (choice_stmt)] - T_CONFIG [reduce using rule 42 (choice_stmt)] - T_MENUCONFIG [reduce using rule 42 (choice_stmt)] - T_IF [reduce using rule 42 (choice_stmt)] - T_ENDIF [reduce using rule 42 (choice_stmt)] - T_EOF [reduce using rule 42 (choice_stmt)] - T_EOL [reduce using rule 42 (choice_stmt)] - $default reduce using rule 42 (choice_stmt) - - common_block go to state 104 - config_entry_start go to state 19 - config_stmt go to state 20 - menuconfig_entry_start go to state 21 - menuconfig_stmt go to state 22 - choice_end go to state 105 - if go to state 26 - if_stmt go to state 27 - source go to state 31 - source_stmt go to state 32 - comment go to state 33 - comment_stmt go to state 34 - end go to state 106 - nl_or_eof go to state 35 - - -state 56 - - 57 if_stmt: if if_block . if_end - 58 | if if_block . - 60 if_block: if_block . common_block - 61 | if_block . menu_stmt - 62 | if_block . choice_stmt - - T_MENU shift, and go to state 5 - T_ENDMENU shift, and go to state 101 - T_SOURCE shift, and go to state 7 - T_CHOICE shift, and go to state 8 - T_ENDCHOICE shift, and go to state 102 - T_COMMENT shift, and go to state 10 - T_CONFIG shift, and go to state 11 - T_MENUCONFIG shift, and go to state 12 - T_IF shift, and go to state 13 - T_ENDIF shift, and go to state 103 - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - T_MENU [reduce using rule 58 (if_stmt)] - T_ENDMENU [reduce using rule 58 (if_stmt)] - T_SOURCE [reduce using rule 58 (if_stmt)] - T_CHOICE [reduce using rule 58 (if_stmt)] - T_ENDCHOICE [reduce using rule 58 (if_stmt)] - T_COMMENT [reduce using rule 58 (if_stmt)] - T_CONFIG [reduce using rule 58 (if_stmt)] - T_MENUCONFIG [reduce using rule 58 (if_stmt)] - T_IF [reduce using rule 58 (if_stmt)] - T_ENDIF [reduce using rule 58 (if_stmt)] - T_EOF [reduce using rule 58 (if_stmt)] - T_EOL [reduce using rule 58 (if_stmt)] - $default reduce using rule 58 (if_stmt) - - common_block go to state 107 - config_entry_start go to state 19 - config_stmt go to state 20 - menuconfig_entry_start go to state 21 - menuconfig_stmt go to state 22 - choice go to state 23 - choice_entry go to state 24 - choice_stmt go to state 108 - if go to state 26 - if_end go to state 109 - if_stmt go to state 27 - menu go to state 28 - menu_entry go to state 29 - menu_stmt go to state 110 - source go to state 31 - source_stmt go to state 32 - comment go to state 33 - comment_stmt go to state 34 - end go to state 111 - nl_or_eof go to state 35 - - -state 57 - - 64 menu_entry: menu depends_list . - 80 depends_list: depends_list . depends - 81 | depends_list . T_EOL - - T_DEPENDS shift, and go to state 74 - T_REQUIRES shift, and go to state 75 - T_EOL shift, and go to state 112 - - T_EOL [reduce using rule 64 (menu_entry)] - $default reduce using rule 64 (menu_entry) - - depends go to state 113 - - -state 58 - - 66 menu_stmt: menu_entry menu_block . menu_end - 67 | menu_entry menu_block . - 69 menu_block: menu_block . common_block - 70 | menu_block . menu_stmt - 71 | menu_block . choice_stmt - 72 | menu_block . error T_EOL - - error shift, and go to state 114 - T_MENU shift, and go to state 5 - T_ENDMENU shift, and go to state 101 - T_SOURCE shift, and go to state 7 - T_CHOICE shift, and go to state 8 - T_ENDCHOICE shift, and go to state 102 - T_COMMENT shift, and go to state 10 - T_CONFIG shift, and go to state 11 - T_MENUCONFIG shift, and go to state 12 - T_IF shift, and go to state 13 - T_ENDIF shift, and go to state 103 - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - $end reduce using rule 67 (menu_stmt) - error [reduce using rule 67 (menu_stmt)] - T_MAINMENU reduce using rule 67 (menu_stmt) - T_MENU [reduce using rule 67 (menu_stmt)] - T_ENDMENU [reduce using rule 67 (menu_stmt)] - T_SOURCE [reduce using rule 67 (menu_stmt)] - T_CHOICE [reduce using rule 67 (menu_stmt)] - T_ENDCHOICE [reduce using rule 67 (menu_stmt)] - T_COMMENT [reduce using rule 67 (menu_stmt)] - T_CONFIG [reduce using rule 67 (menu_stmt)] - T_MENUCONFIG [reduce using rule 67 (menu_stmt)] - T_IF [reduce using rule 67 (menu_stmt)] - T_ENDIF [reduce using rule 67 (menu_stmt)] - T_EOF [reduce using rule 67 (menu_stmt)] - T_EOL [reduce using rule 67 (menu_stmt)] - - common_block go to state 115 - config_entry_start go to state 19 - config_stmt go to state 20 - menuconfig_entry_start go to state 21 - menuconfig_stmt go to state 22 - choice go to state 23 - choice_entry go to state 24 - choice_stmt go to state 116 - if go to state 26 - if_stmt go to state 27 - menu go to state 28 - menu_entry go to state 29 - menu_end go to state 117 - menu_stmt go to state 118 - source go to state 31 - source_stmt go to state 32 - comment go to state 33 - comment_stmt go to state 34 - end go to state 119 - nl_or_eof go to state 35 - - -state 59 - - 76 comment_stmt: comment depends_list . - 80 depends_list: depends_list . depends - 81 | depends_list . T_EOL - - T_DEPENDS shift, and go to state 74 - T_REQUIRES shift, and go to state 75 - T_EOL shift, and go to state 112 - - T_EOL [reduce using rule 76 (comment_stmt)] - $default reduce using rule 76 (comment_stmt) - - depends go to state 113 - - -state 60 - - 6 block: T_MAINMENU prompt nl_or_eof . - - $default reduce using rule 6 (block) - - -state 61 - - 63 menu: T_MENU prompt T_EOL . - - $default reduce using rule 63 (menu) - - -state 62 - - 73 source: T_SOURCE prompt T_EOL . - - $default reduce using rule 73 (source) - - -state 63 - - 75 comment: T_COMMENT prompt T_EOL . - - $default reduce using rule 75 (comment) - - -state 64 - - 17 config_entry_start: T_CONFIG T_WORD T_EOL . - - $default reduce using rule 17 (config_entry_start) - - -state 65 - - 19 menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL . - - $default reduce using rule 19 (menuconfig_entry_start) - - -state 66 - - 99 expr: T_OPEN_PAREN expr . T_CLOSE_PAREN - 101 | expr . T_OR expr - 102 | expr . T_AND expr - - T_CLOSE_PAREN shift, and go to state 120 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - -state 67 - - 100 expr: T_NOT expr . - 101 | expr . T_OR expr - 102 | expr . T_AND expr - - $default reduce using rule 100 (expr) - - -state 68 - - 55 if: T_IF expr T_EOL . - - $default reduce using rule 55 (if) - - -state 69 - - 101 expr: expr T_OR . expr - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 121 - symbol go to state 51 - - -state 70 - - 102 expr: expr T_AND . expr - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 122 - symbol go to state 51 - - -state 71 - - 98 expr: symbol T_UNEQUAL . symbol - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - - symbol go to state 123 - - -state 72 - - 97 expr: symbol T_EQUAL . symbol - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - - symbol go to state 124 - - -state 73 - - 77 help_start: T_HELP . T_EOL - - T_EOL shift, and go to state 125 - - -state 74 - - 82 depends: T_DEPENDS . T_ON expr T_EOL - 83 | T_DEPENDS . expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_ON shift, and go to state 126 - T_NOT shift, and go to state 49 - - expr go to state 127 - symbol go to state 51 - - -state 75 - - 84 depends: T_REQUIRES . expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 128 - symbol go to state 51 - - -state 76 - - 33 config_option: T_PROMPT . prompt if_expr T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 129 - - -state 77 - - 34 config_option: T_DEFAULT . expr if_expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 130 - symbol go to state 51 - - -state 78 - - 26 config_option: T_TRISTATE . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 131 - prompt go to state 132 - - -state 79 - - 27 config_option: T_DEF_TRISTATE . expr if_expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 133 - symbol go to state 51 - - -state 80 - - 28 config_option: T_BOOLEAN . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 134 - prompt go to state 132 - - -state 81 - - 29 config_option: T_DEF_BOOLEAN . expr if_expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 135 - symbol go to state 51 - - -state 82 - - 32 config_option: T_STRING . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 136 - prompt go to state 132 - - -state 83 - - 30 config_option: T_INT . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 137 - prompt go to state 132 - - -state 84 - - 31 config_option: T_HEX . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 138 - prompt go to state 132 - - -state 85 - - 25 config_option_list: config_option_list T_EOL . - - $default reduce using rule 25 (config_option_list) - - -state 86 - - 35 config_option: T_SELECT . T_WORD if_expr T_EOL - 36 | T_SELECT . T_NOT T_WORD if_expr T_EOL - - T_WORD shift, and go to state 139 - T_NOT shift, and go to state 140 - - -state 87 - - 37 config_option: T_RANGE . symbol symbol if_expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - - symbol go to state 141 - - -state 88 - - 22 config_option_list: config_option_list config_option . - - $default reduce using rule 22 (config_option_list) - - -state 89 - - 78 help: help_start . T_HELPTEXT - - T_HELPTEXT shift, and go to state 142 - - -state 90 - - 24 config_option_list: config_option_list help . - - $default reduce using rule 24 (config_option_list) - - -state 91 - - 23 config_option_list: config_option_list depends . - - $default reduce using rule 23 (config_option_list) - - -state 92 - - 51 choice_option: T_OPTIONAL . T_EOL - - T_EOL shift, and go to state 143 - - -state 93 - - 48 choice_option: T_PROMPT . prompt if_expr T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - prompt go to state 144 - - -state 94 - - 52 choice_option: T_DEFAULT . T_WORD if_expr T_EOL - - T_WORD shift, and go to state 145 - - -state 95 - - 49 choice_option: T_TRISTATE . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 146 - prompt go to state 132 - - -state 96 - - 50 choice_option: T_BOOLEAN . prompt_stmt_opt T_EOL - - T_WORD shift, and go to state 37 - T_WORD_QUOTE shift, and go to state 38 - - $default reduce using rule 85 (prompt_stmt_opt) - - prompt_stmt_opt go to state 147 - prompt go to state 132 - - -state 97 - - 47 choice_option_list: choice_option_list T_EOL . - - $default reduce using rule 47 (choice_option_list) - - -state 98 - - 44 choice_option_list: choice_option_list choice_option . - - $default reduce using rule 44 (choice_option_list) - - -state 99 - - 46 choice_option_list: choice_option_list help . - - $default reduce using rule 46 (choice_option_list) - - -state 100 - - 45 choice_option_list: choice_option_list depends . - - $default reduce using rule 45 (choice_option_list) - - -state 101 - - 89 end: T_ENDMENU . nl_or_eof - - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - nl_or_eof go to state 148 - - -state 102 - - 90 end: T_ENDCHOICE . nl_or_eof - - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - nl_or_eof go to state 149 - - -state 103 - - 91 end: T_ENDIF . nl_or_eof - - T_EOF shift, and go to state 15 - T_EOL shift, and go to state 16 - - nl_or_eof go to state 150 - - -state 104 - - 54 choice_block: choice_block common_block . - - $default reduce using rule 54 (choice_block) - - -state 105 - - 41 choice_stmt: choice_entry choice_block choice_end . - - $default reduce using rule 41 (choice_stmt) - - -state 106 - - 40 choice_end: end . - - $default reduce using rule 40 (choice_end) - - -state 107 - - 60 if_block: if_block common_block . - - $default reduce using rule 60 (if_block) - - -state 108 - - 62 if_block: if_block choice_stmt . - - $default reduce using rule 62 (if_block) - - -state 109 - - 57 if_stmt: if if_block if_end . - - $default reduce using rule 57 (if_stmt) - - -state 110 - - 61 if_block: if_block menu_stmt . - - $default reduce using rule 61 (if_block) - - -state 111 - - 56 if_end: end . - - $default reduce using rule 56 (if_end) - - -state 112 - - 81 depends_list: depends_list T_EOL . - - $default reduce using rule 81 (depends_list) - - -state 113 - - 80 depends_list: depends_list depends . - - $default reduce using rule 80 (depends_list) - - -state 114 - - 72 menu_block: menu_block error . T_EOL - - T_EOL shift, and go to state 151 - - -state 115 - - 69 menu_block: menu_block common_block . - - $default reduce using rule 69 (menu_block) - - -state 116 - - 71 menu_block: menu_block choice_stmt . - - $default reduce using rule 71 (menu_block) - - -state 117 - - 66 menu_stmt: menu_entry menu_block menu_end . - - $default reduce using rule 66 (menu_stmt) - - -state 118 - - 70 menu_block: menu_block menu_stmt . - - $default reduce using rule 70 (menu_block) - - -state 119 - - 65 menu_end: end . - - $default reduce using rule 65 (menu_end) - - -state 120 - - 99 expr: T_OPEN_PAREN expr T_CLOSE_PAREN . - - $default reduce using rule 99 (expr) - - -state 121 - - 101 expr: expr . T_OR expr - 101 | expr T_OR expr . - 102 | expr . T_AND expr - - T_AND shift, and go to state 70 - - $default reduce using rule 101 (expr) - - -state 122 - - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - 102 | expr T_AND expr . - - $default reduce using rule 102 (expr) - - -state 123 - - 98 expr: symbol T_UNEQUAL symbol . - - $default reduce using rule 98 (expr) - - -state 124 - - 97 expr: symbol T_EQUAL symbol . - - $default reduce using rule 97 (expr) - - -state 125 - - 77 help_start: T_HELP T_EOL . - - $default reduce using rule 77 (help_start) - - -state 126 - - 82 depends: T_DEPENDS T_ON . expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 152 - symbol go to state 51 - - -state 127 - - 83 depends: T_DEPENDS expr . T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_EOL shift, and go to state 153 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - -state 128 - - 84 depends: T_REQUIRES expr . T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_EOL shift, and go to state 154 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - -state 129 - - 33 config_option: T_PROMPT prompt . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 156 - - -state 130 - - 34 config_option: T_DEFAULT expr . if_expr T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_IF shift, and go to state 155 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 157 - - -state 131 - - 26 config_option: T_TRISTATE prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 158 - - -state 132 - - 86 prompt_stmt_opt: prompt . if_expr - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 159 - - -state 133 - - 27 config_option: T_DEF_TRISTATE expr . if_expr T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_IF shift, and go to state 155 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 160 - - -state 134 - - 28 config_option: T_BOOLEAN prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 161 - - -state 135 - - 29 config_option: T_DEF_BOOLEAN expr . if_expr T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_IF shift, and go to state 155 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 162 - - -state 136 - - 32 config_option: T_STRING prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 163 - - -state 137 - - 30 config_option: T_INT prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 164 - - -state 138 - - 31 config_option: T_HEX prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 165 - - -state 139 - - 35 config_option: T_SELECT T_WORD . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 166 - - -state 140 - - 36 config_option: T_SELECT T_NOT . T_WORD if_expr T_EOL - - T_WORD shift, and go to state 167 - - -state 141 - - 37 config_option: T_RANGE symbol . symbol if_expr T_EOL - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - - symbol go to state 168 - - -state 142 - - 78 help: help_start T_HELPTEXT . - - $default reduce using rule 78 (help) - - -state 143 - - 51 choice_option: T_OPTIONAL T_EOL . - - $default reduce using rule 51 (choice_option) - - -state 144 - - 48 choice_option: T_PROMPT prompt . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 169 - - -state 145 - - 52 choice_option: T_DEFAULT T_WORD . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 170 - - -state 146 - - 49 choice_option: T_TRISTATE prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 171 - - -state 147 - - 50 choice_option: T_BOOLEAN prompt_stmt_opt . T_EOL - - T_EOL shift, and go to state 172 - - -state 148 - - 89 end: T_ENDMENU nl_or_eof . - - $default reduce using rule 89 (end) - - -state 149 - - 90 end: T_ENDCHOICE nl_or_eof . - - $default reduce using rule 90 (end) - - -state 150 - - 91 end: T_ENDIF nl_or_eof . - - $default reduce using rule 91 (end) - - -state 151 - - 72 menu_block: menu_block error T_EOL . - - $default reduce using rule 72 (menu_block) - - -state 152 - - 82 depends: T_DEPENDS T_ON expr . T_EOL - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_EOL shift, and go to state 173 - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - -state 153 - - 83 depends: T_DEPENDS expr T_EOL . - - $default reduce using rule 83 (depends) - - -state 154 - - 84 depends: T_REQUIRES expr T_EOL . - - $default reduce using rule 84 (depends) - - -state 155 - - 95 if_expr: T_IF . expr - - T_WORD shift, and go to state 46 - T_WORD_QUOTE shift, and go to state 47 - T_OPEN_PAREN shift, and go to state 48 - T_NOT shift, and go to state 49 - - expr go to state 174 - symbol go to state 51 - - -state 156 - - 33 config_option: T_PROMPT prompt if_expr . T_EOL - - T_EOL shift, and go to state 175 - - -state 157 - - 34 config_option: T_DEFAULT expr if_expr . T_EOL - - T_EOL shift, and go to state 176 - - -state 158 - - 26 config_option: T_TRISTATE prompt_stmt_opt T_EOL . - - $default reduce using rule 26 (config_option) - - -state 159 - - 86 prompt_stmt_opt: prompt if_expr . - - $default reduce using rule 86 (prompt_stmt_opt) - - -state 160 - - 27 config_option: T_DEF_TRISTATE expr if_expr . T_EOL - - T_EOL shift, and go to state 177 - - -state 161 - - 28 config_option: T_BOOLEAN prompt_stmt_opt T_EOL . - - $default reduce using rule 28 (config_option) - - -state 162 - - 29 config_option: T_DEF_BOOLEAN expr if_expr . T_EOL - - T_EOL shift, and go to state 178 - - -state 163 - - 32 config_option: T_STRING prompt_stmt_opt T_EOL . - - $default reduce using rule 32 (config_option) - - -state 164 - - 30 config_option: T_INT prompt_stmt_opt T_EOL . - - $default reduce using rule 30 (config_option) - - -state 165 - - 31 config_option: T_HEX prompt_stmt_opt T_EOL . - - $default reduce using rule 31 (config_option) - - -state 166 - - 35 config_option: T_SELECT T_WORD if_expr . T_EOL - - T_EOL shift, and go to state 179 - - -state 167 - - 36 config_option: T_SELECT T_NOT T_WORD . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 180 - - -state 168 - - 37 config_option: T_RANGE symbol symbol . if_expr T_EOL - - T_IF shift, and go to state 155 - - $default reduce using rule 94 (if_expr) - - if_expr go to state 181 - - -state 169 - - 48 choice_option: T_PROMPT prompt if_expr . T_EOL - - T_EOL shift, and go to state 182 - - -state 170 - - 52 choice_option: T_DEFAULT T_WORD if_expr . T_EOL - - T_EOL shift, and go to state 183 - - -state 171 - - 49 choice_option: T_TRISTATE prompt_stmt_opt T_EOL . - - $default reduce using rule 49 (choice_option) - - -state 172 - - 50 choice_option: T_BOOLEAN prompt_stmt_opt T_EOL . - - $default reduce using rule 50 (choice_option) - - -state 173 - - 82 depends: T_DEPENDS T_ON expr T_EOL . - - $default reduce using rule 82 (depends) - - -state 174 - - 95 if_expr: T_IF expr . - 101 expr: expr . T_OR expr - 102 | expr . T_AND expr - - T_OR shift, and go to state 69 - T_AND shift, and go to state 70 - - $default reduce using rule 95 (if_expr) - - -state 175 - - 33 config_option: T_PROMPT prompt if_expr T_EOL . - - $default reduce using rule 33 (config_option) - - -state 176 - - 34 config_option: T_DEFAULT expr if_expr T_EOL . - - $default reduce using rule 34 (config_option) - - -state 177 - - 27 config_option: T_DEF_TRISTATE expr if_expr T_EOL . - - $default reduce using rule 27 (config_option) - - -state 178 - - 29 config_option: T_DEF_BOOLEAN expr if_expr T_EOL . - - $default reduce using rule 29 (config_option) - - -state 179 - - 35 config_option: T_SELECT T_WORD if_expr T_EOL . - - $default reduce using rule 35 (config_option) - - -state 180 - - 36 config_option: T_SELECT T_NOT T_WORD if_expr . T_EOL - - T_EOL shift, and go to state 184 - - -state 181 - - 37 config_option: T_RANGE symbol symbol if_expr . T_EOL - - T_EOL shift, and go to state 185 - - -state 182 - - 48 choice_option: T_PROMPT prompt if_expr T_EOL . - - $default reduce using rule 48 (choice_option) - - -state 183 - - 52 choice_option: T_DEFAULT T_WORD if_expr T_EOL . - - $default reduce using rule 52 (choice_option) - - -state 184 - - 36 config_option: T_SELECT T_NOT T_WORD if_expr T_EOL . - - $default reduce using rule 36 (config_option) - - -state 185 - - 37 config_option: T_RANGE symbol symbol if_expr T_EOL . - - $default reduce using rule 37 (config_option) diff --git a/config/zconf.y b/config/zconf.y deleted file mode 100644 index e1f1c151c..000000000 --- a/config/zconf.y +++ /dev/null @@ -1,693 +0,0 @@ -%{ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) - -#define PRINTD 0x0001 -#define DEBUG_PARSE 0x0002 - -int cdebug = PRINTD; - -extern int zconflex(void); -static void zconfprint(const char *err, ...); -static void zconferror(const char *err); -static bool zconf_endtoken(int token, int starttoken, int endtoken); - -struct symbol *symbol_hash[257]; - -#define YYERROR_VERBOSE -%} -%expect 40 - -%union -{ - int token; - char *string; - struct symbol *symbol; - struct expr *expr; - struct menu *menu; -} - -%token T_MAINMENU -%token T_MENU -%token T_ENDMENU -%token T_SOURCE -%token T_CHOICE -%token T_ENDCHOICE -%token T_COMMENT -%token T_CONFIG -%token T_MENUCONFIG -%token T_HELP -%token T_HELPTEXT -%token T_IF -%token T_ENDIF -%token T_DEPENDS -%token T_REQUIRES -%token T_OPTIONAL -%token T_PROMPT -%token T_DEFAULT -%token T_TRISTATE -%token T_DEF_TRISTATE -%token T_BOOLEAN -%token T_DEF_BOOLEAN -%token T_STRING -%token T_INT -%token T_HEX -%token T_WORD -%token T_WORD_QUOTE -%token T_UNEQUAL -%token T_EOF -%token T_EOL -%token T_CLOSE_PAREN -%token T_OPEN_PAREN -%token T_ON -%token T_SELECT -%token T_RANGE - -%left T_OR -%left T_AND -%left T_EQUAL T_UNEQUAL -%nonassoc T_NOT - -%type prompt -%type source -%type symbol -%type expr -%type if_expr -%type end - -%{ -#define LKC_DIRECT_LINK -#include "lkc.h" -%} -%% -input: /* empty */ - | input block -; - -block: common_block - | choice_stmt - | menu_stmt - | T_MAINMENU prompt nl_or_eof - | T_ENDMENU { zconfprint("unexpected 'endmenu' statement"); } - | T_ENDIF { zconfprint("unexpected 'endif' statement"); } - | T_ENDCHOICE { zconfprint("unexpected 'endchoice' statement"); } - | error nl_or_eof { zconfprint("syntax error"); yyerrok; } -; - -common_block: - if_stmt - | comment_stmt - | config_stmt - | menuconfig_stmt - | source_stmt - | nl_or_eof -; - - -/* config/menuconfig entry */ - -config_entry_start: T_CONFIG T_WORD T_EOL -{ - struct symbol *sym = sym_lookup($2, 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); -}; - -config_stmt: config_entry_start config_option_list -{ - menu_end_entry(); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -}; - -menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL -{ - struct symbol *sym = sym_lookup($2, 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); -}; - -menuconfig_stmt: menuconfig_entry_start config_option_list -{ - if (current_entry->prompt) - current_entry->prompt->type = P_MENU; - else - zconfprint("warning: menuconfig statement without prompt"); - menu_end_entry(); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -}; - -config_option_list: - /* empty */ - | config_option_list config_option - | config_option_list depends - | config_option_list help - | config_option_list T_EOL -; - -config_option: T_TRISTATE prompt_stmt_opt T_EOL -{ - menu_set_type(S_TRISTATE); - printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_DEF_TRISTATE expr if_expr T_EOL -{ - menu_add_expr(P_DEFAULT, $2, $3); - menu_set_type(S_TRISTATE); - printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_BOOLEAN prompt_stmt_opt T_EOL -{ - menu_set_type(S_BOOLEAN); - printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_DEF_BOOLEAN expr if_expr T_EOL -{ - menu_add_expr(P_DEFAULT, $2, $3); - menu_set_type(S_BOOLEAN); - printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_INT prompt_stmt_opt T_EOL -{ - menu_set_type(S_INT); - printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_HEX prompt_stmt_opt T_EOL -{ - menu_set_type(S_HEX); - printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_STRING prompt_stmt_opt T_EOL -{ - menu_set_type(S_STRING); - printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_PROMPT prompt if_expr T_EOL -{ - menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_DEFAULT expr if_expr T_EOL -{ - menu_add_expr(P_DEFAULT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_SELECT T_WORD if_expr T_EOL -{ - menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); - printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_SELECT T_NOT T_WORD if_expr T_EOL -{ - menu_add_symbol(P_SELECTNOT, sym_lookup($3, 0), $4); - printd(DEBUG_PARSE, "%s:%d:selectnot\n", zconf_curname(), zconf_lineno()); -}; - -config_option: T_RANGE symbol symbol if_expr T_EOL -{ - menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); - printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); -}; - -/* choice entry */ - -choice: T_CHOICE T_EOL -{ - struct symbol *sym = sym_lookup(NULL, 0); - sym->flags |= SYMBOL_CHOICE; - menu_add_entry(sym); - menu_add_expr(P_CHOICE, NULL, NULL); - printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); -}; - -choice_entry: choice choice_option_list -{ - menu_end_entry(); - menu_add_menu(); -}; - -choice_end: end -{ - if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); - } -}; - -choice_stmt: - choice_entry choice_block choice_end - | choice_entry choice_block -{ - printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno); - zconfnerrs++; -}; - -choice_option_list: - /* empty */ - | choice_option_list choice_option - | choice_option_list depends - | choice_option_list help - | choice_option_list T_EOL -; - -choice_option: T_PROMPT prompt if_expr T_EOL -{ - menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: T_TRISTATE prompt_stmt_opt T_EOL -{ - menu_set_type(S_TRISTATE); - printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: T_BOOLEAN prompt_stmt_opt T_EOL -{ - menu_set_type(S_BOOLEAN); - printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: T_OPTIONAL T_EOL -{ - current_entry->sym->flags |= SYMBOL_OPTIONAL; - printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); -}; - -choice_option: T_DEFAULT T_WORD if_expr T_EOL -{ - menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); - printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); -}; - -choice_block: - /* empty */ - | choice_block common_block -; - -/* if entry */ - -if: T_IF expr T_EOL -{ - printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); - menu_add_entry(NULL); - menu_add_dep($2); - menu_end_entry(); - menu_add_menu(); -}; - -if_end: end -{ - if (zconf_endtoken($1, T_IF, T_ENDIF)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); - } -}; - -if_stmt: - if if_block if_end - | if if_block -{ - printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno); - zconfnerrs++; -}; - -if_block: - /* empty */ - | if_block common_block - | if_block menu_stmt - | if_block choice_stmt -; - -/* menu entry */ - -menu: T_MENU prompt T_EOL -{ - menu_add_entry(NULL); - menu_add_prop(P_MENU, $2, NULL, NULL); - printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); -}; - -menu_entry: menu depends_list -{ - menu_end_entry(); - menu_add_menu(); -}; - -menu_end: end -{ - if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); - } -}; - -menu_stmt: - menu_entry menu_block menu_end - | menu_entry menu_block -{ - printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno); - zconfnerrs++; -}; - -menu_block: - /* empty */ - | menu_block common_block - | menu_block menu_stmt - | menu_block choice_stmt - | menu_block error T_EOL { zconfprint("invalid menu option"); yyerrok; } -; - -source: T_SOURCE prompt T_EOL -{ - $$ = $2; - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); -}; - -source_stmt: source -{ - zconf_nextfile($1); -}; - -/* comment entry */ - -comment: T_COMMENT prompt T_EOL -{ - menu_add_entry(NULL); - menu_add_prop(P_COMMENT, $2, NULL, NULL); - printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); -}; - -comment_stmt: comment depends_list -{ - menu_end_entry(); -}; - -/* help option */ - -help_start: T_HELP T_EOL -{ - printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); - zconf_starthelp(); -}; - -help: help_start T_HELPTEXT -{ - current_entry->sym->help = $2; -}; - -/* depends option */ - -depends_list: /* empty */ - | depends_list depends - | depends_list T_EOL -; - -depends: T_DEPENDS T_ON expr T_EOL -{ - menu_add_dep($3); - printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); -} - | T_DEPENDS expr T_EOL -{ - menu_add_dep($2); - printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); -} - | T_REQUIRES expr T_EOL -{ - menu_add_dep($2); - printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); -}; - -/* prompt statement */ - -prompt_stmt_opt: - /* empty */ - | prompt if_expr -{ - menu_add_prop(P_PROMPT, $1, NULL, $2); -}; - -prompt: T_WORD - | T_WORD_QUOTE -; - -end: T_ENDMENU nl_or_eof { $$ = T_ENDMENU; } - | T_ENDCHOICE nl_or_eof { $$ = T_ENDCHOICE; } - | T_ENDIF nl_or_eof { $$ = T_ENDIF; } -; - -nl_or_eof: - T_EOL | T_EOF; - -if_expr: /* empty */ { $$ = NULL; } - | T_IF expr { $$ = $2; } -; - -expr: symbol { $$ = expr_alloc_symbol($1); } - | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } - | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } - | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } - | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } - | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } - | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } -; - -symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } - | T_WORD_QUOTE { $$ = sym_lookup($1, 1); free($1); } -; - -%% - -void conf_parse(const char *name) -{ - struct symbol *sym; - int i; - - zconf_initscan(name); - - sym_init(); - menu_init(); - modules_sym = sym_lookup("MODULES", 0); - rootmenu.prompt = menu_add_prop(P_MENU, "OpenADK Configuration", NULL, NULL); - - //zconfdebug = 1; - zconfparse(); - if (zconfnerrs) - exit(1); - menu_finalize(&rootmenu); - for_all_symbols(i, sym) { - if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym)) - printf("\n"); - else - sym->flags |= SYMBOL_CHECK_DONE; - } - - sym_change_count = 1; -} - -const char *zconf_tokenname(int token) -{ - switch (token) { - case T_MENU: return "menu"; - case T_ENDMENU: return "endmenu"; - case T_CHOICE: return "choice"; - case T_ENDCHOICE: return "endchoice"; - case T_IF: return "if"; - case T_ENDIF: return "endif"; - } - return ""; -} - -static bool zconf_endtoken(int token, int starttoken, int endtoken) -{ - if (token != endtoken) { - zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken)); - zconfnerrs++; - return false; - } - if (current_menu->file != current_file) { - zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken)); - zconfprint("location of the '%s'", zconf_tokenname(starttoken)); - zconfnerrs++; - return false; - } - return true; -} - -static void zconfprint(const char *err, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -static void zconferror(const char *err) -{ - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); -} - -void print_quoted_string(FILE *out, const char *str) -{ - const char *p; - int len; - - putc('"', out); - while ((p = strchr(str, '"'))) { - len = p - str; - if (len) - fprintf(out, "%.*s", len, str); - fputs("\\\"", out); - str = p + 1; - } - fputs(str, out); - putc('"', out); -} - -void print_symbol(FILE *out, struct menu *menu) -{ - struct symbol *sym = menu->sym; - struct property *prop; - - if (sym_is_choice(sym)) - fprintf(out, "choice\n"); - else - fprintf(out, "config %s\n", sym->name); - switch (sym->type) { - case S_BOOLEAN: - fputs(" boolean\n", out); - break; - case S_TRISTATE: - fputs(" tristate\n", out); - break; - case S_STRING: - fputs(" string\n", out); - break; - case S_INT: - fputs(" integer\n", out); - break; - case S_HEX: - fputs(" hex\n", out); - break; - default: - fputs(" ???\n", out); - break; - } - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - switch (prop->type) { - case P_PROMPT: - fputs(" prompt ", out); - print_quoted_string(out, prop->text); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_DEFAULT: - fputs( " default ", out); - expr_fprint(prop->expr, out); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_CHOICE: - fputs(" #choice value\n", out); - break; - default: - fprintf(out, " unknown prop %d!\n", prop->type); - break; - } - } - if (sym->help) { - int len = strlen(sym->help); - while (sym->help[--len] == '\n') - sym->help[len] = 0; - fprintf(out, " help\n%s\n", sym->help); - } - fputc('\n', out); -} - -void zconfdump(FILE *out) -{ - struct property *prop; - struct symbol *sym; - struct menu *menu; - - menu = rootmenu.list; - while (menu) { - if ((sym = menu->sym)) - print_symbol(out, menu); - else if ((prop = menu->prompt)) { - switch (prop->type) { - case P_COMMENT: - fputs("\ncomment ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - case P_MENU: - fputs("\nmenu ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - default: - ; - } - if (!expr_is_yes(prop->visible.expr)) { - fputs(" depends ", out); - expr_fprint(prop->visible.expr, out); - fputc('\n', out); - } - fputs("\n", out); - } - - if (menu->list) - menu = menu->list; - else if (menu->next) - menu = menu->next; - else while ((menu = menu->parent)) { - if (menu->prompt && menu->prompt->type == P_MENU) - fputs("\nendmenu\n", out); - if (menu->next) { - menu = menu->next; - break; - } - } - } -} - -#include "lex.zconf.c" -#include "confdata.c" -#include "expr.c" -#include "symbol.c" -#include "menu.c" -- cgit v1.2.3 From 3a85fc1dd1b1b56049f8ab3ee1773da2d37bf72d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 13:31:02 +0200 Subject: take over linux-2.6 mconf at state 2.6.31-rc5 --- config/POTFILES.in | 12 + config/check.sh | 14 + config/conf.c | 617 +++++++++ config/confdata.c | 908 ++++++++++++++ config/expr.c | 1106 ++++++++++++++++ config/expr.h | 228 ++++ config/gconf.c | 1632 ++++++++++++++++++++++++ config/gconf.glade | 648 ++++++++++ config/images.c | 326 +++++ config/kconfig_load.c | 35 + config/kxgettext.c | 233 ++++ config/lex.zconf.c_shipped | 2416 +++++++++++++++++++++++++++++++++++ config/lkc.h | 169 +++ config/lkc_proto.h | 45 + config/lxdialog/.gitignore | 4 + config/lxdialog/BIG.FAT.WARNING | 4 + config/lxdialog/check-lxdialog.sh | 82 ++ config/lxdialog/checklist.c | 326 +++++ config/lxdialog/dialog.h | 230 ++++ config/lxdialog/inputbox.c | 238 ++++ config/lxdialog/menubox.c | 434 +++++++ config/lxdialog/textbox.c | 391 ++++++ config/lxdialog/util.c | 657 ++++++++++ config/lxdialog/yesno.c | 114 ++ config/mconf.c | 938 ++++++++++++++ config/menu.c | 453 +++++++ config/qconf.cc | 1765 ++++++++++++++++++++++++++ config/qconf.h | 334 +++++ config/symbol.c | 973 +++++++++++++++ config/util.c | 133 ++ config/zconf.gperf | 44 + config/zconf.hash.c_shipped | 237 ++++ config/zconf.l | 359 ++++++ config/zconf.tab.c_shipped | 2490 +++++++++++++++++++++++++++++++++++++ config/zconf.y | 706 +++++++++++ 35 files changed, 19301 insertions(+) create mode 100644 config/POTFILES.in create mode 100755 config/check.sh create mode 100644 config/conf.c create mode 100644 config/confdata.c create mode 100644 config/expr.c create mode 100644 config/expr.h create mode 100644 config/gconf.c create mode 100644 config/gconf.glade create mode 100644 config/images.c create mode 100644 config/kconfig_load.c create mode 100644 config/kxgettext.c create mode 100644 config/lex.zconf.c_shipped create mode 100644 config/lkc.h create mode 100644 config/lkc_proto.h create mode 100644 config/lxdialog/.gitignore create mode 100644 config/lxdialog/BIG.FAT.WARNING create mode 100644 config/lxdialog/check-lxdialog.sh create mode 100644 config/lxdialog/checklist.c create mode 100644 config/lxdialog/dialog.h create mode 100644 config/lxdialog/inputbox.c create mode 100644 config/lxdialog/menubox.c create mode 100644 config/lxdialog/textbox.c create mode 100644 config/lxdialog/util.c create mode 100644 config/lxdialog/yesno.c create mode 100644 config/mconf.c create mode 100644 config/menu.c create mode 100644 config/qconf.cc create mode 100644 config/qconf.h create mode 100644 config/symbol.c create mode 100644 config/util.c create mode 100644 config/zconf.gperf create mode 100644 config/zconf.hash.c_shipped create mode 100644 config/zconf.l create mode 100644 config/zconf.tab.c_shipped create mode 100644 config/zconf.y diff --git a/config/POTFILES.in b/config/POTFILES.in new file mode 100644 index 000000000..967457396 --- /dev/null +++ b/config/POTFILES.in @@ -0,0 +1,12 @@ +scripts/kconfig/lxdialog/checklist.c +scripts/kconfig/lxdialog/inputbox.c +scripts/kconfig/lxdialog/menubox.c +scripts/kconfig/lxdialog/textbox.c +scripts/kconfig/lxdialog/util.c +scripts/kconfig/lxdialog/yesno.c +scripts/kconfig/mconf.c +scripts/kconfig/conf.c +scripts/kconfig/confdata.c +scripts/kconfig/gconf.c +scripts/kconfig/gconf.glade.h +scripts/kconfig/qconf.cc diff --git a/config/check.sh b/config/check.sh new file mode 100755 index 000000000..fa59cbf9d --- /dev/null +++ b/config/check.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Needed for systems without gettext +$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +#include +int main() +{ + gettext(""); + return 0; +} +EOF +if [ ! "$?" -eq "0" ]; then + echo -DKBUILD_NO_NLS; +fi + diff --git a/config/conf.c b/config/conf.c new file mode 100644 index 000000000..3baaaecd6 --- /dev/null +++ b/config/conf.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static void conf(struct menu *menu); +static void check_conf(struct menu *menu); + +enum { + ask_all, + ask_new, + ask_silent, + set_default, + set_yes, + set_mod, + set_no, + set_random +} input_mode = ask_all; +char *defconfig_file; + +static int indent = 1; +static int valid_stdin = 1; +static int sync_kconfig; +static int conf_cnt; +static char line[128]; +static struct menu *rootEntry; + +static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n"); + +static const char *get_help(struct menu *menu) +{ + if (menu_has_help(menu)) + return _(menu_get_help(menu)); + else + return nohelp_text; +} + +static void strip(char *str) +{ + char *p = str; + int l; + + while ((isspace(*p))) + p++; + l = strlen(p); + if (p != str) + memmove(str, p, l + 1); + if (!l) + return; + p = str + l - 1; + while ((isspace(*p))) + *p-- = 0; +} + +static void check_stdin(void) +{ + if (!valid_stdin) { + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) + printf(_("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; + + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return 0; + } + + switch (input_mode) { + case ask_new: + case ask_silent: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); + case ask_all: + fflush(stdout); + fgets(line, 128, stdin); + return 1; + default: + break; + } + + switch (type) { + case S_INT: + case S_HEX: + case S_STRING: + printf("%s\n", def); + return 1; + default: + ; + } + printf("%s", line); + return 1; +} + +int conf_string(struct menu *menu) +{ + struct symbol *sym = menu->sym; + const char *def; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("(%s) ", sym->name); + def = sym_get_string_value(sym); + if (sym_get_string_value(sym)) + printf("[%s] ", def); + if (!conf_askvalue(sym, def)) + return 0; + switch (line[0]) { + case '\n': + break; + case '?': + /* print help */ + if (line[1] == '\n') { + printf("\n%s\n", get_help(menu)); + def = NULL; + break; + } + default: + line[strlen(line)-1] = 0; + def = line; + } + if (def && sym_set_string_value(sym, def)) + return 0; + } +} + +static int conf_sym(struct menu *menu) +{ + struct symbol *sym = menu->sym; + int type; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); + type = sym_get_type(sym); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { + case no: + putchar('N'); + break; + case mod: + putchar('M'); + break; + case yes: + putchar('Y'); + break; + } + if (oldval != no && sym_tristate_within_range(sym, no)) + printf("/n"); + if (oldval != mod && sym_tristate_within_range(sym, mod)) + printf("/m"); + if (oldval != yes && sym_tristate_within_range(sym, yes)) + printf("/y"); + if (menu_has_help(menu)) + printf("/?"); + printf("] "); + if (!conf_askvalue(sym, sym_get_string_value(sym))) + return 0; + strip(line); + + switch (line[0]) { + case 'n': + case 'N': + newval = no; + if (!line[1] || !strcmp(&line[1], "o")) + break; + continue; + case 'm': + case 'M': + newval = mod; + if (!line[1]) + break; + continue; + case 'y': + case 'Y': + newval = yes; + if (!line[1] || !strcmp(&line[1], "es")) + break; + continue; + case 0: + newval = oldval; + break; + case '?': + goto help; + default: + continue; + } + if (sym_set_tristate_value(sym, newval)) + return 0; +help: + printf("\n%s\n", get_help(menu)); + } +} + +static int conf_choice(struct menu *menu) +{ + struct symbol *sym, *def_sym; + struct menu *child; + int type; + bool is_new; + + sym = menu->sym; + type = sym_get_type(sym); + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); + sym_calc_value(sym); + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + return 0; + case yes: + break; + } + } else { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + return 0; + case yes: + break; + } + } + + while (1) { + int cnt, def; + + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + def_sym = sym_get_choice_value(sym); + cnt = def = 0; + line[0] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + continue; + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, _(menu_get_prompt(child))); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(_(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (menu_has_help(menu)) + printf("?"); + printf("]: "); + switch (input_mode) { + case ask_new: + case ask_silent: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); + case ask_all: + fflush(stdout); + fgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { + printf("\n%s\n", get_help(menu)); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + default: + break; + } + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; + } + if (!child) + continue; + if (line[strlen(line) - 1] == '?') { + printf("\n%s\n", get_help(child)); + continue; + } + sym_set_choice_value(sym, child->sym); + for (child = child->list; child; child = child->next) { + indent += 2; + conf(child); + indent -= 2; + } + return 1; + } +} + +static void conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (prop) { + const char *prompt; + + switch (prop->type) { + case P_MENU: + if (input_mode == ask_silent && rootEntry != menu) { + check_conf(menu); + return; + } + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) + printf("%*c\n%*c %s\n%*c\n", + indent, '*', + indent, '*', _(prompt), + indent, '*'); + default: + ; + } + } + + if (!sym) + goto conf_childs; + + if (sym_is_choice(sym)) { + conf_choice(menu); + if (sym->curr.tri != mod) + return; + goto conf_childs; + } + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + conf_string(menu); + break; + default: + conf_sym(menu); + break; + } + +conf_childs: + if (sym) + indent += 2; + for (child = menu->list; child; child = child->next) + conf(child); + if (sym) + indent -= 2; +} + +static void check_conf(struct menu *menu) +{ + struct symbol *sym; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { + if (!conf_cnt++) + printf(_("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } + } + + for (child = menu->list; child; child = child->next) + check_conf(child); +} + +int main(int ac, char **av) +{ + int opt; + const char *name; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) { + switch (opt) { + case 'o': + input_mode = ask_silent; + break; + case 's': + input_mode = ask_silent; + sync_kconfig = 1; + break; + case 'd': + input_mode = set_default; + break; + case 'D': + input_mode = set_default; + defconfig_file = optarg; + break; + case 'n': + input_mode = set_no; + break; + case 'm': + input_mode = set_mod; + break; + case 'y': + input_mode = set_yes; + break; + case 'r': + { + struct timeval now; + unsigned int seed; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); + + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + srand(seed); + + input_mode = set_random; + break; + } + case 'h': + printf(_("See README for usage info\n")); + exit(0); + break; + default: + fprintf(stderr, _("See README for usage info\n")); + exit(1); + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); + exit(1); + } + name = av[optind]; + conf_parse(name); + //zconfdump(stdout); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" + "*** You have not yet configured your kernel!\n" + "*** (missing kernel config file \"%s\")\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n"), name); + exit(1); + } + } + + switch (input_mode) { + case set_default: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { + printf(_("***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n"), defconfig_file); + exit(1); + } + break; + case ask_silent: + case ask_all: + case ask_new: + conf_read(NULL); + break; + case set_no: + case set_mod: + case set_yes: + case set_random: + name = getenv("KCONFIG_ALLCONFIG"); + if (name && !stat(name, &tmpstat)) { + conf_read_simple(name, S_DEF_USER); + break; + } + switch (input_mode) { + case set_no: name = "allno.config"; break; + case set_mod: name = "allmod.config"; break; + case set_yes: name = "allyes.config"; break; + case set_random: name = "allrandom.config"; break; + default: break; + } + if (!stat(name, &tmpstat)) + conf_read_simple(name, S_DEF_USER); + else if (!stat("all.config", &tmpstat)) + conf_read_simple("all.config", S_DEF_USER); + break; + default: + break; + } + + if (sync_kconfig) { + if (conf_get_changed()) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** Kernel configuration requires explicit update.\n\n")); + return 1; + } + } + valid_stdin = isatty(0) && isatty(1) && isatty(2); + } + + switch (input_mode) { + case set_no: + conf_set_all_new_symbols(def_no); + break; + case set_yes: + conf_set_all_new_symbols(def_yes); + break; + case set_mod: + conf_set_all_new_symbols(def_mod); + break; + case set_random: + conf_set_all_new_symbols(def_random); + break; + case set_default: + conf_set_all_new_symbols(def_default); + break; + case ask_new: + case ask_all: + rootEntry = &rootmenu; + conf(&rootmenu); + input_mode = ask_silent; + /* fall through */ + case ask_silent: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); + } while (conf_cnt); + break; + } + + if (sync_kconfig) { + /* silentoldconfig is used during the build so we shall update autoconf. + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { + fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n")); + return 1; + } + } else { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); + exit(1); + } + } + return 0; +} diff --git a/config/confdata.c b/config/confdata.c new file mode 100644 index 000000000..a04da3459 --- /dev/null +++ b/config/confdata.c @@ -0,0 +1,908 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = "arch/$ARCH/defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +const char *conf_get_configname(void) +{ + char *name = getenv("KCONFIG_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + break; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + conf_warning("invalid string found"); + return 1; + } + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char line[1024]; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) + return 1; + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + printf(_("#\n" + "# using defaults found in %s\n" + "#\n"), name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (fgets(line, sizeof(line), in)) { + conf_lineno++; + sym = NULL; + switch (line[0]) { + case '#': + if (memcmp(line + 2, "CONFIG_", 7)) + continue; + p = strchr(line + 9, ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 9); + if (!sym) { + sym_add_change_count(1); + break; + } + } else { + sym = sym_lookup(line + 9, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + break; + case 'C': + if (memcmp(line, "CONFIG_", 7)) { + conf_warning("unexpected data"); + continue; + } + p = strchr(line + 7, '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + 7); + if (!sym) { + sym_add_change_count(1); + break; + } + } else { + sym = sym_lookup(line + 7, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + break; + case '\r': + case '\n': + break; + default: + conf_warning("unexpected data"); + continue; + } + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym, *choice_sym; + struct property *prop; + struct expr *e; + int i, flags; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + goto sym_ok; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + goto sym_ok; + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + goto sym_ok; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + goto sym_ok; + conf_unsaved++; + /* maybe print value in verbose mode... */ + sym_ok: + if (!sym_is_choice(sym)) + continue; + /* The choice symbol only has a set value (and thus is not new) + * if all its visible childs have values. + */ + prop = sym_get_choice_prop(sym); + flags = sym->flags; + expr_list_for_each_sym(prop->expr, e, choice_sym) + if (choice_sym->visible != no) + flags &= choice_sym->flags; + sym->flags &= flags | ~SYMBOL_DEF_USER; + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + char dirname[128], tmpname[128], newname[128]; + int type, l; + const char *str; + time_t now; + int use_timestamp = 1; + char *env; + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + time(&now); + env = getenv("KCONFIG_NOTIMESTAMP"); + if (env && *env) + use_timestamp = 0; + + fprintf(out, _("#\n" + "# Automatically generated make config: don't edit\n" + "# Linux kernel version: %s\n" + "%s%s" + "#\n"), + sym_get_string_value(sym), + use_timestamp ? "# " : "", + use_timestamp ? ctime(&now) : ""); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + type = sym->type; + if (type == S_TRISTATE) { + sym_calc_value(modules_sym); + if (modules_sym->curr.tri == no) + type = S_BOOLEAN; + } + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + fprintf(out, "# CONFIG_%s is not set\n", sym->name); + break; + case mod: + fprintf(out, "CONFIG_%s=m\n", sym->name); + break; + case yes: + fprintf(out, "CONFIG_%s=y\n", sym->name); + break; + } + break; + case S_STRING: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=\"", sym->name); + while (1) { + l = strcspn(str, "\"\\"); + if (l) { + fwrite(str, l, 1, out); + str += l; + } + if (!*str) + break; + fprintf(out, "\\%c", *str++); + } + fputs("\"\n", out); + break; + case S_HEX: + str = sym_get_string_value(sym); + if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + break; + } + case S_INT: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + break; + } + } + + next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + printf(_("#\n" + "# configuration written to %s\n" + "#\n"), newname); + + sym_set_change_count(0); + + return 0; +} + +int conf_split_config(void) +{ + const char *name; + char path[128]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("include/config")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir("../..")) + return 1; + + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *str; + const char *name; + FILE *out, *out_h; + time_t now; + int i, l; + + sym_clear_all_valid(); + + file_write_dep("include/config/auto.conf.cmd"); + + if (conf_split_config()) + return 1; + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + return 1; + } + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + time(&now); + fprintf(out, "#\n" + "# Automatically generated make config: don't edit\n" + "# Linux kernel version: %s\n" + "# %s" + "#\n", + sym_get_string_value(sym), ctime(&now)); + fprintf(out_h, "/*\n" + " * Automatically generated C config: don't edit\n" + " * Linux kernel version: %s\n" + " * %s" + " */\n" + "#define AUTOCONF_INCLUDED\n", + sym_get_string_value(sym), ctime(&now)); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + break; + case mod: + fprintf(out, "CONFIG_%s=m\n", sym->name); + fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); + break; + case yes: + fprintf(out, "CONFIG_%s=y\n", sym->name); + fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); + break; + } + break; + case S_STRING: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=\"", sym->name); + fprintf(out_h, "#define CONFIG_%s \"", sym->name); + while (1) { + l = strcspn(str, "\"\\"); + if (l) { + fwrite(str, l, 1, out); + fwrite(str, l, 1, out_h); + str += l; + } + if (!*str) + break; + fprintf(out, "\\%c", *str); + fprintf(out_h, "\\%c", *str); + str++; + } + fputs("\"\n", out); + fputs("\"\n", out_h); + break; + case S_HEX: + str = sym_get_string_value(sym); + if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); + break; + } + case S_INT: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); + break; + default: + break; + } + } + fclose(out); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/linux/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + if (rename(".tmpconfig", name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + + +void conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + struct property *prop; + struct expr *e; + int i, cnt, def; + + for_all_symbols(i, sym) { + if (sym_has_value(sym)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = (tristate)(rand() % 3); + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + if (mode != def_random) + return; + /* + * We have different type of choice blocks. + * If curr.tri equal to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equal yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + + if (csym->curr.tri != yes) + continue; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + } +} diff --git a/config/expr.c b/config/expr.c new file mode 100644 index 000000000..579ece4fa --- /dev/null +++ b/config/expr.c @@ -0,0 +1,1106 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define DEBUG_EXPR 0 + +struct expr *expr_alloc_symbol(struct symbol *sym) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = E_SYMBOL; + e->left.sym = sym; + return e; +} + +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.expr = ce; + return e; +} + +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.expr = e1; + e->right.expr = e2; + return e; +} + +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) +{ + struct expr *e = malloc(sizeof(*e)); + memset(e, 0, sizeof(*e)); + e->type = type; + e->left.sym = s1; + e->right.sym = s2; + return e; +} + +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; +} + +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; +} + +struct expr *expr_copy(struct expr *org) +{ + struct expr *e; + + if (!org) + return NULL; + + e = malloc(sizeof(*org)); + memcpy(e, org, sizeof(*org)); + switch (org->type) { + case E_SYMBOL: + e->left = org->left; + break; + case E_NOT: + e->left.expr = expr_copy(org->left.expr); + break; + case E_EQUAL: + case E_UNEQUAL: + e->left.sym = org->left.sym; + e->right.sym = org->right.sym; + break; + case E_AND: + case E_OR: + case E_LIST: + e->left.expr = expr_copy(org->left.expr); + e->right.expr = expr_copy(org->right.expr); + break; + default: + printf("can't copy type %d\n", e->type); + free(e); + e = NULL; + break; + } + + return e; +} + +void expr_free(struct expr *e) +{ + if (!e) + return; + + switch (e->type) { + case E_SYMBOL: + break; + case E_NOT: + expr_free(e->left.expr); + return; + case E_EQUAL: + case E_UNEQUAL: + break; + case E_OR: + case E_AND: + expr_free(e->left.expr); + expr_free(e->right.expr); + break; + default: + printf("how to free type %d?\n", e->type); + break; + } + free(e); +} + +static int trans_count; + +#define e1 (*ep1) +#define e2 (*ep2) + +static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ + if (e1->type == type) { + __expr_eliminate_eq(type, &e1->left.expr, &e2); + __expr_eliminate_eq(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + __expr_eliminate_eq(type, &e1, &e2->left.expr); + __expr_eliminate_eq(type, &e1, &e2->right.expr); + return; + } + if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym && + (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) + return; + if (!expr_eq(e1, e2)) + return; + trans_count++; + expr_free(e1); expr_free(e2); + switch (type) { + case E_OR: + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + break; + case E_AND: + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + break; + default: + ; + } +} + +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) +{ + if (!e1 || !e2) + return; + switch (e1->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e1->type, ep1, ep2); + default: + ; + } + if (e1->type != e2->type) switch (e2->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e2->type, ep1, ep2); + default: + ; + } + e1 = expr_eliminate_yn(e1); + e2 = expr_eliminate_yn(e2); +} + +#undef e1 +#undef e2 + +int expr_eq(struct expr *e1, struct expr *e2) +{ + int res, old_count; + + if (e1->type != e2->type) + return 0; + switch (e1->type) { + case E_EQUAL: + case E_UNEQUAL: + return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; + case E_SYMBOL: + return e1->left.sym == e2->left.sym; + case E_NOT: + return expr_eq(e1->left.expr, e2->left.expr); + case E_AND: + case E_OR: + e1 = expr_copy(e1); + e2 = expr_copy(e2); + old_count = trans_count; + expr_eliminate_eq(&e1, &e2); + res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym); + expr_free(e1); + expr_free(e2); + trans_count = old_count; + return res; + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + + if (DEBUG_EXPR) { + expr_fprint(e1, stdout); + printf(" = "); + expr_fprint(e2, stdout); + printf(" ?\n"); + } + + return 0; +} + +struct expr *expr_eliminate_yn(struct expr *e) +{ + struct expr *tmp; + + if (e) switch (e->type) { + case E_AND: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } + } + break; + case E_OR: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + break; + default: + ; + } + return e; +} + +/* + * bool FOO!=n => FOO + */ +struct expr *expr_trans_bool(struct expr *e) +{ + if (!e) + return NULL; + switch (e->type) { + case E_AND: + case E_OR: + case E_NOT: + e->left.expr = expr_trans_bool(e->left.expr); + e->right.expr = expr_trans_bool(e->right.expr); + break; + case E_UNEQUAL: + // FOO!=n -> FOO + if (e->left.sym->type == S_TRISTATE) { + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + } + } + break; + default: + ; + } + return e; +} + +/* + * e1 || e2 -> ? + */ +struct expr *expr_join_or(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='m') -> (a!='n') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='n') -> (a!='m') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { + // (a='m') || (a='n') -> (a!='y') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); + } + } + if (sym1->type == S_BOOLEAN && sym1 == sym2) { + if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || + (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) + return expr_alloc_symbol(&symbol_yes); + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") || ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +struct expr *expr_join_and(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) + // (a) && (a='y') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) + // (a) && (a!='n') -> (a) + return expr_alloc_symbol(sym1); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) + // (a) && (a!='m') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e1->right.sym; + if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e2->right.sym; + if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='m') -> (a='n') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) + // (a!='m') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || + (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) + return NULL; + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") && ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp; + + if (e1->type == type) { + expr_eliminate_dups1(type, &e1->left.expr, &e2); + expr_eliminate_dups1(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups1(type, &e1, &e2->left.expr); + expr_eliminate_dups1(type, &e1, &e2->right.expr); + return; + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e1->type, &e1, &e1); + default: + ; + } + + switch (type) { + case E_OR: + tmp = expr_join_or(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_no); + e2 = tmp; + trans_count++; + } + break; + case E_AND: + tmp = expr_join_and(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_yes); + e2 = tmp; + trans_count++; + } + break; + default: + ; + } +#undef e1 +#undef e2 +} + +static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp, *tmp1, *tmp2; + + if (e1->type == type) { + expr_eliminate_dups2(type, &e1->left.expr, &e2); + expr_eliminate_dups2(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups2(type, &e1, &e2->left.expr); + expr_eliminate_dups2(type, &e1, &e2->right.expr); + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO || BAR) && (!FOO && !BAR) -> n + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_and(&tmp1, &tmp2); + if (expr_is_yes(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_no); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + case E_AND: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO && BAR) || (!FOO || !BAR) -> y + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_or(&tmp1, &tmp2); + if (expr_is_no(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_yes); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + default: + ; + } +#undef e1 +#undef e2 +} + +struct expr *expr_eliminate_dups(struct expr *e) +{ + int oldcount; + if (!e) + return e; + + oldcount = trans_count; + while (1) { + trans_count = 0; + switch (e->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e->type, &e, &e); + expr_eliminate_dups2(e->type, &e, &e); + default: + ; + } + if (!trans_count) + break; + e = expr_eliminate_yn(e); + } + trans_count = oldcount; + return e; +} + +struct expr *expr_transform(struct expr *e) +{ + struct expr *tmp; + + if (!e) + return NULL; + switch (e->type) { + case E_EQUAL: + case E_UNEQUAL: + case E_SYMBOL: + case E_LIST: + break; + default: + e->left.expr = expr_transform(e->left.expr); + e->right.expr = expr_transform(e->right.expr); + } + + switch (e->type) { + case E_EQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + break; + case E_UNEQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + break; + case E_NOT: + switch (e->left.expr->type) { + case E_NOT: + // !!a -> a + tmp = e->left.expr->left.expr; + free(e->left.expr); + free(e); + e = tmp; + e = expr_transform(e); + break; + case E_EQUAL: + case E_UNEQUAL: + // !a='x' -> a!='x' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; + break; + case E_OR: + // !(a || b) -> !a && !b + tmp = e->left.expr; + e->type = E_AND; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_AND: + // !(a && b) -> !a || !b + tmp = e->left.expr; + e->type = E_OR; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_SYMBOL: + if (e->left.expr->left.sym == &symbol_yes) { + // !'y' -> 'n' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + break; + } + if (e->left.expr->left.sym == &symbol_mod) { + // !'m' -> 'm' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_mod; + break; + } + if (e->left.expr->left.sym == &symbol_no) { + // !'n' -> 'y' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + break; + } + break; + default: + ; + } + break; + default: + ; + } + return e; +} + +int expr_contains_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return 0; + + switch (dep->type) { + case E_AND: + case E_OR: + return expr_contains_symbol(dep->left.expr, sym) || + expr_contains_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + case E_UNEQUAL: + return dep->left.sym == sym || + dep->right.sym == sym; + case E_NOT: + return expr_contains_symbol(dep->left.expr, sym); + default: + ; + } + return 0; +} + +bool expr_depends_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return false; + + switch (dep->type) { + case E_AND: + return expr_depends_symbol(dep->left.expr, sym) || + expr_depends_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) + return true; + } + break; + case E_UNEQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_no) + return true; + } + break; + default: + ; + } + return false; +} + +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_AND, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_OR, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + if (e1->type == type) { + expr_extract_eq(type, ep, &e1->left.expr, &e2); + expr_extract_eq(type, ep, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_extract_eq(type, ep, ep1, &e2->left.expr); + expr_extract_eq(type, ep, ep1, &e2->right.expr); + return; + } + if (expr_eq(e1, e2)) { + *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; + expr_free(e2); + if (type == E_AND) { + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + } else if (type == E_OR) { + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + } + } +#undef e1 +#undef e2 +} + +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) +{ + struct expr *e1, *e2; + + if (!e) { + e = expr_alloc_symbol(sym); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + } + switch (e->type) { + case E_AND: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_AND, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_OR, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_OR: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_OR, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_AND, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_NOT: + return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); + case E_UNEQUAL: + case E_EQUAL: + if (type == E_EQUAL) { + if (sym == &symbol_yes) + return expr_copy(e); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_no); + if (sym == &symbol_no) + return expr_alloc_one(E_NOT, expr_copy(e)); + } else { + if (sym == &symbol_yes) + return expr_alloc_one(E_NOT, expr_copy(e)); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_yes); + if (sym == &symbol_no) + return expr_copy(e); + } + break; + case E_SYMBOL: + return expr_alloc_comp(type, e->left.sym, sym); + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + return NULL; +} + +tristate expr_calc_value(struct expr *e) +{ + tristate val1, val2; + const char *str1, *str2; + + if (!e) + return yes; + + switch (e->type) { + case E_SYMBOL: + sym_calc_value(e->left.sym); + return e->left.sym->curr.tri; + case E_AND: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_AND(val1, val2); + case E_OR: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_OR(val1, val2); + case E_NOT: + val1 = expr_calc_value(e->left.expr); + return EXPR_NOT(val1); + case E_EQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? yes : no; + case E_UNEQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? no : yes; + default: + printf("expr_calc_value: %d?\n", e->type); + return no; + } +} + +int expr_compare_type(enum expr_type t1, enum expr_type t2) +{ +#if 0 + return 1; +#else + if (t1 == t2) + return 0; + switch (t1) { + case E_EQUAL: + case E_UNEQUAL: + if (t2 == E_NOT) + return 1; + case E_NOT: + if (t2 == E_AND) + return 1; + case E_AND: + if (t2 == E_OR) + return 1; + case E_OR: + if (t2 == E_LIST) + return 1; + case E_LIST: + if (t2 == 0) + return 1; + default: + return -1; + } + printf("[%dgt%d?]", t1, t2); + return 0; +#endif +} + +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) +{ + if (!e) { + fn(data, NULL, "y"); + return; + } + + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, "("); + switch (e->type) { + case E_SYMBOL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + break; + case E_NOT: + fn(data, NULL, "!"); + expr_print(e->left.expr, fn, data, E_NOT); + break; + case E_EQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_UNEQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "!="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_OR: + expr_print(e->left.expr, fn, data, E_OR); + fn(data, NULL, " || "); + expr_print(e->right.expr, fn, data, E_OR); + break; + case E_AND: + expr_print(e->left.expr, fn, data, E_AND); + fn(data, NULL, " && "); + expr_print(e->right.expr, fn, data, E_AND); + break; + case E_LIST: + fn(data, e->right.sym, e->right.sym->name); + if (e->left.expr) { + fn(data, NULL, " ^ "); + expr_print(e->left.expr, fn, data, E_LIST); + } + break; + case E_RANGE: + fn(data, NULL, "["); + fn(data, e->left.sym, e->left.sym->name); + fn(data, NULL, " "); + fn(data, e->right.sym, e->right.sym->name); + fn(data, NULL, "]"); + break; + default: + { + char buf[32]; + sprintf(buf, "", e->type); + fn(data, NULL, buf); + break; + } + } + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, ")"); +} + +static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) +{ + fwrite(str, strlen(str), 1, data); +} + +void expr_fprint(struct expr *e, FILE *out) +{ + expr_print(e, expr_print_file_helper, out, E_NONE); +} + +static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) +{ + str_append((struct gstr*)data, str); +} + +void expr_gstr_print(struct expr *e, struct gstr *gs) +{ + expr_print(e, expr_print_gstr_helper, gs, E_NONE); +} diff --git a/config/expr.h b/config/expr.h new file mode 100644 index 000000000..6408fefae --- /dev/null +++ b/config/expr.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifndef __cplusplus +#include +#endif + +struct file { + struct file *next; + struct file *parent; + char *name; + int lineno; + int flags; +}; + +#define FILE_BUSY 0x0001 +#define FILE_SCANNED 0x0002 + +typedef enum tristate { + no, mod, yes +} tristate; + +enum expr_type { + E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE +}; + +union expr_data { + struct expr *expr; + struct symbol *sym; +}; + +struct expr { + enum expr_type type; + union expr_data left, right; +}; + +#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) +#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) +#define EXPR_NOT(dep) (2-(dep)) + +#define expr_list_for_each_sym(l, e, s) \ + for (e = (l); e && (s = e->right.sym); e = e->left.expr) + +struct expr_value { + struct expr *expr; + tristate tri; +}; + +struct symbol_value { + void *val; + tristate tri; +}; + +enum symbol_type { + S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER +}; + +/* enum values are used as index to symbol.def[] */ +enum { + S_DEF_USER, /* main user value */ + S_DEF_AUTO, /* values read from auto.conf */ + S_DEF_DEF3, /* Reserved for UI usage */ + S_DEF_DEF4, /* Reserved for UI usage */ + S_DEF_COUNT +}; + +struct symbol { + struct symbol *next; + char *name; + enum symbol_type type; + struct symbol_value curr; + struct symbol_value def[S_DEF_COUNT]; + tristate visible; + int flags; + struct property *prop; + struct expr_value rev_dep; +}; + +#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + +#define SYMBOL_CONST 0x0001 /* symbol is const */ +#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ +#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ +#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ +#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ +#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ +#define SYMBOL_WRITE 0x0200 /* ? */ +#define SYMBOL_CHANGED 0x0400 /* ? */ +#define SYMBOL_AUTO 0x1000 /* value from environment variable */ +#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ +#define SYMBOL_WARNED 0x8000 /* warning has been issued */ + +/* Set when symbol.def[] is used */ +#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ +#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ +#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ +#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ +#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ + +#define SYMBOL_MAXLENGTH 256 +#define SYMBOL_HASHSIZE 257 +#define SYMBOL_HASHMASK 0xff + +/* A property represent the config options that can be associated + * with a config "symbol". + * Sample: + * config FOO + * default y + * prompt "foo prompt" + * select BAR + * config BAZ + * int "BAZ Value" + * range 1..255 + */ +enum prop_type { + P_UNKNOWN, + P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ + P_COMMENT, /* text associated with a comment */ + P_MENU, /* prompt associated with a menuconfig option */ + P_DEFAULT, /* default y */ + P_CHOICE, /* choice value */ + P_SELECT, /* select BAR */ + P_RANGE, /* range 7..100 (for a symbol) */ + P_ENV, /* value from environment variable */ +}; + +struct property { + struct property *next; /* next property - null if last */ + struct symbol *sym; /* the symbol for which the property is associated */ + enum prop_type type; /* type of property */ + const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ + struct expr_value visible; + struct expr *expr; /* the optional conditional part of the property */ + struct menu *menu; /* the menu the property are associated with + * valid for: P_SELECT, P_RANGE, P_CHOICE, + * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ + struct file *file; /* what file was this property defined */ + int lineno; /* what lineno was this property defined */ +}; + +#define for_all_properties(sym, st, tok) \ + for (st = sym->prop; st; st = st->next) \ + if (st->type == (tok)) +#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) +#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) +#define for_all_prompts(sym, st) \ + for (st = sym->prop; st; st = st->next) \ + if (st->text) + +struct menu { + struct menu *next; + struct menu *parent; + struct menu *list; + struct symbol *sym; + struct property *prompt; + struct expr *dep; + unsigned int flags; + char *help; + struct file *file; + int lineno; + void *data; +}; + +#define MENU_CHANGED 0x0001 +#define MENU_ROOT 0x0002 + +#ifndef SWIG + +extern struct file *file_list; +extern struct file *current_file; +struct file *lookup_file(const char *name); + +extern struct symbol symbol_yes, symbol_no, symbol_mod; +extern struct symbol *modules_sym; +extern struct symbol *sym_defconfig_list; +extern int cdebug; +struct expr *expr_alloc_symbol(struct symbol *sym); +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); +struct expr *expr_copy(struct expr *org); +void expr_free(struct expr *e); +int expr_eq(struct expr *e1, struct expr *e2); +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +tristate expr_calc_value(struct expr *e); +struct expr *expr_eliminate_yn(struct expr *e); +struct expr *expr_trans_bool(struct expr *e); +struct expr *expr_eliminate_dups(struct expr *e); +struct expr *expr_transform(struct expr *e); +int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_depends_symbol(struct expr *dep, struct symbol *sym); +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); + +void expr_fprint(struct expr *e, FILE *out); +struct gstr; /* forward */ +void expr_gstr_print(struct expr *e, struct gstr *gs); + +static inline int expr_is_yes(struct expr *e) +{ + return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); +} + +static inline int expr_is_no(struct expr *e) +{ + return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EXPR_H */ diff --git a/config/gconf.c b/config/gconf.c new file mode 100644 index 000000000..199b22bb4 --- /dev/null +++ b/config/gconf.c @@ -0,0 +1,1632 @@ +/* Hey EMACS -*- linux-c -*- */ +/* + * + * Copyright (C) 2002-2003 Romain Lievin + * Released under the terms of the GNU GPL v2.0. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lkc.h" +#include "images.c" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define DEBUG + +enum { + SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW +}; + +static gint view_mode = FULL_VIEW; +static gboolean show_name = TRUE; +static gboolean show_range = TRUE; +static gboolean show_value = TRUE; +static gboolean show_all = FALSE; +static gboolean show_debug = FALSE; +static gboolean resizeable = FALSE; + +GtkWidget *main_wnd = NULL; +GtkWidget *tree1_w = NULL; // left frame +GtkWidget *tree2_w = NULL; // right frame +GtkWidget *text_w = NULL; +GtkWidget *hpaned = NULL; +GtkWidget *vpaned = NULL; +GtkWidget *back_btn = NULL; +GtkWidget *save_btn = NULL; +GtkWidget *save_menu_item = NULL; + +GtkTextTag *tag1, *tag2; +GdkColor color; + +GtkTreeStore *tree1, *tree2, *tree; +GtkTreeModel *model1, *model2; +static GtkTreeIter *parents[256]; +static gint indent; + +static struct menu *current; // current node for SINGLE view +static struct menu *browsed; // browsed node for SPLIT view + +enum { + COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, + COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, + COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, + COL_NUMBER +}; + +static void display_list(void); +static void display_tree(struct menu *menu); +static void display_tree_part(void); +static void update_tree(struct menu *src, GtkTreeIter * dst); +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); +static gchar **fill_row(struct menu *menu); +static void conf_changed(void); + +/* Helping/Debugging Functions */ + + +const char *dbg_print_stype(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val == S_UNKNOWN) + strcpy(buf, "unknown"); + if (val == S_BOOLEAN) + strcpy(buf, "boolean"); + if (val == S_TRISTATE) + strcpy(buf, "tristate"); + if (val == S_INT) + strcpy(buf, "int"); + if (val == S_HEX) + strcpy(buf, "hex"); + if (val == S_STRING) + strcpy(buf, "string"); + if (val == S_OTHER) + strcpy(buf, "other"); + +#ifdef DEBUG + printf("%s", buf); +#endif + + return buf; +} + +const char *dbg_print_flags(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val & SYMBOL_CONST) + strcat(buf, "const/"); + if (val & SYMBOL_CHECK) + strcat(buf, "check/"); + if (val & SYMBOL_CHOICE) + strcat(buf, "choice/"); + if (val & SYMBOL_CHOICEVAL) + strcat(buf, "choiceval/"); + if (val & SYMBOL_VALID) + strcat(buf, "valid/"); + if (val & SYMBOL_OPTIONAL) + strcat(buf, "optional/"); + if (val & SYMBOL_WRITE) + strcat(buf, "write/"); + if (val & SYMBOL_CHANGED) + strcat(buf, "changed/"); + if (val & SYMBOL_AUTO) + strcat(buf, "auto/"); + + buf[strlen(buf) - 1] = '\0'; +#ifdef DEBUG + printf("%s", buf); +#endif + + return buf; +} + +const char *dbg_print_ptype(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val == P_UNKNOWN) + strcpy(buf, "unknown"); + if (val == P_PROMPT) + strcpy(buf, "prompt"); + if (val == P_COMMENT) + strcpy(buf, "comment"); + if (val == P_MENU) + strcpy(buf, "menu"); + if (val == P_DEFAULT) + strcpy(buf, "default"); + if (val == P_CHOICE) + strcpy(buf, "choice"); + +#ifdef DEBUG + printf("%s", buf); +#endif + + return buf; +} + + +void replace_button_icon(GladeXML * xml, GdkDrawable * window, + GtkStyle * style, gchar * btn_name, gchar ** xpm) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkToolButton *button; + GtkWidget *image; + + pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpm); + + button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); + image = gtk_image_new_from_pixmap(pixmap, mask); + gtk_widget_show(image); + gtk_tool_button_set_icon_widget(button, image); +} + +/* Main Window Initialization */ +void init_main_window(const gchar * glade_file) +{ + GladeXML *xml; + GtkWidget *widget; + GtkTextBuffer *txtbuf; + char title[256]; + GtkStyle *style; + + xml = glade_xml_new(glade_file, "window1", NULL); + if (!xml) + g_error(_("GUI loading failed !\n")); + glade_xml_signal_autoconnect(xml); + + main_wnd = glade_xml_get_widget(xml, "window1"); + hpaned = glade_xml_get_widget(xml, "hpaned1"); + vpaned = glade_xml_get_widget(xml, "vpaned1"); + tree1_w = glade_xml_get_widget(xml, "treeview1"); + tree2_w = glade_xml_get_widget(xml, "treeview2"); + text_w = glade_xml_get_widget(xml, "textview3"); + + back_btn = glade_xml_get_widget(xml, "button1"); + gtk_widget_set_sensitive(back_btn, FALSE); + + widget = glade_xml_get_widget(xml, "show_name1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_name); + + widget = glade_xml_get_widget(xml, "show_range1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_range); + + widget = glade_xml_get_widget(xml, "show_data1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_value); + + save_btn = glade_xml_get_widget(xml, "button3"); + save_menu_item = glade_xml_get_widget(xml, "save1"); + conf_set_changed_callback(conf_changed); + + style = gtk_widget_get_style(main_wnd); + widget = glade_xml_get_widget(xml, "toolbar1"); + +#if 0 /* Use stock Gtk icons instead */ + replace_button_icon(xml, main_wnd->window, style, + "button1", (gchar **) xpm_back); + replace_button_icon(xml, main_wnd->window, style, + "button2", (gchar **) xpm_load); + replace_button_icon(xml, main_wnd->window, style, + "button3", (gchar **) xpm_save); +#endif + replace_button_icon(xml, main_wnd->window, style, + "button4", (gchar **) xpm_single_view); + replace_button_icon(xml, main_wnd->window, style, + "button5", (gchar **) xpm_split_view); + replace_button_icon(xml, main_wnd->window, style, + "button6", (gchar **) xpm_tree_view); + +#if 0 + switch (view_mode) { + case SINGLE_VIEW: + widget = glade_xml_get_widget(xml, "button4"); + g_signal_emit_by_name(widget, "clicked"); + break; + case SPLIT_VIEW: + widget = glade_xml_get_widget(xml, "button5"); + g_signal_emit_by_name(widget, "clicked"); + break; + case FULL_VIEW: + widget = glade_xml_get_widget(xml, "button6"); + g_signal_emit_by_name(widget, "clicked"); + break; + } +#endif + txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", + "foreground", "red", + "weight", PANGO_WEIGHT_BOLD, + NULL); + tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", + /*"style", PANGO_STYLE_OBLIQUE, */ + NULL); + + sprintf(title, _("Linux Kernel v%s Configuration"), + getenv("KERNELVERSION")); + gtk_window_set_title(GTK_WINDOW(main_wnd), title); + + gtk_widget_show(main_wnd); +} + +void init_tree_model(void) +{ + gint i; + + tree = tree2 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model2 = GTK_TREE_MODEL(tree2); + + for (parents[0] = NULL, i = 1; i < 256; i++) + parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); + + tree1 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model1 = GTK_TREE_MODEL(tree1); +} + +void init_left_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree1_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + + gtk_tree_view_set_model(view, model1); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, FALSE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + gtk_widget_realize(tree1_w); +} + +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data); +static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle, + gchar * arg1, gpointer user_data); + +void init_right_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree2_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + gint i; + + gtk_tree_view_set_model(view, model2); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, FALSE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "pixbuf", COL_PIXBUF, + "visible", COL_PIXVIS, NULL); + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + /*g_signal_connect(G_OBJECT(renderer), "toggled", + G_CALLBACK(renderer_toggled), NULL); */ + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Name"), renderer, + "text", COL_NAME, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "N", renderer, + "text", COL_NO, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "M", renderer, + "text", COL_MOD, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "Y", renderer, + "text", COL_YES, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Value"), renderer, + "text", COL_VALUE, + "editable", + COL_EDIT, + "foreground-gdk", + COL_COLOR, NULL); + g_signal_connect(G_OBJECT(renderer), "edited", + G_CALLBACK(renderer_edited), NULL); + + column = gtk_tree_view_get_column(view, COL_NAME); + gtk_tree_view_column_set_visible(column, show_name); + column = gtk_tree_view_get_column(view, COL_NO); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_MOD); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_YES); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_VALUE); + gtk_tree_view_column_set_visible(column, show_value); + + if (resizeable) { + for (i = 0; i < COL_VALUE; i++) { + column = gtk_tree_view_get_column(view, i); + gtk_tree_view_column_set_resizable(column, TRUE); + } + } + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); +} + + +/* Utility Functions */ + + +static void text_insert_help(struct menu *menu) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *prompt = _(menu_get_prompt(menu)); + gchar *name; + const char *help; + + help = menu_get_help(menu); + + /* Gettextize if the help text not empty */ + if ((help != 0) && (help[0] != 0)) + help = _(help); + + if (menu->sym && menu->sym->name) + name = g_strdup_printf(menu->sym->name); + else + name = g_strdup(""); + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, " ", 1); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2, + NULL); +} + + +static void text_insert_msg(const char *title, const char *message) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *msg = message; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, + NULL); +} + + +/* Main Windows Callbacks */ + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); +gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, + gpointer user_data) +{ + GtkWidget *dialog, *label; + gint result; + + if (!conf_get_changed()) + return FALSE; + + dialog = gtk_dialog_new_with_buttons(_("Warning !"), + GTK_WINDOW(main_wnd), + (GtkDialogFlags) + (GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_STOCK_OK, + GTK_RESPONSE_YES, + GTK_STOCK_NO, + GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), + GTK_RESPONSE_CANCEL); + + label = gtk_label_new(_("\nSave configuration ?\n")); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show(label); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch (result) { + case GTK_RESPONSE_YES: + on_save_activate(NULL, NULL); + return FALSE; + case GTK_RESPONSE_NO: + return FALSE; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + default: + gtk_widget_destroy(dialog); + return TRUE; + } + + return FALSE; +} + + +void on_window1_destroy(GtkObject * object, gpointer user_data) +{ + gtk_main_quit(); +} + + +void +on_window1_size_request(GtkWidget * widget, + GtkRequisition * requisition, gpointer user_data) +{ + static gint old_h; + gint w, h; + + if (widget->window == NULL) + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + else + gdk_window_get_size(widget->window, &w, &h); + + if (h == old_h) + return; + old_h = h; + + gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); +} + + +/* Menu & Toolbar Callbacks */ + + +static void +load_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_read(fn)) + text_insert_msg(_("Error"), _("Unable to load configuration !")); + else + display_tree(&rootmenu); +} + +void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Load file...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(load_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (conf_write(NULL)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); +} + + +static void +store_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_write(fn)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); + + gtk_widget_destroy(GTK_WIDGET(user_data)); +} + +void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Save file as...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(store_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (!on_window1_delete_event(NULL, NULL, NULL)) + gtk_widget_destroy(GTK_WIDGET(main_wnd)); +} + + +void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); + if (col) + gtk_tree_view_column_set_visible(col, show_name); +} + + +void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + +} + + +void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); + if (col) + gtk_tree_view_column_set_visible(col, show_value); +} + + +void +on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + show_all = GTK_CHECK_MENU_ITEM(menuitem)->active; + + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); // instead of update_tree to speed-up +} + + +void +on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active; + update_tree(&rootmenu, NULL); +} + + +void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *intro_text = _( + "Welcome to gkc, the GTK+ graphical kernel configuration tool\n" + "for Linux.\n" + "For each option, a blank box indicates the feature is disabled, a\n" + "check indicates it is enabled, and a dot indicates that it is to\n" + "be compiled as a module. Clicking on the box will cycle through the three states.\n" + "\n" + "If you do not see an option (e.g., a device driver) that you\n" + "believe should be present, try turning on Show All Options\n" + "under the Options menu.\n" + "Although there is no cross reference yet to help you figure out\n" + "what other options must be enabled to support the option you\n" + "are interested in, you can still view the help of a grayed-out\n" + "option.\n" + "\n" + "Toggling Show Debug Info under the Options menu will show \n" + "the dependencies, which you can then match by examining other options."); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, intro_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *about_text = + _("gkc is copyright (c) 2002 Romain Lievin .\n" + "Based on the source code from Roman Zippel.\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, about_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *license_text = + _("gkc is released under the terms of the GNU GPL v2.\n" + "For more information, please see the source code or\n" + "visit http://www.fsf.org/licenses/licenses.html\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, license_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_back_clicked(GtkButton * button, gpointer user_data) +{ + enum prop_type ptype; + + current = current->parent; + ptype = current->prompt ? current->prompt->type : P_UNKNOWN; + if (ptype != P_MENU) + current = current->parent; + display_tree_part(); + + if (current == &rootmenu) + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_load_clicked(GtkButton * button, gpointer user_data) +{ + on_load1_activate(NULL, user_data); +} + + +void on_single_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = SINGLE_VIEW; + gtk_paned_set_position(GTK_PANED(hpaned), 0); + gtk_widget_hide(tree1_w); + current = &rootmenu; + display_tree_part(); +} + + +void on_split_clicked(GtkButton * button, gpointer user_data) +{ + gint w, h; + view_mode = SPLIT_VIEW; + gtk_widget_show(tree1_w); + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + gtk_paned_set_position(GTK_PANED(hpaned), w / 2); + if (tree2) + gtk_tree_store_clear(tree2); + display_list(); + + /* Disable back btn, like in full mode. */ + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_full_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = FULL_VIEW; + gtk_paned_set_position(GTK_PANED(hpaned), 0); + gtk_widget_hide(tree1_w); + if (tree2) + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_collapse_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); +} + + +void on_expand_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + + +/* CTree Callbacks */ + +/* Change hex/int/string value in the cell */ +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data) +{ + GtkTreePath *path = gtk_tree_path_new_from_string(path_string); + GtkTreeIter iter; + const char *old_def, *new_def; + struct menu *menu; + struct symbol *sym; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + sym = menu->sym; + + gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); + new_def = new_text; + + sym_set_string_value(sym, new_def); + + update_tree(&rootmenu, NULL); + + gtk_tree_path_free(path); +} + +/* Change the value of a symbol and update the tree */ +static void change_sym_value(struct menu *menu, gint col) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + if (!sym) + return; + + if (col == COL_NO) + newval = no; + else if (col == COL_MOD) + newval = mod; + else if (col == COL_YES) + newval = yes; + else + return; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + if (!sym_tristate_within_range(sym, newval)) + newval = yes; + sym_set_tristate_value(sym, newval); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll + break; + case S_INT: + case S_HEX: + case S_STRING: + default: + break; + } +} + +static void toggle_sym_value(struct menu *menu) +{ + if (!menu->sym) + return; + + sym_toggle_tristate_value(menu->sym); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll +} + +static void renderer_toggled(GtkCellRendererToggle * cell, + gchar * path_string, gpointer user_data) +{ + GtkTreePath *path, *sel_path = NULL; + GtkTreeIter iter, sel_iter; + GtkTreeSelection *sel; + struct menu *menu; + + path = gtk_tree_path_new_from_string(path_string); + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w)); + if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter)) + sel_path = gtk_tree_model_get_path(model2, &sel_iter); + if (!sel_path) + goto out1; + if (gtk_tree_path_compare(path, sel_path)) + goto out2; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + toggle_sym_value(menu); + + out2: + gtk_tree_path_free(sel_path); + out1: + gtk_tree_path_free(path); +} + +static gint column2index(GtkTreeViewColumn * column) +{ + gint i; + + for (i = 0; i < COL_NUMBER; i++) { + GtkTreeViewColumn *col; + + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); + if (col == column) + return i; + } + + return -1; +} + + +/* User click: update choice (full) or goes down (single) */ +gboolean +on_treeview2_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + +#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); +#else + gtk_tree_view_get_cursor(view, &path, &column); +#endif + if (path == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return FALSE; + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + col = column2index(column); + if (event->type == GDK_2BUTTON_PRESS) { + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + + if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { + // goes down into menu + current = menu; + display_tree_part(); + gtk_widget_set_sensitive(back_btn, TRUE); + } else if ((col == COL_OPTION)) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } + } else { + if (col == COL_VALUE) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } else if (col == COL_NO || col == COL_MOD + || col == COL_YES) { + change_sym_value(menu, col); + gtk_tree_view_expand_row(view, path, TRUE); + } + } + + return FALSE; +} + +/* Key pressed: update choice */ +gboolean +on_treeview2_key_press_event(GtkWidget * widget, + GdkEventKey * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + + gtk_tree_view_get_cursor(view, &path, &column); + if (path == NULL) + return FALSE; + + if (event->keyval == GDK_space) { + if (gtk_tree_view_row_expanded(view, path)) + gtk_tree_view_collapse_row(view, path); + else + gtk_tree_view_expand_row(view, path, FALSE); + return TRUE; + } + if (event->keyval == GDK_KP_Enter) { + } + if (widget == tree1_w) + return FALSE; + + gtk_tree_model_get_iter(model2, &iter, path); + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + if (!strcasecmp(event->string, "n")) + col = COL_NO; + else if (!strcasecmp(event->string, "m")) + col = COL_MOD; + else if (!strcasecmp(event->string, "y")) + col = COL_YES; + else + col = -1; + change_sym_value(menu, col); + + return FALSE; +} + + +/* Row selection changed: update help */ +void +on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + struct menu *menu; + + selection = gtk_tree_view_get_selection(treeview); + if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + text_insert_help(menu); + } +} + + +/* User click: display sub-tree in the right frame. */ +gboolean +on_treeview1_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); + if (path == NULL) + return FALSE; + + gtk_tree_model_get_iter(model1, &iter, path); + gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); + + if (event->type == GDK_2BUTTON_PRESS) { + toggle_sym_value(menu); + current = menu; + display_tree_part(); + } else { + browsed = menu; + display_tree_part(); + } + + gtk_widget_realize(tree2_w); + gtk_tree_view_set_cursor(view, path, NULL, FALSE); + gtk_widget_grab_focus(tree2_w); + + return FALSE; +} + + +/* Fill a row of strings */ +static gchar **fill_row(struct menu *menu) +{ + static gchar *row[COL_NUMBER]; + struct symbol *sym = menu->sym; + const char *def; + int stype; + tristate val; + enum prop_type ptype; + int i; + + for (i = COL_OPTION; i <= COL_COLOR; i++) + g_free(row[i]); + bzero(row, sizeof(row)); + + row[COL_OPTION] = + g_strdup_printf("%s %s", _(menu_get_prompt(menu)), + sym && sym_has_value(sym) ? "(NEW)" : ""); + + if (show_all && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else + row[COL_COLOR] = g_strdup("Black"); + + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + row[COL_PIXBUF] = (gchar *) xpm_menu; + if (view_mode == SINGLE_VIEW) + row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + case P_COMMENT: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + default: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + break; + } + + if (!sym) + return row; + row[COL_NAME] = g_strdup(sym->name); + + sym_calc_value(sym); + sym->flags &= ~SYMBOL_CHANGED; + + if (sym_is_choice(sym)) { // parse childs for getting final value + struct menu *child; + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) + && child->sym == def_sym) + def_menu = child; + } + + if (def_menu) + row[COL_VALUE] = + g_strdup(_(menu_get_prompt(def_menu))); + } + if (sym->flags & SYMBOL_CHOICEVAL) + row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); + + stype = sym_get_type(sym); + switch (stype) { + case S_BOOLEAN: + if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + if (sym_is_choice(sym)) + break; + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + row[COL_NO] = g_strdup("N"); + row[COL_VALUE] = g_strdup("N"); + row[COL_BTNACT] = GINT_TO_POINTER(FALSE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + case mod: + row[COL_MOD] = g_strdup("M"); + row[COL_VALUE] = g_strdup("M"); + row[COL_BTNINC] = GINT_TO_POINTER(TRUE); + break; + case yes: + row[COL_YES] = g_strdup("Y"); + row[COL_VALUE] = g_strdup("Y"); + row[COL_BTNACT] = GINT_TO_POINTER(TRUE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + } + + if (val != no && sym_tristate_within_range(sym, no)) + row[COL_NO] = g_strdup("_"); + if (val != mod && sym_tristate_within_range(sym, mod)) + row[COL_MOD] = g_strdup("_"); + if (val != yes && sym_tristate_within_range(sym, yes)) + row[COL_YES] = g_strdup("_"); + break; + case S_INT: + case S_HEX: + case S_STRING: + def = sym_get_string_value(sym); + row[COL_VALUE] = g_strdup(def); + row[COL_EDIT] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + } + + return row; +} + + +/* Set the node content with a row of strings */ +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) +{ + GdkColor color; + gboolean success; + GdkPixbuf *pix; + + pix = gdk_pixbuf_new_from_xpm_data((const char **) + row[COL_PIXBUF]); + + gdk_color_parse(row[COL_COLOR], &color); + gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, + FALSE, FALSE, &success); + + gtk_tree_store_set(tree, node, + COL_OPTION, row[COL_OPTION], + COL_NAME, row[COL_NAME], + COL_NO, row[COL_NO], + COL_MOD, row[COL_MOD], + COL_YES, row[COL_YES], + COL_VALUE, row[COL_VALUE], + COL_MENU, (gpointer) menu, + COL_COLOR, &color, + COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), + COL_PIXBUF, pix, + COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), + COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), + COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), + COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), + COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), + -1); + + g_object_unref(pix); +} + + +/* Add a node to the tree */ +static void place_node(struct menu *menu, char **row) +{ + GtkTreeIter *parent = parents[indent - 1]; + GtkTreeIter *node = parents[indent]; + + gtk_tree_store_append(tree, node, parent); + set_node(node, menu, row); +} + + +/* Find a node in the GTK+ tree */ +static GtkTreeIter found; + +/* + * Find a menu in the GtkTree starting at parent. + */ +GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, + struct menu *tofind) +{ + GtkTreeIter iter; + GtkTreeIter *child = &iter; + gboolean valid; + GtkTreeIter *ret; + + valid = gtk_tree_model_iter_children(model2, child, parent); + while (valid) { + struct menu *menu; + + gtk_tree_model_get(model2, child, 6, &menu, -1); + + if (menu == tofind) { + memcpy(&found, child, sizeof(GtkTreeIter)); + return &found; + } + + ret = gtktree_iter_find_node(child, tofind); + if (ret) + return ret; + + valid = gtk_tree_model_iter_next(model2, child); + } + + return NULL; +} + + +/* + * Update the tree by adding/removing entries + * Does not change other nodes + */ +static void update_tree(struct menu *src, GtkTreeIter * dst) +{ + struct menu *child1; + GtkTreeIter iter, tmp; + GtkTreeIter *child2 = &iter; + gboolean valid; + GtkTreeIter *sibling; + struct symbol *sym; + struct property *prop; + struct menu *menu1, *menu2; + + if (src == &rootmenu) + indent = 1; + + valid = gtk_tree_model_iter_children(model2, child2, dst); + for (child1 = src->list; child1; child1 = child1->next) { + + prop = child1->prompt; + sym = child1->sym; + + reparse: + menu1 = child1; + if (valid) + gtk_tree_model_get(model2, child2, COL_MENU, + &menu2, -1); + else + menu2 = NULL; // force adding of a first child + +#ifdef DEBUG + printf("%*c%s | %s\n", indent, ' ', + menu1 ? menu_get_prompt(menu1) : "nil", + menu2 ? menu_get_prompt(menu2) : "nil"); +#endif + + if (!menu_is_visible(child1) && !show_all) { // remove node + if (gtktree_iter_find_node(dst, menu1) != NULL) { + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; // next parent + else + goto reparse; // next child + } else + continue; + } + + if (menu1 != menu2) { + if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node + if (!valid && !menu2) + sibling = NULL; + else + sibling = child2; + gtk_tree_store_insert_before(tree2, + child2, + dst, sibling); + set_node(child2, menu1, fill_row(menu1)); + if (menu2 == NULL) + valid = TRUE; + } else { // remove node + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; // next parent + else + goto reparse; // next child + } + } else if (sym && (sym->flags & SYMBOL_CHANGED)) { + set_node(child2, menu1, fill_row(menu1)); + } + + indent++; + update_tree(child1, child2); + indent--; + + valid = gtk_tree_model_iter_next(model2, child2); + } +} + + +/* Display the whole tree (single/split/full view) */ +static void display_tree(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + enum prop_type ptype; + + if (menu == &rootmenu) { + indent = 1; + current = &rootmenu; + } + + for (child = menu->list; child; child = child->next) { + prop = child->prompt; + sym = child->sym; + ptype = prop ? prop->type : P_UNKNOWN; + + if (sym) + sym->flags &= ~SYMBOL_CHANGED; + + if ((view_mode == SPLIT_VIEW) + && !(child->flags & MENU_ROOT) && (tree == tree1)) + continue; + + if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) + && (tree == tree2)) + continue; + + if (menu_is_visible(child) || show_all) + place_node(child, fill_row(child)); +#ifdef DEBUG + printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); + printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); + dbg_print_ptype(ptype); + printf(" | "); + if (sym) { + dbg_print_stype(sym->type); + printf(" | "); + dbg_print_flags(sym->flags); + printf("\n"); + } else + printf("\n"); +#endif + if ((view_mode != FULL_VIEW) && (ptype == P_MENU) + && (tree == tree2)) + continue; +/* + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW))*/ + if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW)) { + indent++; + display_tree(child); + indent--; + } + } +} + +/* Display a part of the tree starting at current node (single/split view) */ +static void display_tree_part(void) +{ + if (tree2) + gtk_tree_store_clear(tree2); + if (view_mode == SINGLE_VIEW) + display_tree(current); + else if (view_mode == SPLIT_VIEW) + display_tree(browsed); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + +/* Display the list in the left frame (split view) */ +static void display_list(void) +{ + if (tree1) + gtk_tree_store_clear(tree1); + + tree = tree1; + display_tree(&rootmenu); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); + tree = tree2; +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + + +/* Main */ +int main(int ac, char *av[]) +{ + const char *name; + char *env; + gchar *glade_file; + +#ifndef LKC_DIRECT_LINK + kconfig_load(); +#endif + + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + + /* GTK stuffs */ + gtk_set_locale(); + gtk_init(&ac, &av); + glade_init(); + + //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); + //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); + + /* Determine GUI path */ + env = getenv(SRCTREE); + if (env) + glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); + else if (av[0][0] == '/') + glade_file = g_strconcat(av[0], ".glade", NULL); + else + glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); + + /* Load the interface and connect signals */ + init_main_window(glade_file); + init_tree_model(); + init_left_tree(); + init_right_tree(); + + /* Conf stuffs */ + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'a': + //showAll = 1; + break; + case 'h': + case '?': + printf("%s \n", av[0]); + exit(0); + } + name = av[2]; + } else + name = av[1]; + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + + switch (view_mode) { + case SINGLE_VIEW: + display_tree_part(); + break; + case SPLIT_VIEW: + display_list(); + break; + case FULL_VIEW: + display_tree(&rootmenu); + break; + } + + gtk_main(); + + return 0; +} + +static void conf_changed(void) +{ + bool changed = conf_get_changed(); + gtk_widget_set_sensitive(save_btn, changed); + gtk_widget_set_sensitive(save_menu_item, changed); +} diff --git a/config/gconf.glade b/config/gconf.glade new file mode 100644 index 000000000..803233fdd --- /dev/null +++ b/config/gconf.glade @@ -0,0 +1,648 @@ + + + + + + + True + Gtk Kernel Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + + + + True + False + 0 + + + + True + + + + True + _File + True + + + + + + + True + Load a config file + _Load + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in .config + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in a file + Save _as + True + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + Show name + Show _name + True + False + + + + + + + True + Show range (Y/M/N) + Show _range + True + False + + + + + + + True + Show value of the option + Show _data + True + False + + + + + + + True + + + + + + True + Show all options + Show all _options + True + False + + + + + + + True + Show masked options + Show _debug info + True + False + + + + + + + + + + + True + _Help + True + + + + + + + True + _Introduction + True + + + + + + True + gtk-dialog-question + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _About + True + + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _License + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Goes up of one level (single view) + Back + True + gtk-undo + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Load a config file + Load + True + gtk-open + True + True + False + + + + False + True + + + + + + True + Save a config file + Save + True + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Single view + Single + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Split view + Split + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Full view + Full + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Collapse the whole tree in the right frame + Collapse + True + gtk-remove + True + True + False + + + + False + True + + + + + + True + Expand the whole tree in the right frame + Expand + True + gtk-add + True + True + False + + + + False + True + + + + + + + 0 + False + False + + + + + + 1 + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + + + + + + + + True + False + + + + + + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + True + + + + + + + + True + False + + + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + Sorry, no help available for this option yet. + + + + + True + True + + + + + True + True + + + + + 0 + True + True + + + + + + + diff --git a/config/images.c b/config/images.c new file mode 100644 index 000000000..d4f84bd4a --- /dev/null +++ b/config/images.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +static const char *xpm_load[] = { +"22 22 5 1", +". c None", +"# c #000000", +"c c #838100", +"a c #ffff00", +"b c #ffffff", +"......................", +"......................", +"......................", +"............####....#.", +"...........#....##.##.", +"..................###.", +".................####.", +".####...........#####.", +"#abab##########.......", +"#babababababab#.......", +"#ababababababa#.......", +"#babababababab#.......", +"#ababab###############", +"#babab##cccccccccccc##", +"#abab##cccccccccccc##.", +"#bab##cccccccccccc##..", +"#ab##cccccccccccc##...", +"#b##cccccccccccc##....", +"###cccccccccccc##.....", +"##cccccccccccc##......", +"###############.......", +"......................"}; + +static const char *xpm_save[] = { +"22 22 5 1", +". c None", +"# c #000000", +"a c #838100", +"b c #c5c2c5", +"c c #cdb6d5", +"......................", +".####################.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbcbb####.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aaa############aaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaa#############aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +"..##################..", +"......................"}; + +static const char *xpm_back[] = { +"22 22 3 1", +". c None", +"# c #000083", +"a c #838183", +"......................", +"......................", +"......................", +"......................", +"......................", +"...........######a....", +"..#......##########...", +"..##...####......##a..", +"..###.###.........##..", +"..######..........##..", +"..#####...........##..", +"..######..........##..", +"..#######.........##..", +"..########.......##a..", +"...............a###...", +"...............###....", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................"}; + +static const char *xpm_tree_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......................", +"......................"}; + +static const char *xpm_single_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"......................", +"......................"}; + +static const char *xpm_split_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......................", +"......................"}; + +static const char *xpm_symbol_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_mod[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . . ", +" . .. . ", +" . . .. . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_choice_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_choice_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_menu[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_menu_inv[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" .......... ", +" .. ...... ", +" .. .... ", +" .. .. ", +" .. .. ", +" .. .... ", +" .. ...... ", +" .......... ", +" .......... ", +" "}; + +static const char *xpm_menuback[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_void[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/config/kconfig_load.c b/config/kconfig_load.c new file mode 100644 index 000000000..dbdcaad82 --- /dev/null +++ b/config/kconfig_load.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#include "lkc.h" + +#define P(name,type,arg) type (*name ## _p) arg +#include "lkc_proto.h" +#undef P + +void kconfig_load(void) +{ + void *handle; + char *error; + + handle = dlopen("./libkconfig.so", RTLD_LAZY); + if (!handle) { + handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY); + if (!handle) { + fprintf(stderr, "%s\n", dlerror()); + exit(1); + } + } + +#define P(name,type,arg) \ +{ \ + name ## _p = dlsym(handle, #name); \ + if ((error = dlerror())) { \ + fprintf(stderr, "%s\n", error); \ + exit(1); \ + } \ +} +#include "lkc_proto.h" +#undef P +} diff --git a/config/kxgettext.c b/config/kxgettext.c new file mode 100644 index 000000000..8d9ce22b0 --- /dev/null +++ b/config/kxgettext.c @@ -0,0 +1,233 @@ +/* + * Arnaldo Carvalho de Melo , 2005 + * + * Released under the terms of the GNU GPL v2.0 + */ + +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static char *escape(const char* text, char *bf, int len) +{ + char *bfp = bf; + int multiline = strchr(text, '\n') != NULL; + int eol = 0; + int textlen = strlen(text); + + if ((textlen > 0) && (text[textlen-1] == '\n')) + eol = 1; + + *bfp++ = '"'; + --len; + + if (multiline) { + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 3; + } + + while (*text != '\0' && len > 1) { + if (*text == '"') + *bfp++ = '\\'; + else if (*text == '\n') { + *bfp++ = '\\'; + *bfp++ = 'n'; + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 5; + ++text; + goto next; + } + else if (*text == '\\') { + *bfp++ = '\\'; + len--; + } + *bfp++ = *text++; +next: + --len; + } + + if (multiline && eol) + bfp -= 3; + + *bfp++ = '"'; + *bfp = '\0'; + + return bf; +} + +struct file_line { + struct file_line *next; + char* file; + int lineno; +}; + +static struct file_line *file_line__new(char *file, int lineno) +{ + struct file_line *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->file = file; + self->lineno = lineno; + self->next = NULL; +out: + return self; +} + +struct message { + const char *msg; + const char *option; + struct message *next; + struct file_line *files; +}; + +static struct message *message__list; + +static struct message *message__new(const char *msg, char *option, char *file, int lineno) +{ + struct message *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->files = file_line__new(file, lineno); + if (self->files == NULL) + goto out_fail; + + self->msg = strdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + + self->option = option; + self->next = NULL; +out: + return self; +out_fail_msg: + free(self->files); +out_fail: + free(self); + self = NULL; + goto out; +} + +static struct message *mesage__find(const char *msg) +{ + struct message *m = message__list; + + while (m != NULL) { + if (strcmp(m->msg, msg) == 0) + break; + m = m->next; + } + + return m; +} + +static int message__add_file_line(struct message *self, char *file, int lineno) +{ + int rc = -1; + struct file_line *fl = file_line__new(file, lineno); + + if (fl == NULL) + goto out; + + fl->next = self->files; + self->files = fl; + rc = 0; +out: + return rc; +} + +static int message__add(const char *msg, char *option, char *file, int lineno) +{ + int rc = 0; + char bf[16384]; + char *escaped = escape(msg, bf, sizeof(bf)); + struct message *m = mesage__find(escaped); + + if (m != NULL) + rc = message__add_file_line(m, file, lineno); + else { + m = message__new(escaped, option, file, lineno); + + if (m != NULL) { + m->next = message__list; + message__list = m; + } else + rc = -1; + } + return rc; +} + +void menu_build_message_list(struct menu *menu) +{ + struct menu *child; + + message__add(menu_get_prompt(menu), NULL, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + if (menu->sym != NULL && menu_has_help(menu)) + message__add(menu_get_help(menu), menu->sym->name, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + for (child = menu->list; child != NULL; child = child->next) + if (child->prompt != NULL) + menu_build_message_list(child); +} + +static void message__print_file_lineno(struct message *self) +{ + struct file_line *fl = self->files; + + putchar('\n'); + if (self->option != NULL) + printf("# %s:00000\n", self->option); + + printf("#: %s:%d", fl->file, fl->lineno); + fl = fl->next; + + while (fl != NULL) { + printf(", %s:%d", fl->file, fl->lineno); + fl = fl->next; + } + + putchar('\n'); +} + +static void message__print_gettext_msgid_msgstr(struct message *self) +{ + message__print_file_lineno(self); + + printf("msgid %s\n" + "msgstr \"\"\n", self->msg); +} + +void menu__xgettext(void) +{ + struct message *m = message__list; + + while (m != NULL) { + /* skip empty lines ("") */ + if (strlen(m->msg) > sizeof("\"\"")) + message__print_gettext_msgid_msgstr(m); + m = m->next; + } +} + +int main(int ac, char **av) +{ + conf_parse(av[1]); + + menu_build_message_list(menu_get_root_menu(NULL)); + menu__xgettext(); + return 0; +} diff --git a/config/lex.zconf.c_shipped b/config/lex.zconf.c_shipped new file mode 100644 index 000000000..dc3e81807 --- /dev/null +++ b/config/lex.zconf.c_shipped @@ -0,0 +1,2416 @@ + +#line 3 "scripts/kconfig/lex.zconf.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer zconf_create_buffer +#define yy_delete_buffer zconf_delete_buffer +#define yy_flex_debug zconf_flex_debug +#define yy_init_buffer zconf_init_buffer +#define yy_flush_buffer zconf_flush_buffer +#define yy_load_buffer_state zconf_load_buffer_state +#define yy_switch_to_buffer zconf_switch_to_buffer +#define yyin zconfin +#define yyleng zconfleng +#define yylex zconflex +#define yylineno zconflineno +#define yyout zconfout +#define yyrestart zconfrestart +#define yytext zconftext +#define yywrap zconfwrap +#define yyalloc zconfalloc +#define yyrealloc zconfrealloc +#define yyfree zconffree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE zconfrestart(zconfin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int zconfleng; + +extern FILE *zconfin, *zconfout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via zconfrestart()), so that the user can continue scanning by + * just pointing zconfin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when zconftext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int zconfleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void zconfrestart (FILE *input_file ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); +void zconf_delete_buffer (YY_BUFFER_STATE b ); +void zconf_flush_buffer (YY_BUFFER_STATE b ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); + +void *zconfalloc (yy_size_t ); +void *zconfrealloc (void *,yy_size_t ); +void zconffree (void * ); + +#define yy_new_buffer zconf_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define zconfwrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + +typedef int yy_state_type; + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][17] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + }, + + { + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11 + }, + + { + 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12 + }, + + { + 11, -13, 39, 40, -13, -13, 41, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13 + }, + + { + 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14 + + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16 + }, + + { + 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17 + }, + + { + 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, 44, -18, -18, -18 + }, + + { + 11, 45, 45, -19, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + + }, + + { + 11, -20, 46, 47, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20 + }, + + { + 11, 48, -21, -21, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, 49, 49, 50, 49, -22, 49, 49, -22, 49, + 49, 49, 49, 49, 49, -22, 49 + }, + + { + 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, + -23, -23, -23, -23, -23, -23, -23 + }, + + { + 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24 + + }, + + { + 11, 51, 51, 52, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51 + }, + + { + 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26 + }, + + { + 11, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27 + }, + + { + 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, 53, -28, -28 + }, + + { + 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29 + + }, + + { + 11, 54, 54, -30, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + }, + + { + 11, -31, -31, -31, -31, -31, -31, 55, -31, -31, + -31, -31, -31, -31, -31, -31, -31 + }, + + { + 11, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32 + }, + + { + 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33 + }, + + { + 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, 56, 57, 57, -34, -34, -34 + + }, + + { + 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, 57, 57, 57, -35, -35, -35 + }, + + { + 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36 + }, + + { + 11, -37, -37, 58, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37 + }, + + { + 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, + -38, -38, -38, -38, -38, -38, 59 + }, + + { + 11, -39, 39, 40, -39, -39, 41, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39 + + }, + + { + 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43 + }, + + { + 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, 44, -44, -44, -44 + + }, + + { + 11, 45, 45, -45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + }, + + { + 11, -46, 46, 47, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46 + }, + + { + 11, 48, -47, -47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48 + }, + + { + 11, 49, 49, 50, 49, -49, 49, 49, -49, 49, + 49, 49, 49, 49, 49, -49, 49 + + }, + + { + 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50 + }, + + { + 11, -51, -51, 52, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51 + }, + + { + 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52 + }, + + { + 11, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53 + }, + + { + 11, 54, 54, -54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + + }, + + { + 11, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55 + }, + + { + 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, 60, 57, 57, -56, -56, -56 + }, + + { + 11, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, 57, 57, 57, -57, -57, -57 + }, + + { + 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58 + }, + + { + 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59 + + }, + + { + 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, 57, 57, 57, -60, -60, -60 + }, + + } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up zconftext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + zconfleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[61] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 34, 5, 4, 2, 3, 7, 8, 6, 32, 29, + 31, 24, 28, 27, 26, 22, 17, 13, 16, 20, + 22, 11, 12, 19, 19, 14, 22, 22, 4, 2, + 3, 3, 1, 6, 32, 29, 31, 30, 24, 23, + 26, 25, 15, 20, 9, 19, 19, 21, 10, 18 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, + 10, 1, 1, 1, 11, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, + 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 15, 1, 1, 13, 1, 13, 13, 13, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 1, 16, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *zconftext; +#define YY_NO_INPUT 1 + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +void new_string(void) +{ + text = malloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +void alloc_string(const char *str, int size) +{ + text = malloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} + +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int zconflex_destroy (void ); + +int zconfget_debug (void ); + +void zconfset_debug (int debug_flag ); + +YY_EXTRA_TYPE zconfget_extra (void ); + +void zconfset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *zconfget_in (void ); + +void zconfset_in (FILE * in_str ); + +FILE *zconfget_out (void ); + +void zconfset_out (FILE * out_str ); + +int zconfget_leng (void ); + +char *zconfget_text (void ); + +int zconfget_lineno (void ); + +void zconfset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int zconfwrap (void ); +#else +extern int zconfwrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( zconftext, zconfleng, 1, zconfout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + errno=0; \ + while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(zconfin); \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + int str = 0; + int ts, i; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! zconfin ) + zconfin = stdin; + + if ( ! zconfout ) + zconfout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of zconftext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) + ++yy_cp; + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + return T_EOL; +} + YY_BREAK +case 3: +YY_RULE_SETUP + + YY_BREAK +case 4: +YY_RULE_SETUP +{ + BEGIN(COMMAND); +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + unput(zconftext[0]); + BEGIN(COMMAND); +} + YY_BREAK + +case 6: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 7: +YY_RULE_SETUP + + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } + YY_BREAK + +case 9: +YY_RULE_SETUP +return T_AND; + YY_BREAK +case 10: +YY_RULE_SETUP +return T_OR; + YY_BREAK +case 11: +YY_RULE_SETUP +return T_OPEN_PAREN; + YY_BREAK +case 12: +YY_RULE_SETUP +return T_CLOSE_PAREN; + YY_BREAK +case 13: +YY_RULE_SETUP +return T_NOT; + YY_BREAK +case 14: +YY_RULE_SETUP +return T_EQUAL; + YY_BREAK +case 15: +YY_RULE_SETUP +return T_UNEQUAL; + YY_BREAK +case 16: +YY_RULE_SETUP +{ + str = zconftext[0]; + new_string(); + BEGIN(STRING); + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +BEGIN(INITIAL); current_file->lineno++; return T_EOL; + YY_BREAK +case 18: +YY_RULE_SETUP +/* ignore */ + YY_BREAK +case 19: +YY_RULE_SETUP +{ + struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 20: +YY_RULE_SETUP +/* comment */ + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +current_file->lineno++; + YY_BREAK +case 22: +YY_RULE_SETUP + + YY_BREAK +case YY_STATE_EOF(PARAM): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 23: +/* rule 23 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 24: +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + } + YY_BREAK +case 25: +/* rule 25 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 26: +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + } + YY_BREAK +case 27: +YY_RULE_SETUP +{ + if (str == zconftext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(zconftext, 1); + } + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +{ + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + YY_BREAK +case YY_STATE_EOF(STRING): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 29: +YY_RULE_SETUP +{ + ts = 0; + for (i = 0; i < zconfleng; i++) { + if (zconftext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + YY_BREAK +case 30: +/* rule 30 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK +case 31: +/* rule 31 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + append_string("\n", 1); + } + YY_BREAK +case 32: +YY_RULE_SETUP +{ + while (zconfleng) { + if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) + break; + zconfleng--; + } + append_string(zconftext, zconfleng); + if (!first_ts) + first_ts = last_ts; + } + YY_BREAK +case YY_STATE_EOF(HELP): +{ + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK + +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMAND): +{ + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(zconfin); + yyterminate(); +} + YY_BREAK +case 33: +YY_RULE_SETUP +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed zconfin at a new source and called + * zconflex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( zconfwrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * zconftext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of zconflex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + zconfrestart(zconfin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + + yy_current_state = yy_nxt[yy_current_state][1]; + yy_is_jam = (yy_current_state <= 0); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up zconftext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + zconfrestart(zconfin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( zconfwrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve zconftext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void zconfrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); + zconf_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * zconfpop_buffer_state(); + * zconfpush_buffer_state(new_buffer); + */ + zconfensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + zconf_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (zconfwrap()) processing, but the only time this flag + * is looked at is after zconfwrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void zconf_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + zconf_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + * + */ + void zconf_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + zconffree((void *) b->yy_ch_buf ); + + zconffree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ + static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + zconf_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then zconf_init_buffer was _probably_ + * called from zconfrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void zconf_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + zconfensure_buffer_stack(); + + /* This block is copied from zconf_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from zconf_switch_to_buffer. */ + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void zconfpop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + zconf_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) +{ + + return zconf_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) zconfalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = zconf_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + zconftext[zconfleng] = (yy_hold_char); \ + (yy_c_buf_p) = zconftext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + zconfleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int zconfget_lineno (void) +{ + + return zconflineno; +} + +/** Get the input stream. + * + */ +FILE *zconfget_in (void) +{ + return zconfin; +} + +/** Get the output stream. + * + */ +FILE *zconfget_out (void) +{ + return zconfout; +} + +/** Get the length of the current token. + * + */ +int zconfget_leng (void) +{ + return zconfleng; +} + +/** Get the current token. + * + */ + +char *zconfget_text (void) +{ + return zconftext; +} + +/** Set the current line number. + * @param line_number + * + */ +void zconfset_lineno (int line_number ) +{ + + zconflineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE * in_str ) +{ + zconfin = in_str ; +} + +void zconfset_out (FILE * out_str ) +{ + zconfout = out_str ; +} + +int zconfget_debug (void) +{ + return zconf_flex_debug; +} + +void zconfset_debug (int bdebug ) +{ + zconf_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from zconflex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + zconfin = stdin; + zconfout = stdout; +#else + zconfin = (FILE *) 0; + zconfout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * zconflex_init() + */ + return 0; +} + +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + zconfpop_buffer_state(); + } + + /* Destroy the stack itself. */ + zconffree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * zconflex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *zconfalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *zconfrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void zconffree (void * ptr ) +{ + free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = malloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; + current_file->flags = FILE_BUSY; +} + +void zconf_nextfile(const char *name) +{ + struct file *file = file_lookup(name); + struct buffer *buf = malloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); + exit(1); + } + zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + if (file->flags & FILE_BUSY) { + printf("%s:%d: do not source '%s' from itself\n", + zconf_curname(), zconf_lineno(), name); + exit(1); + } + if (file->flags & FILE_SCANNED) { + printf("%s:%d: file '%s' is already sourced from '%s'\n", + zconf_curname(), zconf_lineno(), name, + file->parent->name); + exit(1); + } + file->flags |= FILE_BUSY; + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file->flags |= FILE_SCANNED; + current_file->flags &= ~FILE_BUSY; + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(zconfin); + zconf_delete_buffer(YY_CURRENT_BUFFER); + zconf_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} + diff --git a/config/lkc.h b/config/lkc.h new file mode 100644 index 000000000..f379b0bf8 --- /dev/null +++ b/config/lkc.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LKC_DIRECT_LINK +#define P(name,type,arg) extern type name arg +#else +#include "lkc_defs.h" +#define P(name,type,arg) extern type (*name ## _p) arg +#endif +#include "lkc_proto.h" +#undef P + +#define SRCTREE "srctree" + +#define PACKAGE "linux" +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + + +#define TF_COMMAND 0x0001 +#define TF_PARAM 0x0002 +#define TF_OPTION 0x0004 + +enum conf_def_mode { + def_default, + def_yes, + def_mod, + def_no, + def_random +}; + +#define T_OPT_MODULES 1 +#define T_OPT_DEFCONFIG_LIST 2 +#define T_OPT_ENV 3 + +struct kconf_id { + int name; + int token; + unsigned int flags; + enum symbol_type stype; +}; + +int zconfparse(void); +void zconfdump(FILE *out); + +extern int zconfdebug; +void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); +void zconf_initscan(const char *name); +void zconf_nextfile(const char *name); +int zconf_lineno(void); +char *zconf_curname(void); + +/* confdata.c */ +const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); +char *conf_get_default_confname(void); +void sym_set_change_count(int count); +void sym_add_change_count(int count); +void conf_set_all_new_symbols(enum conf_def_mode mode); + +/* kconfig_load.c */ +void kconfig_load(void); + +/* menu.c */ +void menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_end_entry(void); +void menu_add_dep(struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_add_option(int token, char *arg); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +/* util.c */ +struct file *file_lookup(const char *name); +int file_write_dep(const char *name); + +struct gstr { + size_t len; + char *s; +}; +struct gstr str_new(void); +struct gstr str_assign(const char *s); +void str_free(struct gstr *gs); +void str_append(struct gstr *gs, const char *s); +void str_printf(struct gstr *gs, const char *fmt, ...); +const char *str_get(struct gstr *gs); + +/* symbol.c */ +extern struct expr *sym_env_list; + +void sym_init(void); +void sym_clear_all_valid(void); +void sym_set_all_changed(void); +void sym_set_changed(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); +struct property *sym_get_env_prop(struct symbol *sym); + +static inline tristate sym_get_tristate_value(struct symbol *sym) +{ + return sym->curr.tri; +} + + +static inline struct symbol *sym_get_choice_value(struct symbol *sym) +{ + return (struct symbol *)sym->curr.val; +} + +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) +{ + return sym_set_tristate_value(chval, yes); +} + +static inline bool sym_is_choice(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICE ? true : false; +} + +static inline bool sym_is_choice_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICEVAL ? true : false; +} + +static inline bool sym_is_optional(struct symbol *sym) +{ + return sym->flags & SYMBOL_OPTIONAL ? true : false; +} + +static inline bool sym_has_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_DEF_USER ? true : false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LKC_H */ diff --git a/config/lkc_proto.h b/config/lkc_proto.h new file mode 100644 index 000000000..8e6946131 --- /dev/null +++ b/config/lkc_proto.h @@ -0,0 +1,45 @@ + +/* confdata.c */ +P(conf_parse,void,(const char *name)); +P(conf_read,int,(const char *name)); +P(conf_read_simple,int,(const char *name, int)); +P(conf_write,int,(const char *name)); +P(conf_write_autoconf,int,(void)); +P(conf_get_changed,bool,(void)); +P(conf_set_changed_callback, void,(void (*fn)(void))); + +/* menu.c */ +P(rootmenu,struct menu,); + +P(menu_is_visible,bool,(struct menu *menu)); +P(menu_get_prompt,const char *,(struct menu *menu)); +P(menu_get_root_menu,struct menu *,(struct menu *menu)); +P(menu_get_parent_menu,struct menu *,(struct menu *menu)); +P(menu_has_help,bool,(struct menu *menu)); +P(menu_get_help,const char *,(struct menu *menu)); + +/* symbol.c */ +P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); + +P(sym_lookup,struct symbol *,(const char *name, int flags)); +P(sym_find,struct symbol *,(const char *name)); +P(sym_re_search,struct symbol **,(const char *pattern)); +P(sym_type_name,const char *,(enum symbol_type type)); +P(sym_calc_value,void,(struct symbol *sym)); +P(sym_get_type,enum symbol_type,(struct symbol *sym)); +P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); +P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); +P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); +P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); +P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); +P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); +P(sym_is_changable,bool,(struct symbol *sym)); +P(sym_get_choice_prop,struct property *,(struct symbol *sym)); +P(sym_get_default_prop,struct property *,(struct symbol *sym)); +P(sym_get_string_value,const char *,(struct symbol *sym)); + +P(prop_get_type_name,const char *,(enum prop_type type)); + +/* expr.c */ +P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); +P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); diff --git a/config/lxdialog/.gitignore b/config/lxdialog/.gitignore new file mode 100644 index 000000000..90b08ff02 --- /dev/null +++ b/config/lxdialog/.gitignore @@ -0,0 +1,4 @@ +# +# Generated files +# +lxdialog diff --git a/config/lxdialog/BIG.FAT.WARNING b/config/lxdialog/BIG.FAT.WARNING new file mode 100644 index 000000000..a8999d82b --- /dev/null +++ b/config/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +This is NOT the official version of dialog. This version has been +significantly modified from the original. It is for use by the Linux +kernel configuration script. Please do not bother Savio Lam with +questions about this program. diff --git a/config/lxdialog/check-lxdialog.sh b/config/lxdialog/check-lxdialog.sh new file mode 100644 index 000000000..fcef0f59d --- /dev/null +++ b/config/lxdialog/check-lxdialog.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# Check ncurses compatibility + +# What library to link +ldflags() +{ + for ext in so a dylib ; do + for lib in ncursesw ncurses curses ; do + $cc -print-file-name=lib${lib}.${ext} | grep -q / + if [ $? -eq 0 ]; then + echo "-l${lib}" + exit + fi + done + done + exit 1 +} + +# Where is ncurses.h? +ccflags() +{ + if [ -f /usr/include/ncurses/ncurses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses/curses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses.h ]; then + echo '-DCURSES_LOC=""' + else + echo '-DCURSES_LOC=""' + fi +} + +# Temp file, try to clean up after us +tmp=.lxdialog.tmp +trap "rm -f $tmp" 0 1 2 3 15 + +# Check if we can link to ncurses +check() { + $cc -xc - -o $tmp 2>/dev/null <<'EOF' +#include CURSES_LOC +main() {} +EOF + if [ $? != 0 ]; then + echo " *** Unable to find the ncurses libraries or the" 1>&2 + echo " *** required header files." 1>&2 + echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 + echo " *** " 1>&2 + echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 + echo " *** " 1>&2 + exit 1 + fi +} + +usage() { + printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" +} + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +cc="" +case "$1" in + "-check") + shift + cc="$@" + check + ;; + "-ccflags") + ccflags + ;; + "-ldflags") + shift + cc="$@" + ldflags + ;; + "*") + usage + exit 1 + ;; +esac diff --git a/config/lxdialog/checklist.c b/config/lxdialog/checklist.c new file mode 100644 index 000000000..bcc6f19c3 --- /dev/null +++ b/config/lxdialog/checklist.c @@ -0,0 +1,326 @@ +/* + * checklist.c -- implements the checklist box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension + * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static int list_width, check_x, item_x; + +/* + * Print list item + */ +static void print_item(WINDOW * win, int choice, int selected) +{ + int i; + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, choice, 0); + for (i = 0; i < list_width; i++) + waddch(win, ' '); + + wmove(win, choice, check_x); + wattrset(win, selected ? dlg.check_selected.atr + : dlg.check.atr); + if (!item_is_tag(':')) + wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); + + wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); + mvwaddch(win, choice, item_x, item_str()[0]); + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + waddstr(win, (char *)item_str() + 1); + if (selected) { + wmove(win, choice, check_x + 1); + wrefresh(win); + } +} + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, + int y, int x, int height) +{ + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + + if ((height < item_no) && (scroll + choice < item_no - 1)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } +} + +/* + * Display the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext("Select"), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with a list of options that can be turned on or off + * in the style of radiolist (only one option turned on at a time). + */ +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height) +{ + int i, x, y, box_x, box_y; + int key = 0, button = 0, choice = 0, scroll = 0, max_choice; + WINDOW *dialog, *list; + + /* which item to highlight */ + item_foreach() { + if (item_is_tag('X')) + choice = item_n(); + if (item_is_selected()) { + choice = item_n(); + break; + } + } + +do_resize: + if (getmaxy(stdscr) < (height + 6)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + 6)) + return -ERRDISPLAYTOOSMALL; + + max_choice = MIN(list_height, item_count()); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + list_width = width - 6; + box_y = height - list_height - 5; + box_x = (width - list_width) / 2 - 1; + + /* create new window for the list */ + list = subwin(dialog, list_height, list_width, y + box_y + 1, + x + box_x + 1); + + keypad(list, TRUE); + + /* draw a box around the list items */ + draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + /* Find length of longest item in order to center checklist */ + check_x = 0; + item_foreach() + check_x = MAX(check_x, strlen(item_str()) + 4); + + check_x = (list_width - check_x) / 2; + item_x = check_x + 4; + + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + + /* Print the list */ + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + print_item(list, i, i == choice); + } + + print_arrows(dialog, choice, item_count(), scroll, + box_y, box_x + check_x + 5, list_height); + + print_buttons(dialog, height, width, 0); + + wnoutrefresh(dialog); + wnoutrefresh(list); + doupdate(); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + for (i = 0; i < max_choice; i++) { + item_set(i + scroll); + if (toupper(key) == toupper(item_str()[0])) + break; + } + + if (i < max_choice || key == KEY_UP || key == KEY_DOWN || + key == '+' || key == '-') { + if (key == KEY_UP || key == '-') { + if (!choice) { + if (!scroll) + continue; + /* Scroll list down */ + if (list_height > 1) { + /* De-highlight current first item */ + item_set(scroll); + print_item(list, 0, FALSE); + scrollok(list, TRUE); + wscrl(list, -1); + scrollok(list, FALSE); + } + scroll--; + item_set(scroll); + print_item(list, 0, TRUE); + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice - 1; + } else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll + choice >= item_count() - 1) + continue; + /* Scroll list up */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + item_set(scroll + max_choice - 1); + print_item(list, + max_choice - 1, + FALSE); + scrollok(list, TRUE); + wscrl(list, 1); + scrollok(list, FALSE); + } + scroll++; + item_set(scroll + max_choice - 1); + print_item(list, max_choice - 1, TRUE); + + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice + 1; + } + if (i != choice) { + /* De-highlight current item */ + item_set(scroll + choice); + print_item(list, choice, FALSE); + /* Highlight new item */ + choice = i; + item_set(scroll + choice); + print_item(list, choice, TRUE); + wnoutrefresh(dialog); + wrefresh(list); + } + continue; /* wait for another key press */ + } + switch (key) { + case 'H': + case 'h': + case '?': + button = 1; + /* fall-through */ + case 'S': + case 's': + case ' ': + case '\n': + item_foreach() + item_set_selected(0); + item_set(scroll + choice); + item_set_selected(1); + delwin(list); + delwin(dialog); + return button; + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(list); + delwin(dialog); + on_key_resize(); + goto do_resize; + } + + /* Now, update everything... */ + doupdate(); + } + delwin(list); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/config/lxdialog/dialog.h b/config/lxdialog/dialog.h new file mode 100644 index 000000000..b5211fce0 --- /dev/null +++ b/config/lxdialog/dialog.h @@ -0,0 +1,230 @@ +/* + * dialog.h -- common declarations for all dialog modules + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef KBUILD_NO_NLS +# include +#else +# define gettext(Msgid) ((const char *) (Msgid)) +#endif + +#ifdef __sun__ +#define CURS_MACROS +#endif +#include CURSES_LOC + +/* + * Colors in ncurses 1.9.9e do not work properly since foreground and + * background colors are OR'd rather than separately masked. This version + * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible + * with standard curses. The simplest fix (to make this work with standard + * curses) uses the wbkgdset() function, not used in the original hack. + * Turn it off if we're building with 1.9.9e, since it just confuses things. + */ +#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) +#define OLD_NCURSES 1 +#undef wbkgdset +#define wbkgdset(w,p) /*nothing */ +#else +#define OLD_NCURSES 0 +#endif + +#define TR(params) _tracef params + +#define KEY_ESC 27 +#define TAB 9 +#define MAX_LEN 2048 +#define BUF_SIZE (10*1024) +#define MIN(x,y) (x < y ? x : y) +#define MAX(x,y) (x > y ? x : y) + +#ifndef ACS_ULCORNER +#define ACS_ULCORNER '+' +#endif +#ifndef ACS_LLCORNER +#define ACS_LLCORNER '+' +#endif +#ifndef ACS_URCORNER +#define ACS_URCORNER '+' +#endif +#ifndef ACS_LRCORNER +#define ACS_LRCORNER '+' +#endif +#ifndef ACS_HLINE +#define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +#define ACS_VLINE '|' +#endif +#ifndef ACS_LTEE +#define ACS_LTEE '+' +#endif +#ifndef ACS_RTEE +#define ACS_RTEE '+' +#endif +#ifndef ACS_UARROW +#define ACS_UARROW '^' +#endif +#ifndef ACS_DARROW +#define ACS_DARROW 'v' +#endif + +/* error return codes */ +#define ERRDISPLAYTOOSMALL (KEY_MAX + 1) + +/* + * Color definitions + */ +struct dialog_color { + chtype atr; /* Color attribute */ + int fg; /* foreground */ + int bg; /* background */ + int hl; /* highlight this item */ +}; + +struct dialog_info { + const char *backtitle; + struct dialog_color screen; + struct dialog_color shadow; + struct dialog_color dialog; + struct dialog_color title; + struct dialog_color border; + struct dialog_color button_active; + struct dialog_color button_inactive; + struct dialog_color button_key_active; + struct dialog_color button_key_inactive; + struct dialog_color button_label_active; + struct dialog_color button_label_inactive; + struct dialog_color inputbox; + struct dialog_color inputbox_border; + struct dialog_color searchbox; + struct dialog_color searchbox_title; + struct dialog_color searchbox_border; + struct dialog_color position_indicator; + struct dialog_color menubox; + struct dialog_color menubox_border; + struct dialog_color item; + struct dialog_color item_selected; + struct dialog_color tag; + struct dialog_color tag_selected; + struct dialog_color tag_key; + struct dialog_color tag_key_selected; + struct dialog_color check; + struct dialog_color check_selected; + struct dialog_color uarrow; + struct dialog_color darrow; +}; + +/* + * Global variables + */ +extern struct dialog_info dlg; +extern char dialog_input_result[]; + +/* + * Function prototypes + */ + +/* item list as used by checklist and menubox */ +void item_reset(void); +void item_make(const char *fmt, ...); +void item_add_str(const char *fmt, ...); +void item_set_tag(char tag); +void item_set_data(void *p); +void item_set_selected(int val); +int item_activate_selected(void); +void *item_data(void); +char item_tag(void); + +/* item list manipulation for lxdialog use */ +#define MAXITEMSTR 200 +struct dialog_item { + char str[MAXITEMSTR]; /* promtp displayed */ + char tag; + void *data; /* pointer to menu item - used by menubox+checklist */ + int selected; /* Set to 1 by dialog_*() function if selected. */ +}; + +/* list of lialog_items */ +struct dialog_list { + struct dialog_item node; + struct dialog_list *next; +}; + +extern struct dialog_list *item_cur; +extern struct dialog_list item_nil; +extern struct dialog_list *item_head; + +int item_count(void); +void item_set(int n); +int item_n(void); +const char *item_str(void); +int item_is_selected(void); +int item_is_tag(char tag); +#define item_foreach() \ + for (item_cur = item_head ? item_head: item_cur; \ + item_cur && (item_cur != &item_nil); item_cur = item_cur->next) + +/* generic key handlers */ +int on_key_esc(WINDOW *win); +int on_key_resize(void); + +int init_dialog(const char *backtitle); +void set_dialog_backtitle(const char *backtitle); +void end_dialog(int x, int y); +void attr_clear(WINDOW * win, int height, int width, chtype attr); +void dialog_clear(void); +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); +void print_button(WINDOW * win, const char *label, int y, int x, int selected); +void print_title(WINDOW *dialog, const char *title, int width); +void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, + chtype border); +void draw_shadow(WINDOW * win, int y, int x, int height, int width); + +int first_alpha(const char *string, const char *exempt); +int dialog_yesno(const char *title, const char *prompt, int height, int width); +int dialog_msgbox(const char *title, const char *prompt, int height, + int width, int pause); +int dialog_textbox(const char *title, const char *file, int height, int width); +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll); +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height); +extern char dialog_input_result[]; +int dialog_inputbox(const char *title, const char *prompt, int height, + int width, const char *init); + +/* + * This is the base for fictitious keys, which activate + * the buttons. + * + * Mouse-generated keys are the following: + * -- the first 32 are used as numbers, in addition to '0'-'9' + * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') + * -- uppercase chars are used to invoke the button (M_EVENT + 'O') + */ +#define M_EVENT (KEY_MAX+1) diff --git a/config/lxdialog/inputbox.c b/config/lxdialog/inputbox.c new file mode 100644 index 000000000..616c60138 --- /dev/null +++ b/config/lxdialog/inputbox.c @@ -0,0 +1,238 @@ +/* + * inputbox.c -- implements the input box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +char dialog_input_result[MAX_LEN + 1]; + +/* + * Print the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext(" Ok "), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box for inputing a string + */ +int dialog_inputbox(const char *title, const char *prompt, int height, int width, + const char *init) +{ + int i, x, y, box_y, box_x, box_width; + int input_x = 0, scroll = 0, key = 0, button = -1; + char *instr = dialog_input_result; + WINDOW *dialog; + + if (!init) + instr[0] = '\0'; + else + strcpy(instr, init); + +do_resize: + if (getmaxy(stdscr) <= (height - 2)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) <= (width - 2)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + /* Draw the input field box */ + box_width = width - 6; + getyx(dialog, y, x); + box_y = y + 2; + box_x = (width - box_width) / 2; + draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, + dlg.dialog.atr, dlg.border.atr); + + print_buttons(dialog, height, width, 0); + + /* Set up the initial value */ + wmove(dialog, box_y, box_x); + wattrset(dialog, dlg.inputbox.atr); + + input_x = strlen(instr); + + if (input_x >= box_width) { + scroll = input_x - box_width + 1; + input_x = box_width - 1; + for (i = 0; i < box_width - 1; i++) + waddch(dialog, instr[scroll + i]); + } else { + waddstr(dialog, instr); + } + + wmove(dialog, box_y, box_x + input_x); + + wrefresh(dialog); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + if (button == -1) { /* Input box selected */ + switch (key) { + case TAB: + case KEY_UP: + case KEY_DOWN: + break; + case KEY_LEFT: + continue; + case KEY_RIGHT: + continue; + case KEY_BACKSPACE: + case 127: + if (input_x || scroll) { + wattrset(dialog, dlg.inputbox.atr); + if (!input_x) { + scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1); + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) + waddch(dialog, + instr[scroll + input_x + i] ? + instr[scroll + input_x + i] : ' '); + input_x = strlen(instr) - scroll; + } else + input_x--; + instr[scroll + input_x] = '\0'; + mvwaddch(dialog, box_y, input_x + box_x, ' '); + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + } + continue; + default: + if (key < 0x100 && isprint(key)) { + if (scroll + input_x < MAX_LEN) { + wattrset(dialog, dlg.inputbox.atr); + instr[scroll + input_x] = key; + instr[scroll + input_x + 1] = '\0'; + if (input_x == box_width - 1) { + scroll++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width - 1; i++) + waddch(dialog, instr [scroll + i]); + } else { + wmove(dialog, box_y, input_x++ + box_x); + waddch(dialog, key); + } + wrefresh(dialog); + } else + flash(); /* Alarm user about overflow */ + continue; + } + } + } + switch (key) { + case 'O': + case 'o': + delwin(dialog); + return 0; + case 'H': + case 'h': + delwin(dialog); + return 1; + case KEY_UP: + case KEY_LEFT: + switch (button) { + case -1: + button = 1; /* Indicates "Cancel" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 0: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + case 1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + } + break; + case TAB: + case KEY_DOWN: + case KEY_RIGHT: + switch (button) { + case -1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + case 0: + button = 1; /* Indicates "Cancel" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 1: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + } + break; + case ' ': + case '\n': + delwin(dialog); + return (button == -1 ? 0 : button); + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return KEY_ESC; /* ESC pressed */ +} diff --git a/config/lxdialog/menubox.c b/config/lxdialog/menubox.c new file mode 100644 index 000000000..fa9d633f2 --- /dev/null +++ b/config/lxdialog/menubox.c @@ -0,0 +1,434 @@ +/* + * menubox.c -- implements the menu box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Changes by Clifford Wolf (god@clifford.at) + * + * [ 1998-06-13 ] + * + * *) A bugfix for the Page-Down problem + * + * *) Formerly when I used Page Down and Page Up, the cursor would be set + * to the first position in the menu box. Now lxdialog is a bit + * smarter and works more like other menu systems (just have a look at + * it). + * + * *) Formerly if I selected something my scrolling would be broken because + * lxdialog is re-invoked by the Menuconfig shell script, can't + * remember the last scrolling position, and just sets it so that the + * cursor is at the bottom of the box. Now it writes the temporary file + * lxdialog.scrltmp which contains this information. The file is + * deleted by lxdialog if the user leaves a submenu or enters a new + * one, but it would be nice if Menuconfig could make another "rm -f" + * just to be sure. Just try it out - you will recognise a difference! + * + * [ 1998-06-14 ] + * + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files + * and menus change their size on the fly. + * + * *) If for some reason the last scrolling position is not saved by + * lxdialog, it sets the scrolling so that the selected item is in the + * middle of the menu box, not at the bottom. + * + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. + * This fixes a bug in Menuconfig where using ' ' to descend into menus + * would leave mis-synchronized lxdialog.scrltmp files lying around, + * fscanf would read in 'scroll', and eventually that value would get used. + */ + +#include "dialog.h" + +static int menu_width, item_x; + +/* + * Print menu item + */ +static void do_print_item(WINDOW * win, const char *item, int line_y, + int selected, int hotkey) +{ + int j; + char *menu_item = malloc(menu_width + 1); + + strncpy(menu_item, item, menu_width - item_x); + menu_item[menu_width - item_x] = '\0'; + j = first_alpha(menu_item, "YyNnMmHh"); + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, line_y, 0); +#if OLD_NCURSES + { + int i; + for (i = 0; i < menu_width; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + mvwaddstr(win, line_y, item_x, menu_item); + if (hotkey) { + wattrset(win, selected ? dlg.tag_key_selected.atr + : dlg.tag_key.atr); + mvwaddch(win, line_y, item_x + j, menu_item[j]); + } + if (selected) { + wmove(win, line_y, item_x + 1); + } + free(menu_item); + wrefresh(win); +} + +#define print_item(index, choice, selected) \ +do { \ + item_set(index); \ + do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \ +} while (0) + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, + int height) +{ + int cur_y, cur_x; + + getyx(win, cur_y, cur_x); + + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + wrefresh(win); + + if ((height < item_no) && (scroll + height < item_no)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + wmove(win, cur_y, cur_x); + wrefresh(win); +} + +/* + * Display the termination buttons. + */ +static void print_buttons(WINDOW * win, int height, int width, int selected) +{ + int x = width / 2 - 16; + int y = height - 2; + + print_button(win, gettext("Select"), y, x, selected == 0); + print_button(win, gettext(" Exit "), y, x + 12, selected == 1); + print_button(win, gettext(" Help "), y, x + 24, selected == 2); + + wmove(win, y, x + 1 + 12 * selected); + wrefresh(win); +} + +/* scroll up n lines (n may be negative) */ +static void do_scroll(WINDOW *win, int *scroll, int n) +{ + /* Scroll menu up */ + scrollok(win, TRUE); + wscrl(win, n); + scrollok(win, FALSE); + *scroll = *scroll + n; + wrefresh(win); +} + +/* + * Display a menu for choosing among a number of options + */ +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll) +{ + int i, j, x, y, box_x, box_y; + int height, width, menu_height; + int key = 0, button = 0, scroll = 0, choice = 0; + int first_item = 0, max_choice; + WINDOW *dialog, *menu; + +do_resize: + height = getmaxy(stdscr); + width = getmaxx(stdscr); + if (height < 15 || width < 65) + return -ERRDISPLAYTOOSMALL; + + height -= 4; + width -= 5; + menu_height = height - 10; + + max_choice = MIN(menu_height, item_count()); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + menu_width = width - 6; + box_y = height - menu_height - 5; + box_x = (width - menu_width) / 2 - 1; + + /* create new window for the menu */ + menu = subwin(dialog, menu_height, menu_width, + y + box_y + 1, x + box_x + 1); + keypad(menu, TRUE); + + /* draw a box around the menu items */ + draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + if (menu_width >= 80) + item_x = (menu_width - 70) / 2; + else + item_x = 4; + + /* Set choice to default item */ + item_foreach() + if (selected && (selected == item_data())) + choice = item_n(); + /* get the saved scroll info */ + scroll = *s_scroll; + if ((scroll <= choice) && (scroll + max_choice > choice) && + (scroll >= 0) && (scroll + max_choice <= item_count())) { + first_item = scroll; + choice = choice - scroll; + } else { + scroll = 0; + } + if ((choice >= max_choice)) { + if (choice >= item_count() - max_choice / 2) + scroll = first_item = item_count() - max_choice; + else + scroll = first_item = choice - max_choice / 2; + choice = choice - scroll; + } + + /* Print the menu */ + for (i = 0; i < max_choice; i++) { + print_item(first_item + i, i, i == choice); + } + + wnoutrefresh(menu); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + print_buttons(dialog, height, width, 0); + wmove(menu, choice, item_x + 1); + wrefresh(menu); + + while (key != KEY_ESC) { + key = wgetch(menu); + + if (key < 256 && isalpha(key)) + key = tolower(key); + + if (strchr("ynmh", key)) + i = max_choice; + else { + for (i = choice + 1; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + if (i == max_choice) + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + } + + if (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE) { + /* Remove highligt of current item */ + print_item(scroll + choice, choice, FALSE); + + if (key == KEY_UP || key == '-') { + if (choice < 2 && scroll) { + /* Scroll menu down */ + do_scroll(menu, &scroll, -1); + + print_item(scroll, 0, FALSE); + } else + choice = MAX(choice - 1, 0); + + } else if (key == KEY_DOWN || key == '+') { + print_item(scroll+choice, choice, FALSE); + + if ((choice > max_choice - 3) && + (scroll + max_choice < item_count())) { + /* Scroll menu up */ + do_scroll(menu, &scroll, 1); + + print_item(scroll+max_choice - 1, + max_choice - 1, FALSE); + } else + choice = MIN(choice + 1, max_choice - 1); + + } else if (key == KEY_PPAGE) { + scrollok(menu, TRUE); + for (i = 0; (i < max_choice); i++) { + if (scroll > 0) { + do_scroll(menu, &scroll, -1); + print_item(scroll, 0, FALSE); + } else { + if (choice > 0) + choice--; + } + } + + } else if (key == KEY_NPAGE) { + for (i = 0; (i < max_choice); i++) { + if (scroll + max_choice < item_count()) { + do_scroll(menu, &scroll, 1); + print_item(scroll+max_choice-1, + max_choice - 1, FALSE); + } else { + if (choice + 1 < max_choice) + choice++; + } + } + } else + choice = i; + + print_item(scroll + choice, choice, TRUE); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + wnoutrefresh(dialog); + wrefresh(menu); + + continue; /* wait for another key press */ + } + + switch (key) { + case KEY_LEFT: + case TAB: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 2 : (button > 2 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(menu); + break; + case ' ': + case 's': + case 'y': + case 'n': + case 'm': + case '/': + /* save scroll info */ + *s_scroll = scroll; + delwin(menu); + delwin(dialog); + item_set(scroll + choice); + item_set_selected(1); + switch (key) { + case 's': + return 3; + case 'y': + return 3; + case 'n': + return 4; + case 'm': + return 5; + case ' ': + return 6; + case '/': + return 7; + } + return 0; + case 'h': + case '?': + button = 2; + case '\n': + *s_scroll = scroll; + delwin(menu); + delwin(dialog); + item_set(scroll + choice); + item_set_selected(1); + return button; + case 'e': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(menu); + break; + case KEY_RESIZE: + on_key_resize(); + delwin(menu); + delwin(dialog); + goto do_resize; + } + } + delwin(menu); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/config/lxdialog/textbox.c b/config/lxdialog/textbox.c new file mode 100644 index 000000000..c704712d0 --- /dev/null +++ b/config/lxdialog/textbox.c @@ -0,0 +1,391 @@ +/* + * textbox.c -- implements the text box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static void back_lines(int n); +static void print_page(WINDOW * win, int height, int width); +static void print_line(WINDOW * win, int row, int width); +static char *get_line(void); +static void print_position(WINDOW * win); + +static int hscroll; +static int begin_reached, end_reached, page_length; +static const char *buf; +static const char *page; + +/* + * refresh window content + */ +static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, + int cur_y, int cur_x) +{ + print_page(box, boxh, boxw); + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); +} + + +/* + * Display text from a file in a dialog box. + */ +int dialog_textbox(const char *title, const char *tbuf, + int initial_height, int initial_width) +{ + int i, x, y, cur_x, cur_y, key = 0; + int height, width, boxh, boxw; + int passed_end; + WINDOW *dialog, *box; + + begin_reached = 1; + end_reached = 0; + page_length = 0; + hscroll = 0; + buf = tbuf; + page = buf; /* page is pointer to start of page to be displayed */ + +do_resize: + getmaxyx(stdscr, height, width); + if (height < 8 || width < 8) + return -ERRDISPLAYTOOSMALL; + if (initial_height != 0) + height = initial_height; + else + if (height > 4) + height -= 4; + else + height = 0; + if (initial_width != 0) + width = initial_width; + else + if (width > 5) + width -= 5; + else + width = 0; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + /* Create window for box region, used for scrolling text */ + boxh = height - 4; + boxw = width - 2; + box = subwin(dialog, boxh, boxw, y + 1, x + 1); + wattrset(box, dlg.dialog.atr); + wbkgdset(box, dlg.dialog.atr & A_COLOR); + + keypad(box, TRUE); + + /* register the new window, along with its borders */ + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); + wnoutrefresh(dialog); + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + + /* Print first page of text */ + attr_clear(box, boxh, boxw, dlg.dialog.atr); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); + + while ((key != KEY_ESC) && (key != '\n')) { + key = wgetch(dialog); + switch (key) { + case 'E': /* Exit */ + case 'e': + case 'X': + case 'x': + delwin(box); + delwin(dialog); + return 0; + case 'g': /* First page */ + case KEY_HOME: + if (!begin_reached) { + begin_reached = 1; + page = buf; + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + } + break; + case 'G': /* Last page */ + case KEY_END: + + end_reached = 1; + /* point to last char in buf */ + page = buf + strlen(buf); + back_lines(boxh); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'K': /* Previous line */ + case 'k': + case KEY_UP: + if (!begin_reached) { + back_lines(page_length + 1); + + /* We don't call print_page() here but use + * scrolling to ensure faster screen update. + * However, 'end_reached' and 'page_length' + * should still be updated, and 'page' should + * point to start of next page. This is done + * by calling get_line() in the following + * 'for' loop. */ + scrollok(box, TRUE); + wscrl(box, -1); /* Scroll box region down one line */ + scrollok(box, FALSE); + page_length = 0; + passed_end = 0; + for (i = 0; i < boxh; i++) { + if (!i) { + /* print first line of page */ + print_line(box, 0, boxw); + wnoutrefresh(box); + } else + /* Called to update 'end_reached' and 'page' */ + get_line(); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case 'B': /* Previous page */ + case 'b': + case KEY_PPAGE: + if (begin_reached) + break; + back_lines(page_length + boxh); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'J': /* Next line */ + case 'j': + case KEY_DOWN: + if (!end_reached) { + begin_reached = 0; + scrollok(box, TRUE); + scroll(box); /* Scroll box region up one line */ + scrollok(box, FALSE); + print_line(box, boxh - 1, boxw); + wnoutrefresh(box); + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); + } + break; + case KEY_NPAGE: /* Next page */ + case ' ': + if (end_reached) + break; + + begin_reached = 0; + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case '0': /* Beginning of line */ + case 'H': /* Scroll left */ + case 'h': + case KEY_LEFT: + if (hscroll <= 0) + break; + + if (key == '0') + hscroll = 0; + else + hscroll--; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case 'L': /* Scroll right */ + case 'l': + case KEY_RIGHT: + if (hscroll >= MAX_LEN) + break; + hscroll++; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x); + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + back_lines(height); + delwin(box); + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + delwin(box); + delwin(dialog); + return key; /* ESC pressed */ +} + +/* + * Go back 'n' lines in text. Called by dialog_textbox(). + * 'page' will be updated to point to the desired line in 'buf'. + */ +static void back_lines(int n) +{ + int i; + + begin_reached = 0; + /* Go back 'n' lines */ + for (i = 0; i < n; i++) { + if (*page == '\0') { + if (end_reached) { + end_reached = 0; + continue; + } + } + if (page == buf) { + begin_reached = 1; + return; + } + page--; + do { + if (page == buf) { + begin_reached = 1; + return; + } + page--; + } while (*page != '\n'); + page++; + } +} + +/* + * Print a new page of text. Called by dialog_textbox(). + */ +static void print_page(WINDOW * win, int height, int width) +{ + int i, passed_end = 0; + + page_length = 0; + for (i = 0; i < height; i++) { + print_line(win, i, width); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + wnoutrefresh(win); +} + +/* + * Print a new line of text. Called by dialog_textbox() and print_page(). + */ +static void print_line(WINDOW * win, int row, int width) +{ + int y, x; + char *line; + + line = get_line(); + line += MIN(strlen(line), hscroll); /* Scroll horizontally */ + wmove(win, row, 0); /* move cursor to correct line */ + waddch(win, ' '); + waddnstr(win, line, MIN(strlen(line), width - 2)); + + getyx(win, y, x); + /* Clear 'residue' of previous line */ +#if OLD_NCURSES + { + int i; + for (i = 0; i < width - x; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif +} + +/* + * Return current line of text. Called by dialog_textbox() and print_line(). + * 'page' should point to start of current line before calling, and will be + * updated to point to start of next line. + */ +static char *get_line(void) +{ + int i = 0; + static char line[MAX_LEN + 1]; + + end_reached = 0; + while (*page != '\n') { + if (*page == '\0') { + if (!end_reached) { + end_reached = 1; + break; + } + } else if (i < MAX_LEN) + line[i++] = *(page++); + else { + /* Truncate lines longer than MAX_LEN characters */ + if (i == MAX_LEN) + line[i++] = '\0'; + page++; + } + } + if (i <= MAX_LEN) + line[i] = '\0'; + if (!end_reached) + page++; /* move pass '\n' */ + + return line; +} + +/* + * Print current position + */ +static void print_position(WINDOW * win) +{ + int percent; + + wattrset(win, dlg.position_indicator.atr); + wbkgdset(win, dlg.position_indicator.atr & A_COLOR); + percent = (page - buf) * 100 / strlen(buf); + wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); + wprintw(win, "(%3d%%)", percent); +} diff --git a/config/lxdialog/util.c b/config/lxdialog/util.c new file mode 100644 index 000000000..f2375ad7e --- /dev/null +++ b/config/lxdialog/util.c @@ -0,0 +1,657 @@ +/* + * util.c + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "dialog.h" + +struct dialog_info dlg; + +static void set_mono_theme(void) +{ + dlg.screen.atr = A_NORMAL; + dlg.shadow.atr = A_NORMAL; + dlg.dialog.atr = A_NORMAL; + dlg.title.atr = A_BOLD; + dlg.border.atr = A_NORMAL; + dlg.button_active.atr = A_REVERSE; + dlg.button_inactive.atr = A_DIM; + dlg.button_key_active.atr = A_REVERSE; + dlg.button_key_inactive.atr = A_BOLD; + dlg.button_label_active.atr = A_REVERSE; + dlg.button_label_inactive.atr = A_NORMAL; + dlg.inputbox.atr = A_NORMAL; + dlg.inputbox_border.atr = A_NORMAL; + dlg.searchbox.atr = A_NORMAL; + dlg.searchbox_title.atr = A_BOLD; + dlg.searchbox_border.atr = A_NORMAL; + dlg.position_indicator.atr = A_BOLD; + dlg.menubox.atr = A_NORMAL; + dlg.menubox_border.atr = A_NORMAL; + dlg.item.atr = A_NORMAL; + dlg.item_selected.atr = A_REVERSE; + dlg.tag.atr = A_BOLD; + dlg.tag_selected.atr = A_REVERSE; + dlg.tag_key.atr = A_BOLD; + dlg.tag_key_selected.atr = A_REVERSE; + dlg.check.atr = A_BOLD; + dlg.check_selected.atr = A_REVERSE; + dlg.uarrow.atr = A_BOLD; + dlg.darrow.atr = A_BOLD; +} + +#define DLG_COLOR(dialog, f, b, h) \ +do { \ + dlg.dialog.fg = (f); \ + dlg.dialog.bg = (b); \ + dlg.dialog.hl = (h); \ +} while (0) + +static void set_classic_theme(void) +{ + DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true); + DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false); + DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); + DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true); + DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true); +} + +static void set_blackbg_theme(void) +{ + DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); + DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); + DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); + + DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); + DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); + + DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); + + DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); +} + +static void set_bluetitle_theme(void) +{ + set_classic_theme(); + DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); + +} + +/* + * Select color theme + */ +static int set_theme(const char *theme) +{ + int use_color = 1; + if (!theme) + set_bluetitle_theme(); + else if (strcmp(theme, "classic") == 0) + set_classic_theme(); + else if (strcmp(theme, "bluetitle") == 0) + set_bluetitle_theme(); + else if (strcmp(theme, "blackbg") == 0) + set_blackbg_theme(); + else if (strcmp(theme, "mono") == 0) + use_color = 0; + + return use_color; +} + +static void init_one_color(struct dialog_color *color) +{ + static int pair = 0; + + pair++; + init_pair(pair, color->fg, color->bg); + if (color->hl) + color->atr = A_BOLD | COLOR_PAIR(pair); + else + color->atr = COLOR_PAIR(pair); +} + +static void init_dialog_colors(void) +{ + init_one_color(&dlg.screen); + init_one_color(&dlg.shadow); + init_one_color(&dlg.dialog); + init_one_color(&dlg.title); + init_one_color(&dlg.border); + init_one_color(&dlg.button_active); + init_one_color(&dlg.button_inactive); + init_one_color(&dlg.button_key_active); + init_one_color(&dlg.button_key_inactive); + init_one_color(&dlg.button_label_active); + init_one_color(&dlg.button_label_inactive); + init_one_color(&dlg.inputbox); + init_one_color(&dlg.inputbox_border); + init_one_color(&dlg.searchbox); + init_one_color(&dlg.searchbox_title); + init_one_color(&dlg.searchbox_border); + init_one_color(&dlg.position_indicator); + init_one_color(&dlg.menubox); + init_one_color(&dlg.menubox_border); + init_one_color(&dlg.item); + init_one_color(&dlg.item_selected); + init_one_color(&dlg.tag); + init_one_color(&dlg.tag_selected); + init_one_color(&dlg.tag_key); + init_one_color(&dlg.tag_key_selected); + init_one_color(&dlg.check); + init_one_color(&dlg.check_selected); + init_one_color(&dlg.uarrow); + init_one_color(&dlg.darrow); +} + +/* + * Setup for color display + */ +static void color_setup(const char *theme) +{ + int use_color; + + use_color = set_theme(theme); + if (use_color && has_colors()) { + start_color(); + init_dialog_colors(); + } else + set_mono_theme(); +} + +/* + * Set window to attribute 'attr' + */ +void attr_clear(WINDOW * win, int height, int width, chtype attr) +{ + int i, j; + + wattrset(win, attr); + for (i = 0; i < height; i++) { + wmove(win, i, 0); + for (j = 0; j < width; j++) + waddch(win, ' '); + } + touchwin(win); +} + +void dialog_clear(void) +{ + attr_clear(stdscr, LINES, COLS, dlg.screen.atr); + /* Display background title if it exists ... - SLH */ + if (dlg.backtitle != NULL) { + int i; + + wattrset(stdscr, dlg.screen.atr); + mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); + wmove(stdscr, 1, 1); + for (i = 1; i < COLS - 1; i++) + waddch(stdscr, ACS_HLINE); + } + wnoutrefresh(stdscr); +} + +/* + * Do some initialization for dialog + */ +int init_dialog(const char *backtitle) +{ + int height, width; + + initscr(); /* Init curses */ + getmaxyx(stdscr, height, width); + if (height < 19 || width < 80) { + endwin(); + return -ERRDISPLAYTOOSMALL; + } + + dlg.backtitle = backtitle; + color_setup(getenv("MENUCONFIG_COLOR")); + + keypad(stdscr, TRUE); + cbreak(); + noecho(); + dialog_clear(); + + return 0; +} + +void set_dialog_backtitle(const char *backtitle) +{ + dlg.backtitle = backtitle; +} + +/* + * End using dialog functions. + */ +void end_dialog(int x, int y) +{ + /* move cursor back to original position */ + move(y, x); + refresh(); + endwin(); +} + +/* Print the title of the dialog. Center the title and truncate + * tile if wider than dialog (- 2 chars). + **/ +void print_title(WINDOW *dialog, const char *title, int width) +{ + if (title) { + int tlen = MIN(width - 2, strlen(title)); + wattrset(dialog, dlg.title.atr); + mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); + mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); + waddch(dialog, ' '); + } +} + +/* + * Print a string of text in a window, automatically wrap around to the + * next line if the string is too long to fit on one line. Newline + * characters '\n' are replaced by spaces. We start on a new line + * if there is no room for at least 4 nonblanks following a double-space. + */ +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) +{ + int newl, cur_x, cur_y; + int i, prompt_len, room, wlen; + char tempstr[MAX_LEN + 1], *word, *sp, *sp2; + + strcpy(tempstr, prompt); + + prompt_len = strlen(tempstr); + + /* + * Remove newlines + */ + for (i = 0; i < prompt_len; i++) { + if (tempstr[i] == '\n') + tempstr[i] = ' '; + } + + if (prompt_len <= width - x * 2) { /* If prompt is short */ + wmove(win, y, (width - prompt_len) / 2); + waddstr(win, tempstr); + } else { + cur_x = x; + cur_y = y; + newl = 1; + word = tempstr; + while (word && *word) { + sp = strchr(word, ' '); + if (sp) + *sp++ = 0; + + /* Wrap to next line if either the word does not fit, + or it is the first word of a new sentence, and it is + short, and the next word does not fit. */ + room = width - cur_x; + wlen = strlen(word); + if (wlen > room || + (newl && wlen < 4 && sp + && wlen + 1 + strlen(sp) > room + && (!(sp2 = strchr(sp, ' ')) + || wlen + 1 + (sp2 - sp) > room))) { + cur_y++; + cur_x = x; + } + wmove(win, cur_y, cur_x); + waddstr(win, word); + getyx(win, cur_y, cur_x); + cur_x++; + if (sp && *sp == ' ') { + cur_x++; /* double space */ + while (*++sp == ' ') ; + newl = 1; + } else + newl = 0; + word = sp; + } + } +} + +/* + * Print a button + */ +void print_button(WINDOW * win, const char *label, int y, int x, int selected) +{ + int i, temp; + + wmove(win, y, x); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, "<"); + temp = strspn(label, " "); + label += temp; + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + for (i = 0; i < temp; i++) + waddch(win, ' '); + wattrset(win, selected ? dlg.button_key_active.atr + : dlg.button_key_inactive.atr); + waddch(win, label[0]); + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + waddstr(win, (char *)label + 1); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, ">"); + wmove(win, y, x + temp + 1); +} + +/* + * Draw a rectangular box with line drawing characters + */ +void +draw_box(WINDOW * win, int y, int x, int height, int width, + chtype box, chtype border) +{ + int i, j; + + wattrset(win, 0); + for (i = 0; i < height; i++) { + wmove(win, y + i, x); + for (j = 0; j < width; j++) + if (!i && !j) + waddch(win, border | ACS_ULCORNER); + else if (i == height - 1 && !j) + waddch(win, border | ACS_LLCORNER); + else if (!i && j == width - 1) + waddch(win, box | ACS_URCORNER); + else if (i == height - 1 && j == width - 1) + waddch(win, box | ACS_LRCORNER); + else if (!i) + waddch(win, border | ACS_HLINE); + else if (i == height - 1) + waddch(win, box | ACS_HLINE); + else if (!j) + waddch(win, border | ACS_VLINE); + else if (j == width - 1) + waddch(win, box | ACS_VLINE); + else + waddch(win, box | ' '); + } +} + +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes + */ +void draw_shadow(WINDOW * win, int y, int x, int height, int width) +{ + int i; + + if (has_colors()) { /* Whether terminal supports color? */ + wattrset(win, dlg.shadow.atr); + wmove(win, y + height, x + 2); + for (i = 0; i < width; i++) + waddch(win, winch(win) & A_CHARTEXT); + for (i = y + 1; i < y + height + 1; i++) { + wmove(win, i, x + width); + waddch(win, winch(win) & A_CHARTEXT); + waddch(win, winch(win) & A_CHARTEXT); + } + wnoutrefresh(win); + } +} + +/* + * Return the position of the first alphabetic character in a string. + */ +int first_alpha(const char *string, const char *exempt) +{ + int i, in_paren = 0, c; + + for (i = 0; i < strlen(string); i++) { + c = tolower(string[i]); + + if (strchr("<[(", c)) + ++in_paren; + if (strchr(">])", c) && in_paren > 0) + --in_paren; + + if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) + return i; + } + + return 0; +} + +/* + * ncurses uses ESC to detect escaped char sequences. This resutl in + * a small timeout before ESC is actually delivered to the application. + * lxdialog suggest which is correctly translated to two + * times esc. But then we need to ignore the second esc to avoid stepping + * out one menu too much. Filter away all escaped key sequences since + * keypad(FALSE) turn off ncurses support for escape sequences - and thats + * needed to make notimeout() do as expected. + */ +int on_key_esc(WINDOW *win) +{ + int key; + int key2; + int key3; + + nodelay(win, TRUE); + keypad(win, FALSE); + key = wgetch(win); + key2 = wgetch(win); + do { + key3 = wgetch(win); + } while (key3 != ERR); + nodelay(win, FALSE); + keypad(win, TRUE); + if (key == KEY_ESC && key2 == ERR) + return KEY_ESC; + else if (key != ERR && key != KEY_ESC && key2 == ERR) + ungetch(key); + + return -1; +} + +/* redraw screen in new size */ +int on_key_resize(void) +{ + dialog_clear(); + return KEY_RESIZE; +} + +struct dialog_list *item_cur; +struct dialog_list item_nil; +struct dialog_list *item_head; + +void item_reset(void) +{ + struct dialog_list *p, *next; + + for (p = item_head; p; p = next) { + next = p->next; + free(p); + } + item_head = NULL; + item_cur = &item_nil; +} + +void item_make(const char *fmt, ...) +{ + va_list ap; + struct dialog_list *p = malloc(sizeof(*p)); + + if (item_head) + item_cur->next = p; + else + item_head = p; + item_cur = p; + memset(p, 0, sizeof(*p)); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); + va_end(ap); +} + +void item_add_str(const char *fmt, ...) +{ + va_list ap; + size_t avail; + + avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str + strlen(item_cur->node.str), + avail, fmt, ap); + item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; + va_end(ap); +} + +void item_set_tag(char tag) +{ + item_cur->node.tag = tag; +} +void item_set_data(void *ptr) +{ + item_cur->node.data = ptr; +} + +void item_set_selected(int val) +{ + item_cur->node.selected = val; +} + +int item_activate_selected(void) +{ + item_foreach() + if (item_is_selected()) + return 1; + return 0; +} + +void *item_data(void) +{ + return item_cur->node.data; +} + +char item_tag(void) +{ + return item_cur->node.tag; +} + +int item_count(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) + n++; + return n; +} + +void item_set(int n) +{ + int i = 0; + item_foreach() + if (i++ == n) + return; +} + +int item_n(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) { + if (p == item_cur) + return n; + n++; + } + return 0; +} + +const char *item_str(void) +{ + return item_cur->node.str; +} + +int item_is_selected(void) +{ + return (item_cur->node.selected != 0); +} + +int item_is_tag(char tag) +{ + return (item_cur->node.tag == tag); +} diff --git a/config/lxdialog/yesno.c b/config/lxdialog/yesno.c new file mode 100644 index 000000000..4e6e8090c --- /dev/null +++ b/config/lxdialog/yesno.c @@ -0,0 +1,114 @@ +/* + * yesno.c -- implements the yes/no box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +/* + * Display termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 10; + int y = height - 2; + + print_button(dialog, gettext(" Yes "), y, x, selected == 0); + print_button(dialog, gettext(" No "), y, x + 13, selected == 1); + + wmove(dialog, y, x + 1 + 13 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with two buttons - Yes and No + */ +int dialog_yesno(const char *title, const char *prompt, int height, int width) +{ + int i, x, y, key = 0, button = 0; + WINDOW *dialog; + +do_resize: + if (getmaxy(stdscr) < (height + 4)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + 4)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + print_buttons(dialog, height, width, 0); + + while (key != KEY_ESC) { + key = wgetch(dialog); + switch (key) { + case 'Y': + case 'y': + delwin(dialog); + return 0; + case 'N': + case 'n': + delwin(dialog); + return 1; + + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + return button; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/config/mconf.c b/config/mconf.c new file mode 100644 index 000000000..25b60bc11 --- /dev/null +++ b/config/mconf.c @@ -0,0 +1,938 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis + * + * i18n, 2005, Arnaldo Carvalho de Melo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "lxdialog/dialog.h" + +static const char mconf_readme[] = N_( +"Overview\n" +"--------\n" +"Some kernel features may be built directly into the kernel.\n" +"Some may be made into loadable runtime modules. Some features\n" +"may be completely removed altogether. There are also certain\n" +"kernel parameters which are not really features, but must be\n" +"entered in as decimal or hexadecimal numbers or possibly text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to removed it. You may also press the to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +" you wish to change or submenu wish to select and press .\n" +" Submenus are designated by \"--->\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, use the or cursor keys to highlight the help option\n" +" and press . You can try as well.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do and for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"Menuconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different kernel configurations.\n" +"\n" +"At the end of the main menu you will find two options. One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a Menuconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting Menuconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use Menuconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"Menuconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the kernel options listed in a single\n" +"menu, rather than the default multimenu hierarchy, run the menuconfig\n" +"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make MENUCONFIG_MODE=single_menu menuconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n" +"Different color themes available\n" +"--------------------------------\n" +"It is possible to select different color themes using the variable\n" +"MENUCONFIG_COLOR. To select a theme use:\n" +"\n" +"make MENUCONFIG_COLOR= menuconfig\n" +"\n" +"Available themes are\n" +" mono => selects colors suitable for monochrome displays\n" +" blackbg => selects a color scheme with black background\n" +" classic => theme with blue background. The classic look\n" +" bluetitle => a LCD friendly version of classic. (default)\n" +"\n"), +menu_instructions[] = N_( + "Arrow keys navigate the menu. " + " selects submenus --->. " + "Highlighted letters are hotkeys. " + "Pressing includes, excludes, modularizes features. " + "Press to exit, for Help, for Search. " + "Legend: [*] built-in [ ] excluded module < > module capable"), +radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " + "followed by the . " + "Press for additional information about this option."), +inputbox_instructions_int[] = N_( + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( + "Please enter a string value. " + "Use the key to move from the input field to the buttons below it."), +setmod_text[] = N_( + "This feature depends on another which has been configured as a module.\n" + "As a result, this feature will be built as a module."), +nohelp_text[] = N_( + "There is no help available for this kernel option.\n"), +load_config_text[] = N_( + "Enter the name of the configuration file you wish to load. " + "Accept the name shown to restore the configuration you " + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep several different kernel\n" + "configurations available on a single machine.\n" + "\n" + "If you have saved a previous configuration in a file other than the\n" + "kernel's default, entering the name of the file here will allow you\n" + "to modify that configuration.\n" + "\n" + "If you are uncertain, then you have probably never used alternate\n" + "configuration files. You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( + "Enter a filename to which this configuration should be saved " + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep different kernel\n" + "configurations available on a single machine.\n" + "\n" + "Entering a file name here will allow you to later retrieve, modify\n" + "and use the current configuration as an alternate to whatever\n" + "configuration options you have selected at that time.\n" + "\n" + "If you are uncertain what all this means then you should probably\n" + "leave this blank.\n"), +search_help[] = N_( + "\n" + "Search for CONFIG_ symbols and display their relations.\n" + "Regular expressions are allowed.\n" + "Example: search for \"^FOO\"\n" + "Result:\n" + "-----------------------------------------------------------------\n" + "Symbol: FOO [=m]\n" + "Prompt: Foo bus is used to drive the bar HW\n" + "Defined at drivers/pci/Kconfig:47\n" + "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + "Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" + " -> PCI support (PCI [=y])\n" + " -> PCI access mode ( [=y])\n" + "Selects: LIBCRC32\n" + "Selected by: BAR\n" + "-----------------------------------------------------------------\n" + "o The line 'Prompt:' shows the text used in the menu structure for\n" + " this CONFIG_ symbol\n" + "o The 'Defined at' line tell at what file / line number the symbol\n" + " is defined\n" + "o The 'Depends on:' line tell what symbols needs to be defined for\n" + " this symbol to be visible in the menu (selectable)\n" + "o The 'Location:' lines tell where in the menu structure this symbol\n" + " is located\n" + " A location followed by a [=y] indicate that this is a selectable\n" + " menu item - and current value is displayed inside brackets.\n" + "o The 'Selects:' line tell what symbol will be automatically\n" + " selected if this symbol is selected (y or m)\n" + "o The 'Selected by' line tell what symbol has selected this symbol\n" + "\n" + "Only relevant lines are shown.\n" + "\n\n" + "Search examples:\n" + "Examples: USB => find all CONFIG_ symbols containing USB\n" + " ^USB => find all CONFIG_ symbols starting with USB\n" + " USB$ => find all CONFIG_ symbols ending with USB\n" + "\n"); + +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_textbox(const char *title, const char *text, int r, int c); +static void show_helptext(const char *title, const char *text); +static void show_help(struct menu *menu); + +static void get_prompt_str(struct gstr *r, struct property *prop) +{ + int i, j; + struct menu *submenu[8], *menu; + + str_printf(r, _("Prompt: %s\n"), _(prop->text)); + str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, + prop->menu->lineno); + if (!expr_is_yes(prop->visible.expr)) { + str_append(r, _(" Depends on: ")); + expr_gstr_print(prop->visible.expr, r); + str_append(r, "\n"); + } + menu = prop->menu->parent; + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) + submenu[i++] = menu; + if (i > 0) { + str_printf(r, _(" Location:\n")); + for (j = 4; --i >= 0; j += 2) { + menu = submenu[i]; + str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); + if (menu->sym) { + str_printf(r, " (%s [=%s])", menu->sym->name ? + menu->sym->name : _(""), + sym_get_string_value(menu->sym)); + } + str_append(r, "\n"); + } + } +} + +static void get_symbol_str(struct gstr *r, struct symbol *sym) +{ + bool hit; + struct property *prop; + + if (sym && sym->name) + str_printf(r, "Symbol: %s [=%s]\n", sym->name, + sym_get_string_value(sym)); + for_all_prompts(sym, prop) + get_prompt_str(r, prop); + hit = false; + for_all_properties(sym, prop, P_SELECT) { + if (!hit) { + str_append(r, " Selects: "); + hit = true; + } else + str_printf(r, " && "); + expr_gstr_print(prop->expr, r); + } + if (hit) + str_append(r, "\n"); + if (sym->rev_dep.expr) { + str_append(r, _(" Selected by: ")); + expr_gstr_print(sym->rev_dep.expr, r); + str_append(r, "\n"); + } + str_append(r, "\n\n"); +} + +static struct gstr get_relations_str(struct symbol **sym_arr) +{ + struct symbol *sym; + struct gstr res = str_new(); + int i; + + for (i = 0; sym_arr && (sym = sym_arr[i]); i++) + get_symbol_str(&res, sym); + if (!i) + str_append(&res, _("No matches found.\n")); + return res; +} + +static char filename[PATH_MAX+1]; +static void set_config_filename(const char *config_filename) +{ + static char menu_backtitle[PATH_MAX+128]; + int size; + struct symbol *sym; + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + _("%s - Linux Kernel v%s Configuration"), + config_filename, sym_get_string_value(sym)); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + set_dialog_backtitle(menu_backtitle); + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + char *dialog_input; + int dres; +again: + dialog_clear(); + dres = dialog_inputbox(_("Search Configuration Parameter"), + _("Enter CONFIG_ (sub)string to search for " + "(with or without \"CONFIG\")"), + 10, 75, ""); + switch (dres) { + case 0: + break; + case 1: + show_helptext(_("Search Configuration"), search_help); + goto again; + default: + return; + } + + /* strip CONFIG_ if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0) + dialog_input += 7; + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr); + free(sym_arr); + show_textbox(_("Search Results"), str_get(&res), 0, 0); + str_free(&res); +} + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + switch (prop->type) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(" %*c%s --->", indent + 1, ' ', prompt); + + item_set_tag('m'); + item_set_data(menu); + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + break; + default: + if (prompt) { + child_count++; + item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make("[%c]", val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + item_make("<%c>", ch); + break; + } + item_set_tag('t'); + item_set_data(menu); + } else { + item_make(" "); + item_set_tag(def_menu ? 't' : ':'); + item_set_data(menu); + } + + item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_set_tag(':'); + item_set_data(menu); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(" "); + item_set_tag(':'); + item_set_data(menu); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); + item_set_data(menu); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt->type == P_MENU) { + item_add_str(" --->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void conf(struct menu *menu) +{ + struct menu *submenu; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + struct menu *active_menu = NULL; + int res; + int s_scroll = 0; + + while (1) { + item_reset(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + if (menu == &rootmenu) { + item_make("--- "); + item_set_tag(':'); + item_make(_(" Load an Alternate Configuration File")); + item_set_tag('L'); + item_make(_(" Save an Alternate Configuration File")); + item_set_tag('S'); + } + dialog_clear(); + res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + active_menu, &s_scroll); + if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) + break; + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + + submenu = item_data(); + active_menu = item_data(); + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case 0: + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt->type == P_MENU) + conf(submenu); + break; + case 's': + conf_string(submenu); + break; + case 'L': + conf_load(); + break; + case 'S': + conf_save(); + break; + } + break; + case 2: + if (sym) + show_help(submenu); + else + show_helptext(_("README"), _(mconf_readme)); + break; + case 3: + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + show_textbox(NULL, setmod_text, 6, 74); + } + break; + case 4: + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 5: + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case 6: + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case 7: + search_conf(); + break; + } + } +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + dialog_clear(); + dialog_textbox(title, text, r, c); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + struct symbol *sym = menu->sym; + + if (menu_has_help(menu)) + { + if (sym->name) { + str_printf(&help, "CONFIG_%s:\n\n", sym->name); + str_append(&help, _(menu_get_help(menu))); + str_append(&help, "\n"); + } + } else { + str_append(&help, nohelp_text); + } + get_symbol_str(&help, sym); + show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child; + struct symbol *active; + + active = sym_get_choice_value(menu->sym); + while (1) { + int res; + int selected; + item_reset(); + + current_menu = menu; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } + item_set_data(child); + if (child->sym == active) + item_set_selected(1); + if (child->sym == sym_get_choice_value(menu->sym)) + item_set_tag('X'); + } + dialog_clear(); + res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), + _(radiolist_instructions), + 15, 70, 6); + selected = item_activate_selected(); + switch (res) { + case 0: + if (selected) { + child = item_data(); + if (!child->sym) + break; + + sym_set_tristate_value(child->sym, yes); + } + return; + case 1: + if (selected) { + child = item_data(); + show_help(child); + active = child->sym; + } else + show_help(menu); + break; + case KEY_ESC: + return; + case -ERRDISPLAYTOOSMALL: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal mconf error!"); + } + dialog_clear(); + res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + heading, 10, 75, + sym_get_string_value(menu->sym)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, dialog_input_result)) + return; + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + break; + case 1: + show_help(menu); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_load(void) +{ + + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, load_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + show_textbox(NULL, _("File does not exist!"), 5, 38); + break; + case 1: + show_helptext(_("Load Alternate Configuration"), load_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, save_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_write(dialog_input_result)) { + set_config_filename(dialog_input_result); + return; + } + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + break; + case 1: + show_helptext(_("Save Alternate Configuration"), save_config_help); + break; + case KEY_ESC: + return; + } + } +} + +int main(int ac, char **av) +{ + int saved_x, saved_y; + char *mode; + int res; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + initscr(); + + getyx(stdscr, saved_y, saved_x); + if (init_dialog(NULL)) { + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + return 1; + } + + set_config_filename(conf_get_configname()); + do { + conf(&rootmenu); + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your " + "new kernel configuration?\n" + " to continue."), + 6, 60); + else + res = -1; + } while (res == KEY_ESC); + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error during writing of the kernel configuration.\n" + "Your kernel configuration changes were NOT saved." + "\n\n")); + return 1; + } + case -1: + printf(_("\n\n" + "*** End of Linux kernel configuration.\n" + "*** Execute 'make' to build the kernel or try 'make help'." + "\n\n")); + break; + default: + fprintf(stderr, _("\n\n" + "Your kernel configuration changes were NOT saved." + "\n\n")); + } + + return 0; +} + diff --git a/config/menu.c b/config/menu.c new file mode 100644 index 000000000..07ff8d105 --- /dev/null +++ b/config/menu.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +struct menu rootmenu; +static struct menu **last_entry_ptr; + +struct file *file_list; +struct file *current_file; + +void menu_warn(struct menu *menu, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +static void prop_warn(struct property *prop, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void menu_init(void) +{ + current_entry = current_menu = &rootmenu; + last_entry_ptr = &rootmenu.list; +} + +void menu_add_entry(struct symbol *sym) +{ + struct menu *menu; + + menu = malloc(sizeof(*menu)); + memset(menu, 0, sizeof(*menu)); + menu->sym = sym; + menu->parent = current_menu; + menu->file = current_file; + menu->lineno = zconf_lineno(); + + *last_entry_ptr = menu; + last_entry_ptr = &menu->next; + current_entry = menu; +} + +void menu_end_entry(void) +{ +} + +struct menu *menu_add_menu(void) +{ + menu_end_entry(); + last_entry_ptr = ¤t_entry->list; + return current_menu = current_entry; +} + +void menu_end_menu(void) +{ + last_entry_ptr = ¤t_menu->next; + current_menu = current_menu->parent; +} + +struct expr *menu_check_dep(struct expr *e) +{ + if (!e) + return e; + + switch (e->type) { + case E_NOT: + e->left.expr = menu_check_dep(e->left.expr); + break; + case E_OR: + case E_AND: + e->left.expr = menu_check_dep(e->left.expr); + e->right.expr = menu_check_dep(e->right.expr); + break; + case E_SYMBOL: + /* change 'm' into 'm' && MODULES */ + if (e->left.sym == &symbol_mod) + return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); + break; + default: + break; + } + return e; +} + +void menu_add_dep(struct expr *dep) +{ + current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); +} + +void menu_set_type(int type) +{ + struct symbol *sym = current_entry->sym; + + if (sym->type == type) + return; + if (sym->type == S_UNKNOWN) { + sym->type = type; + return; + } + menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'", + sym->name ? sym->name : "", + sym_type_name(sym->type), sym_type_name(type)); +} + +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +{ + struct property *prop = prop_alloc(type, current_entry->sym); + + prop->menu = current_entry; + prop->expr = expr; + prop->visible.expr = menu_check_dep(dep); + + if (prompt) { + if (isspace(*prompt)) { + prop_warn(prop, "leading whitespace ignored"); + while (isspace(*prompt)) + prompt++; + } + if (current_entry->prompt) + prop_warn(prop, "prompt redefined"); + current_entry->prompt = prop; + } + prop->text = prompt; + + return prop; +} + +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) +{ + return menu_add_prop(type, prompt, NULL, dep); +} + +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) +{ + menu_add_prop(type, NULL, expr, dep); +} + +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) +{ + menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); +} + +void menu_add_option(int token, char *arg) +{ + struct property *prop; + + switch (token) { + case T_OPT_MODULES: + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(current_entry->sym); + break; + case T_OPT_DEFCONFIG_LIST: + if (!sym_defconfig_list) + sym_defconfig_list = current_entry->sym; + else if (sym_defconfig_list != current_entry->sym) + zconf_error("trying to redefine defconfig symbol"); + break; + case T_OPT_ENV: + prop_add_env(arg); + break; + } +} + +static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2) +{ + return sym2->type == S_INT || sym2->type == S_HEX || + (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); +} + +void sym_check_prop(struct symbol *sym) +{ + struct property *prop; + struct symbol *sym2; + for (prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_DEFAULT: + if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && + prop->expr->type != E_SYMBOL) + prop_warn(prop, + "default for config symbol '%'" + " must be a single symbol", sym->name); + break; + case P_SELECT: + sym2 = prop_get_symbol(prop); + if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) + prop_warn(prop, + "config symbol '%s' uses select, but is " + "not boolean or tristate", sym->name); + else if (sym2->type != S_UNKNOWN && + sym2->type != S_BOOLEAN && + sym2->type != S_TRISTATE) + prop_warn(prop, + "'%s' has wrong type. 'select' only " + "accept arguments of boolean and " + "tristate type", sym2->name); + break; + case P_RANGE: + if (sym->type != S_INT && sym->type != S_HEX) + prop_warn(prop, "range is only allowed " + "for int or hex symbols"); + if (!menu_range_valid_sym(sym, prop->expr->left.sym) || + !menu_range_valid_sym(sym, prop->expr->right.sym)) + prop_warn(prop, "range is invalid"); + break; + default: + ; + } + } +} + +void menu_finalize(struct menu *parent) +{ + struct menu *menu, *last_menu; + struct symbol *sym; + struct property *prop; + struct expr *parentdep, *basedep, *dep, *dep2, **ep; + + sym = parent->sym; + if (parent->list) { + if (sym && sym_is_choice(sym)) { + if (sym->type == S_UNKNOWN) { + /* find the first choice value to find out choice type */ + current_entry = parent; + for (menu = parent->list; menu; menu = menu->next) { + if (menu->sym && menu->sym->type != S_UNKNOWN) { + menu_set_type(menu->sym->type); + break; + } + } + } + /* set the type of the remaining choice values */ + for (menu = parent->list; menu; menu = menu->next) { + current_entry = menu; + if (menu->sym && menu->sym->type == S_UNKNOWN) + menu_set_type(sym->type); + } + parentdep = expr_alloc_symbol(sym); + } else if (parent->prompt) + parentdep = parent->prompt->visible.expr; + else + parentdep = parent->dep; + + for (menu = parent->list; menu; menu = menu->next) { + basedep = expr_transform(menu->dep); + basedep = expr_alloc_and(expr_copy(parentdep), basedep); + basedep = expr_eliminate_dups(basedep); + menu->dep = basedep; + if (menu->sym) + prop = menu->sym->prop; + else + prop = menu->prompt; + for (; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + dep = expr_transform(prop->visible.expr); + dep = expr_alloc_and(expr_copy(basedep), dep); + dep = expr_eliminate_dups(dep); + if (menu->sym && menu->sym->type != S_TRISTATE) + dep = expr_trans_bool(dep); + prop->visible.expr = dep; + if (prop->type == P_SELECT) { + struct symbol *es = prop_get_symbol(prop); + es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, + expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + } + } + } + for (menu = parent->list; menu; menu = menu->next) + menu_finalize(menu); + } else if (sym) { + basedep = parent->prompt ? parent->prompt->visible.expr : NULL; + basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); + basedep = expr_eliminate_dups(expr_transform(basedep)); + last_menu = NULL; + for (menu = parent->next; menu; menu = menu->next) { + dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; + if (!expr_contains_symbol(dep, sym)) + break; + if (expr_depends_symbol(dep, sym)) + goto next; + dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); + dep = expr_eliminate_dups(expr_transform(dep)); + dep2 = expr_copy(basedep); + expr_eliminate_eq(&dep, &dep2); + expr_free(dep); + if (!expr_is_yes(dep2)) { + expr_free(dep2); + break; + } + expr_free(dep2); + next: + menu_finalize(menu); + menu->parent = parent; + last_menu = menu; + } + if (last_menu) { + parent->list = parent->next; + parent->next = last_menu->next; + last_menu->next = NULL; + } + } + for (menu = parent->list; menu; menu = menu->next) { + if (sym && sym_is_choice(sym) && + menu->sym && !sym_is_choice_value(menu->sym)) { + current_entry = menu; + menu->sym->flags |= SYMBOL_CHOICEVAL; + if (!menu->prompt) + menu_warn(menu, "choice value must have a prompt"); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->type == P_DEFAULT) + prop_warn(prop, "defaults for choice " + "values not supported"); + if (prop->menu == menu) + continue; + if (prop->type == P_PROMPT && + prop->menu->parent->sym != sym) + prop_warn(prop, "choice value used outside its choice group"); + } + /* Non-tristate choice values of tristate choices must + * depend on the choice being set to Y. The choice + * values' dependencies were propagated to their + * properties above, so the change here must be re- + * propagated. + */ + if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { + basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); + menu->dep = expr_alloc_and(basedep, menu->dep); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + prop->visible.expr = expr_alloc_and(expr_copy(basedep), + prop->visible.expr); + } + } + menu_add_symbol(P_CHOICE, sym, NULL); + prop = sym_get_choice_prop(sym); + for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) + ; + *ep = expr_alloc_one(E_LIST, NULL); + (*ep)->right.sym = menu->sym; + } + if (menu->list && (!menu->prompt || !menu->prompt->text)) { + for (last_menu = menu->list; ; last_menu = last_menu->next) { + last_menu->parent = parent; + if (!last_menu->next) + break; + } + last_menu->next = menu->next; + menu->next = menu->list; + menu->list = NULL; + } + } + + if (sym && !(sym->flags & SYMBOL_WARNED)) { + if (sym->type == S_UNKNOWN) + menu_warn(parent, "config symbol defined without type"); + + if (sym_is_choice(sym) && !parent->prompt) + menu_warn(parent, "choice must have a prompt"); + + /* Check properties connected to this symbol */ + sym_check_prop(sym); + sym->flags |= SYMBOL_WARNED; + } + + if (sym && !sym_is_optional(sym) && parent->prompt) { + sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, + expr_alloc_and(parent->prompt->visible.expr, + expr_alloc_symbol(&symbol_mod))); + } +} + +bool menu_is_visible(struct menu *menu) +{ + struct menu *child; + struct symbol *sym; + tristate visible; + + if (!menu->prompt) + return false; + sym = menu->sym; + if (sym) { + sym_calc_value(sym); + visible = menu->prompt->visible.tri; + } else + visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); + + if (visible != no) + return true; + if (!sym || sym_get_tristate_value(menu->sym) == no) + return false; + + for (child = menu->list; child; child = child->next) + if (menu_is_visible(child)) + return true; + return false; +} + +const char *menu_get_prompt(struct menu *menu) +{ + if (menu->prompt) + return menu->prompt->text; + else if (menu->sym) + return menu->sym->name; + return NULL; +} + +struct menu *menu_get_root_menu(struct menu *menu) +{ + return &rootmenu; +} + +struct menu *menu_get_parent_menu(struct menu *menu) +{ + enum prop_type type; + + for (; menu != &rootmenu; menu = menu->parent) { + type = menu->prompt ? menu->prompt->type : 0; + if (type == P_MENU) + break; + } + return menu; +} + +bool menu_has_help(struct menu *menu) +{ + return menu->help != NULL; +} + +const char *menu_get_help(struct menu *menu) +{ + if (menu->help) + return menu->help; + else + return ""; +} diff --git a/config/qconf.cc b/config/qconf.cc new file mode 100644 index 000000000..ce7d508c7 --- /dev/null +++ b/config/qconf.cc @@ -0,0 +1,1765 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lkc.h" +#include "qconf.h" + +#include "qconf.moc" +#include "images.c" + +#ifdef _ +# undef _ +# define _ qgettext +#endif + +static QApplication *configApp; +static ConfigSettings *configSettings; + +QAction *ConfigMainWindow::saveAction; + +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + +/** + * Reads a list of integer values from the application settings. + */ +QValueList ConfigSettings::readSizes(const QString& key, bool *ok) +{ + QValueList result; + QStringList entryList = readListEntry(key, ok); + if (ok) { + QStringList::Iterator it; + for (it = entryList.begin(); it != entryList.end(); ++it) + result.push_back((*it).toInt()); + } + + return result; +} + +/** + * Writes a list of integer values to the application settings. + */ +bool ConfigSettings::writeSizes(const QString& key, const QValueList& value) +{ + QStringList stringList; + QValueList::ConstIterator it; + + for (it = value.begin(); it != value.end(); ++it) + stringList.push_back(QString::number(*it)); + return writeEntry(key, stringList); +} + + +#if QT_VERSION >= 300 +/* + * set the new data + * TODO check the value + */ +void ConfigItem::okRename(int col) +{ + Parent::okRename(col); + sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); +} +#endif + +/* + * update the displayed of a menu entry + */ +void ConfigItem::updateMenu(void) +{ + ConfigList* list; + struct symbol* sym; + struct property *prop; + QString prompt; + int type; + tristate expr; + + list = listView(); + if (goParent) { + setPixmap(promptColIdx, list->menuBackPix); + prompt = ".."; + goto set_prompt; + } + + sym = menu->sym; + prop = menu->prompt; + prompt = _(menu_get_prompt(menu)); + + if (prop) switch (prop->type) { + case P_MENU: + if (list->mode == singleMode || list->mode == symbolMode) { + /* a menuconfig entry is displayed differently + * depending whether it's at the view root or a child. + */ + if (sym && list->rootEntry == menu) + break; + setPixmap(promptColIdx, list->menuPix); + } else { + if (sym) + break; + setPixmap(promptColIdx, 0); + } + goto set_prompt; + case P_COMMENT: + setPixmap(promptColIdx, 0); + goto set_prompt; + default: + ; + } + if (!sym) + goto set_prompt; + + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + char ch; + + if (!sym_is_changable(sym) && !list->showAll) { + setPixmap(promptColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); + break; + } + expr = sym_get_tristate_value(sym); + switch (expr) { + case yes: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceYesPix); + else + setPixmap(promptColIdx, list->symbolYesPix); + setText(yesColIdx, "Y"); + ch = 'Y'; + break; + case mod: + setPixmap(promptColIdx, list->symbolModPix); + setText(modColIdx, "M"); + ch = 'M'; + break; + default: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceNoPix); + else + setPixmap(promptColIdx, list->symbolNoPix); + setText(noColIdx, "N"); + ch = 'N'; + break; + } + if (expr != no) + setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); + if (expr != mod) + setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); + if (expr != yes) + setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); + + setText(dataColIdx, QChar(ch)); + break; + case S_INT: + case S_HEX: + case S_STRING: + const char* data; + + data = sym_get_string_value(sym); + +#if QT_VERSION >= 300 + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); +#endif + setText(dataColIdx, data); + if (type == S_STRING) + prompt = QString("%1: %2").arg(prompt).arg(data); + else + prompt = QString("(%2) %1").arg(prompt).arg(data); + break; + } + if (!sym_has_value(sym) && visible) + prompt += _(" (NEW)"); +set_prompt: + setText(promptColIdx, prompt); +} + +void ConfigItem::testUpdateMenu(bool v) +{ + ConfigItem* i; + + visible = v; + if (!menu) + return; + + sym_calc_value(menu->sym); + if (menu->flags & MENU_CHANGED) { + /* the menu entry changed, so update all list items */ + menu->flags &= ~MENU_CHANGED; + for (i = (ConfigItem*)menu->data; i; i = i->nextItem) + i->updateMenu(); + } else if (listView()->updateAll) + updateMenu(); +} + +void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) +{ + ConfigList* list = listView(); + + if (visible) { + if (isSelected() && !list->hasFocus() && list->mode == menuMode) + Parent::paintCell(p, list->inactivedColorGroup, column, width, align); + else + Parent::paintCell(p, cg, column, width, align); + } else + Parent::paintCell(p, list->disabledColorGroup, column, width, align); +} + +/* + * construct a menu entry + */ +void ConfigItem::init(void) +{ + if (menu) { + ConfigList* list = listView(); + nextItem = (ConfigItem*)menu->data; + menu->data = this; + + if (list->mode != fullMode) + setOpen(TRUE); + sym_calc_value(menu->sym); + } + updateMenu(); +} + +/* + * destruct a menu entry + */ +ConfigItem::~ConfigItem(void) +{ + if (menu) { + ConfigItem** ip = (ConfigItem**)&menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } + } +} + +ConfigLineEdit::ConfigLineEdit(ConfigView* parent) + : Parent(parent) +{ + connect(this, SIGNAL(lostFocus()), SLOT(hide())); +} + +void ConfigLineEdit::show(ConfigItem* i) +{ + item = i; + if (sym_get_string_value(item->menu->sym)) + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); + else + setText(QString::null); + Parent::show(); + setFocus(); +} + +void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + break; + case Qt::Key_Return: + case Qt::Key_Enter: + sym_set_string_value(item->menu->sym, text().latin1()); + parent()->updateList(item); + break; + default: + Parent::keyPressEvent(e); + return; + } + e->accept(); + parent()->list->setFocus(); + hide(); +} + +ConfigList::ConfigList(ConfigView* p, const char *name) + : Parent(p, name), + updateAll(false), + symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), + choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), + showAll(false), showName(false), showRange(false), showData(false), + rootEntry(0), headerPopup(0) +{ + int i; + + setSorting(-1); + setRootIsDecorated(TRUE); + disabledColorGroup = palette().active(); + disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); + inactivedColorGroup = palette().active(); + inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); + + connect(this, SIGNAL(selectionChanged(void)), + SLOT(updateSelection(void))); + + if (name) { + configSettings->beginGroup(name); + showAll = configSettings->readBoolEntry("/showAll", false); + showName = configSettings->readBoolEntry("/showName", false); + showRange = configSettings->readBoolEntry("/showRange", false); + showData = configSettings->readBoolEntry("/showData", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } + + for (i = 0; i < colNr; i++) + colMap[i] = colRevMap[i] = -1; + addColumn(promptColIdx, _("Option")); + + reinit(); +} + +void ConfigList::reinit(void) +{ + removeColumn(dataColIdx); + removeColumn(yesColIdx); + removeColumn(modColIdx); + removeColumn(noColIdx); + removeColumn(nameColIdx); + + if (showName) + addColumn(nameColIdx, _("Name")); + if (showRange) { + addColumn(noColIdx, "N"); + addColumn(modColIdx, "M"); + addColumn(yesColIdx, "Y"); + } + if (showData) + addColumn(dataColIdx, _("Value")); + + updateListAll(); +} + +void ConfigList::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showName", showName); + configSettings->writeEntry("/showRange", showRange); + configSettings->writeEntry("/showData", showData); + configSettings->writeEntry("/showAll", showAll); + configSettings->endGroup(); + } +} + +ConfigItem* ConfigList::findConfigItem(struct menu *menu) +{ + ConfigItem* item = (ConfigItem*)menu->data; + + for (; item; item = item->nextItem) { + if (this == item->listView()) + break; + } + + return item; +} + +void ConfigList::updateSelection(void) +{ + struct menu *menu; + enum prop_type type; + + ConfigItem* item = (ConfigItem*)selectedItem(); + if (!item) + return; + + menu = item->menu; + emit menuChanged(menu); + if (!menu) + return; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (mode == menuMode && type == P_MENU) + emit menuSelected(menu); +} + +void ConfigList::updateList(ConfigItem* item) +{ + ConfigItem* last = 0; + + if (!rootEntry) { + if (mode != listMode) + goto update; + QListViewItemIterator it(this); + ConfigItem* item; + + for (; it.current(); ++it) { + item = (ConfigItem*)it.current(); + if (!item->menu) + continue; + item->testUpdateMenu(menu_is_visible(item->menu)); + } + return; + } + + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { + item = firstChild(); + if (!item) + item = new ConfigItem(this, 0, true); + last = item; + } + if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && + rootEntry->sym && rootEntry->prompt) { + item = last ? last->nextSibling() : firstChild(); + if (!item) + item = new ConfigItem(this, last, rootEntry, true); + else + item->testUpdateMenu(true); + + updateMenuList(item, rootEntry); + triggerUpdate(); + return; + } +update: + updateMenuList(this, rootEntry); + triggerUpdate(); +} + +void ConfigList::setValue(ConfigItem* item, tristate val) +{ + struct symbol* sym; + int type; + tristate oldval; + + sym = item->menu ? item->menu->sym : 0; + if (!sym) + return; + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + + if (!sym_set_tristate_value(sym, val)) + return; + if (oldval == no && item->menu->list) + item->setOpen(TRUE); + parent()->updateList(item); + break; + } +} + +void ConfigList::changeValue(ConfigItem* item) +{ + struct symbol* sym; + struct menu* menu; + int type, oldexpr, newexpr; + + menu = item->menu; + if (!menu) + return; + sym = menu->sym; + if (!sym) { + if (item->menu->list) + item->setOpen(!item->isOpen()); + return; + } + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldexpr = sym_get_tristate_value(sym); + newexpr = sym_toggle_tristate_value(sym); + if (item->menu->list) { + if (oldexpr == newexpr) + item->setOpen(!item->isOpen()); + else if (oldexpr == no) + item->setOpen(TRUE); + } + if (oldexpr != newexpr) + parent()->updateList(item); + break; + case S_INT: + case S_HEX: + case S_STRING: +#if QT_VERSION >= 300 + if (colMap[dataColIdx] >= 0) + item->startRename(colMap[dataColIdx]); + else +#endif + parent()->lineEdit->show(item); + break; + } +} + +void ConfigList::setRootMenu(struct menu *menu) +{ + enum prop_type type; + + if (rootEntry == menu) + return; + type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type != P_MENU) + return; + updateMenuList(this, 0); + rootEntry = menu; + updateListAll(); + setSelected(currentItem(), hasFocus()); + ensureItemVisible(currentItem()); +} + +void ConfigList::setParentMenu(void) +{ + ConfigItem* item; + struct menu *oldroot; + + oldroot = rootEntry; + if (rootEntry == &rootmenu) + return; + setRootMenu(menu_get_parent_menu(rootEntry->parent)); + + QListViewItemIterator it(this); + for (; (item = (ConfigItem*)it.current()); it++) { + if (item->menu == oldroot) { + setCurrentItem(item); + ensureItemVisible(item); + break; + } + } +} + +/* + * update all the children of a menu entry + * removes/adds the entries from the parent widget as necessary + * + * parent: either the menu list widget or a menu entry widget + * menu: entry to be updated + */ +template +void ConfigList::updateMenuList(P* parent, struct menu* menu) +{ + struct menu* child; + ConfigItem* item; + ConfigItem* last; + bool visible; + enum prop_type type; + + if (!menu) { + while ((item = parent->firstChild())) + delete item; + return; + } + + last = parent->firstChild(); + if (last && !last->goParent) + last = 0; + for (child = menu->list; child; child = child->next) { + item = last ? last->nextSibling() : parent->firstChild(); + type = child->prompt ? child->prompt->type : P_UNKNOWN; + + switch (mode) { + case menuMode: + if (!(child->flags & MENU_ROOT)) + goto hide; + break; + case symbolMode: + if (child->flags & MENU_ROOT) + goto hide; + break; + default: + break; + } + + visible = menu_is_visible(child); + if (showAll || visible) { + if (!child->sym && !child->list && !child->prompt) + continue; + if (!item || item->menu != child) + item = new ConfigItem(parent, last, child, visible); + else + item->testUpdateMenu(visible); + + if (mode == fullMode || mode == menuMode || type != P_MENU) + updateMenuList(item, child); + else + updateMenuList(item, 0); + last = item; + continue; + } + hide: + if (item && item->menu == child) { + last = parent->firstChild(); + if (last == item) + last = 0; + else while (last->nextSibling() != item) + last = last->nextSibling(); + delete item; + } + } +} + +void ConfigList::keyPressEvent(QKeyEvent* ev) +{ + QListViewItem* i = currentItem(); + ConfigItem* item; + struct menu *menu; + enum prop_type type; + + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + emit parentSelected(); + ev->accept(); + return; + } + + if (!i) { + Parent::keyPressEvent(ev); + return; + } + item = (ConfigItem*)i; + + switch (ev->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + if (item->goParent) { + emit parentSelected(); + break; + } + menu = item->menu; + if (!menu) + break; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { + emit menuSelected(menu); + break; + } + case Qt::Key_Space: + changeValue(item); + break; + case Qt::Key_N: + setValue(item, no); + break; + case Qt::Key_M: + setValue(item, mod); + break; + case Qt::Key_Y: + setValue(item, yes); + break; + default: + Parent::keyPressEvent(ev); + return; + } + ev->accept(); +} + +void ConfigList::contentsMousePressEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMousePressEvent(e); +} + +void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + const QPixmap* pm; + int idx, x; + + if (!item) + goto skip; + + menu = item->menu; + x = header()->offset() + p.x(); + idx = colRevMap[header()->sectionAt(x)]; + switch (idx) { + case promptColIdx: + pm = item->pixmap(promptColIdx); + if (pm) { + int off = header()->sectionPos(0) + itemMargin() + + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); + if (x >= off && x < off + pm->width()) { + if (item->goParent) { + emit parentSelected(); + break; + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) + emit menuSelected(menu); + else + changeValue(item); + } + } + break; + case noColIdx: + setValue(item, no); + break; + case modColIdx: + setValue(item, mod); + break; + case yesColIdx: + setValue(item, yes); + break; + case dataColIdx: + changeValue(item); + break; + } + +skip: + //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseReleaseEvent(e); +} + +void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseMoveEvent(e); +} + +void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + + if (!item) + goto skip; + if (item->goParent) { + emit parentSelected(); + goto skip; + } + menu = item->menu; + if (!menu) + goto skip; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) + emit menuSelected(menu); + else if (menu->sym) + changeValue(item); + +skip: + //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseDoubleClickEvent(e); +} + +void ConfigList::focusInEvent(QFocusEvent *e) +{ + struct menu *menu = NULL; + + Parent::focusInEvent(e); + + ConfigItem* item = (ConfigItem *)currentItem(); + if (item) { + setSelected(item, TRUE); + menu = item->menu; + } + emit gotFocus(menu); +} + +void ConfigList::contextMenuEvent(QContextMenuEvent *e) +{ + if (e->y() <= header()->geometry().bottom()) { + if (!headerPopup) { + QAction *action; + + headerPopup = new QPopupMenu(this); + action = new QAction(NULL, _("Show Name"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowName(bool))); + connect(parent(), SIGNAL(showNameChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showName); + action->addTo(headerPopup); + action = new QAction(NULL, _("Show Range"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowRange(bool))); + connect(parent(), SIGNAL(showRangeChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showRange); + action->addTo(headerPopup); + action = new QAction(NULL, _("Show Data"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowData(bool))); + connect(parent(), SIGNAL(showDataChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showData); + action->addTo(headerPopup); + } + headerPopup->exec(e->globalPos()); + e->accept(); + } else + e->ignore(); +} + +ConfigView* ConfigView::viewList; + +ConfigView::ConfigView(QWidget* parent, const char *name) + : Parent(parent, name) +{ + list = new ConfigList(this, name); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::setShowAll(bool b) +{ + if (list->showAll != b) { + list->showAll = b; + list->updateListAll(); + emit showAllChanged(b); + } +} + +void ConfigView::setShowName(bool b) +{ + if (list->showName != b) { + list->showName = b; + list->reinit(); + emit showNameChanged(b); + } +} + +void ConfigView::setShowRange(bool b) +{ + if (list->showRange != b) { + list->showRange = b; + list->reinit(); + emit showRangeChanged(b); + } +} + +void ConfigView::setShowData(bool b) +{ + if (list->showData != b) { + list->showData = b; + list->reinit(); + emit showDataChanged(b); + } +} + +void ConfigList::setAllOpen(bool open) +{ + QListViewItemIterator it(this); + + for (; it.current(); it++) + it.current()->setOpen(open); +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) + : Parent(parent, name), sym(0), menu(0) +{ + if (name) { + configSettings->beginGroup(name); + _showDebug = configSettings->readBoolEntry("/showDebug", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigInfoView::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showDebug", showDebug()); + configSettings->endGroup(); + } +} + +void ConfigInfoView::setShowDebug(bool b) +{ + if (_showDebug != b) { + _showDebug = b; + if (menu) + menuInfo(); + else if (sym) + symbolInfo(); + emit showDebugChanged(b); + } +} + +void ConfigInfoView::setInfo(struct menu *m) +{ + if (menu == m) + return; + menu = m; + sym = NULL; + if (!menu) + clear(); + else + menuInfo(); +} + +void ConfigInfoView::setSource(const QString& name) +{ + const char *p = name.latin1(); + + menu = NULL; + sym = NULL; + + switch (p[0]) { + case 'm': + struct menu *m; + + if (sscanf(p, "m%p", &m) == 1 && menu != m) { + menu = m; + menuInfo(); + emit menuSelected(menu); + } + break; + case 's': + struct symbol *s; + + if (sscanf(p, "s%p", &s) == 1 && sym != s) { + sym = s; + symbolInfo(); + } + break; + } +} + +void ConfigInfoView::symbolInfo(void) +{ + QString str; + + str += "Symbol: "; + str += print_filter(sym->name); + str += "

value: "; + str += print_filter(sym_get_string_value(sym)); + str += "
visibility: "; + str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; + str += "
"; + str += debug_info(sym); + + setText(str); +} + +void ConfigInfoView::menuInfo(void) +{ + struct symbol* sym; + QString head, debug, help; + + sym = menu->sym; + if (sym) { + if (menu->prompt) { + head += ""; + head += print_filter(_(menu->prompt->text)); + head += ""; + if (sym->name) { + head += " ("; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ")"; + } + } else if (sym->name) { + head += ""; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ""; + } + head += "

"; + + if (showDebug()) + debug = debug_info(sym); + + help = menu_get_help(menu); + /* Gettextize if the help text not empty */ + if (help.isEmpty()) + help = print_filter(menu_get_help(menu)); + else + help = print_filter(_(menu_get_help(menu))); + } else if (menu->prompt) { + head += ""; + head += print_filter(_(menu->prompt->text)); + head += "

"; + if (showDebug()) { + if (menu->prompt->visible.expr) { + debug += "  dep: "; + expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); + debug += "

"; + } + } + } + if (showDebug()) + debug += QString().sprintf("defined at %s:%d

", menu->file->name, menu->lineno); + + setText(head + debug + help); +} + +QString ConfigInfoView::debug_info(struct symbol *sym) +{ + QString debug; + + debug += "type: "; + debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; + debug += "
"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + for (struct property *prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_PROMPT: + case P_MENU: + debug += QString().sprintf("prompt: ", prop->menu); + debug += print_filter(_(prop->text)); + debug += "
"; + break; + case P_DEFAULT: + case P_SELECT: + case P_RANGE: + case P_ENV: + debug += prop_get_type_name(prop->type); + debug += ": "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + break; + default: + debug += "unknown property: "; + debug += prop_get_type_name(prop->type); + debug += "
"; + } + if (prop->visible.expr) { + debug += "    dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + } + debug += "
"; + + return debug; +} + +QString ConfigInfoView::print_filter(const QString &str) +{ + QRegExp re("[<>&\"\\n]"); + QString res = str; + for (int i = 0; (i = res.find(re, i)) >= 0;) { + switch (res[i].latin1()) { + case '<': + res.replace(i, 1, "<"); + i += 4; + break; + case '>': + res.replace(i, 1, ">"); + i += 4; + break; + case '&': + res.replace(i, 1, "&"); + i += 5; + break; + case '"': + res.replace(i, 1, """); + i += 6; + break; + case '\n': + res.replace(i, 1, "
"); + i += 4; + break; + } + } + return res; +} + +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) +{ + QString* text = reinterpret_cast(data); + QString str2 = print_filter(str); + + if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { + *text += QString().sprintf("", sym); + *text += str2; + *text += ""; + } else + *text += str2; +} + +QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) +{ + QPopupMenu* popup = Parent::createPopupMenu(pos); + QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); + action->setOn(showDebug()); + popup->insertSeparator(); + action->addTo(popup); + return popup; +} + +void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) +{ + Parent::contentsContextMenuEvent(e); +} + +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) + : Parent(parent, name), result(NULL) +{ + setCaption("Search Config"); + + QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); + QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); + layout2->addWidget(new QLabel(_("Find:"), this)); + editField = new QLineEdit(this); + connect(editField, SIGNAL(returnPressed()), SLOT(search())); + layout2->addWidget(editField); + searchButton = new QPushButton(_("Search"), this); + searchButton->setAutoDefault(FALSE); + connect(searchButton, SIGNAL(clicked()), SLOT(search())); + layout2->addWidget(searchButton); + layout1->addLayout(layout2); + + split = new QSplitter(this); + split->setOrientation(Qt::Vertical); + list = new ConfigView(split, name); + list->list->mode = listMode; + info = new ConfigInfoView(split, name); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + info, SLOT(setInfo(struct menu *))); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + parent, SLOT(setMenuLink(struct menu *))); + + layout1->addWidget(split); + + if (name) { + int x, y, width, height; + bool ok; + + configSettings->beginGroup(name); + width = configSettings->readNumEntry("/window width", parent->width() / 2); + height = configSettings->readNumEntry("/window height", parent->height() / 2); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + QValueList sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigSearchWindow::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + configSettings->writeSizes("/split", split->sizes()); + configSettings->endGroup(); + } +} + +void ConfigSearchWindow::search(void) +{ + struct symbol **p; + struct property *prop; + ConfigItem *lastItem = NULL; + + free(result); + list->list->clear(); + info->clear(); + + result = sym_re_search(editField->text().latin1()); + if (!result) + return; + for (p = result; *p; p++) { + for_all_prompts((*p), prop) + lastItem = new ConfigItem(list->list, lastItem, prop->menu, + menu_is_visible(prop->menu)); + } +} + +/* + * Construct the complete config widget + */ +ConfigMainWindow::ConfigMainWindow(void) + : searchWindow(0) +{ + QMenuBar* menu; + bool ok; + int x, y, width, height; + char title[256]; + + QDesktopWidget *d = configApp->desktop(); + snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"), + getenv("KERNELVERSION")); + setCaption(title); + + width = configSettings->readNumEntry("/window width", d->width() - 64); + height = configSettings->readNumEntry("/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + + split1 = new QSplitter(this); + split1->setOrientation(Qt::Horizontal); + setCentralWidget(split1); + + menuView = new ConfigView(split1, "menu"); + menuList = menuView->list; + + split2 = new QSplitter(split1); + split2->setOrientation(Qt::Vertical); + + // create config tree + configView = new ConfigView(split2, "config"); + configList = configView->list; + + helpText = new ConfigInfoView(split2, "help"); + helpText->setTextFormat(Qt::RichText); + + setTabOrder(configList, helpText); + configList->setFocus(); + + menu = menuBar(); + toolBar = new QToolBar("Tools", this); + + backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this); + connect(backAction, SIGNAL(activated()), SLOT(goBack())); + backAction->setEnabled(FALSE); + QAction *quitAction = new QAction("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); + connect(quitAction, SIGNAL(activated()), SLOT(close())); + QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); + connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); + saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); + connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state + conf_changed(); + QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this); + connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); + QAction *searchAction = new QAction("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); + connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); + QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); + connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); + QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); + connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); + QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); + connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); + + QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this); + showNameAction->setToggleAction(TRUE); + connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); + connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); + showNameAction->setOn(configView->showName()); + QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this); + showRangeAction->setToggleAction(TRUE); + connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); + connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); + showRangeAction->setOn(configList->showRange); + QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this); + showDataAction->setToggleAction(TRUE); + connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); + showDataAction->setOn(configList->showData); + QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this); + showAllAction->setToggleAction(TRUE); + connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool))); + connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool))); + showAllAction->setOn(configList->showAll); + QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this); + showDebugAction->setToggleAction(TRUE); + connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); + showDebugAction->setOn(helpText->showDebug()); + + QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + QAction *showAboutAction = new QAction(NULL, _("About"), 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + + // init tool bar + backAction->addTo(toolBar); + toolBar->addSeparator(); + loadAction->addTo(toolBar); + saveAction->addTo(toolBar); + toolBar->addSeparator(); + singleViewAction->addTo(toolBar); + splitViewAction->addTo(toolBar); + fullViewAction->addTo(toolBar); + + // create config menu + QPopupMenu* config = new QPopupMenu(this); + menu->insertItem(_("&File"), config); + loadAction->addTo(config); + saveAction->addTo(config); + saveAsAction->addTo(config); + config->insertSeparator(); + quitAction->addTo(config); + + // create edit menu + QPopupMenu* editMenu = new QPopupMenu(this); + menu->insertItem(_("&Edit"), editMenu); + searchAction->addTo(editMenu); + + // create options menu + QPopupMenu* optionMenu = new QPopupMenu(this); + menu->insertItem(_("&Option"), optionMenu); + showNameAction->addTo(optionMenu); + showRangeAction->addTo(optionMenu); + showDataAction->addTo(optionMenu); + optionMenu->insertSeparator(); + showAllAction->addTo(optionMenu); + showDebugAction->addTo(optionMenu); + + // create help menu + QPopupMenu* helpMenu = new QPopupMenu(this); + menu->insertSeparator(); + menu->insertItem(_("&Help"), helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + + connect(configList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(configList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + connect(configList, SIGNAL(parentSelected()), + SLOT(goBack())); + connect(menuList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + + connect(configList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + SLOT(listFocusChanged(void))); + connect(helpText, SIGNAL(menuSelected(struct menu *)), + SLOT(setMenuLink(struct menu *))); + + QString listMode = configSettings->readEntry("/listMode", "symbol"); + if (listMode == "single") + showSingleView(); + else if (listMode == "full") + showFullView(); + else /*if (listMode == "split")*/ + showSplitView(); + + // UI setup done, restore splitter positions + QValueList sizes = configSettings->readSizes("/split1", &ok); + if (ok) + split1->setSizes(sizes); + + sizes = configSettings->readSizes("/split2", &ok); + if (ok) + split2->setSizes(sizes); +} + +void ConfigMainWindow::loadConfig(void) +{ + QString s = QFileDialog::getOpenFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_read(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + ConfigView::updateListAll(); +} + +void ConfigMainWindow::saveConfig(void) +{ + if (conf_write(NULL)) + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); +} + +void ConfigMainWindow::saveConfigAs(void) +{ + QString s = QFileDialog::getSaveFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_write(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); +} + +void ConfigMainWindow::searchConfig(void) +{ + if (!searchWindow) + searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow->show(); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + configList->setRootMenu(menu); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); +} + +void ConfigMainWindow::setMenuLink(struct menu *menu) +{ + struct menu *parent; + ConfigList* list = NULL; + ConfigItem* item; + + if (!menu_is_visible(menu) && !configView->showAll()) + return; + + switch (configList->mode) { + case singleMode: + list = configList; + parent = menu_get_parent_menu(menu); + if (!parent) + return; + list->setRootMenu(parent); + break; + case symbolMode: + if (menu->flags & MENU_ROOT) { + configList->setRootMenu(menu); + configList->clearSelection(); + list = menuList; + } else { + list = configList; + parent = menu_get_parent_menu(menu->parent); + if (!parent) + return; + item = menuList->findConfigItem(parent); + if (item) { + menuList->setSelected(item, TRUE); + menuList->ensureItemVisible(item); + } + list->setRootMenu(parent); + } + break; + case fullMode: + list = configList; + break; + default: + break; + } + + if (list) { + item = list->findConfigItem(menu); + if (item) { + list->setSelected(item, TRUE); + list->ensureItemVisible(item); + list->setFocus(); + } + } +} + +void ConfigMainWindow::listFocusChanged(void) +{ + if (menuList->mode == menuMode) + configList->clearSelection(); +} + +void ConfigMainWindow::goBack(void) +{ + ConfigItem* item; + + configList->setParentMenu(); + if (configList->rootEntry == &rootmenu) + backAction->setEnabled(FALSE); + item = (ConfigItem*)menuList->selectedItem(); + while (item) { + if (item->menu == configList->rootEntry) { + menuList->setSelected(item, TRUE); + break; + } + item = (ConfigItem*)item->parent(); + } +} + +void ConfigMainWindow::showSingleView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = singleMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configList->setFocus(); +} + +void ConfigMainWindow::showSplitView(void) +{ + configList->mode = symbolMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configApp->processEvents(); + menuList->mode = menuMode; + menuList->setRootMenu(&rootmenu); + menuList->setAllOpen(TRUE); + menuView->show(); + menuList->setFocus(); +} + +void ConfigMainWindow::showFullView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = fullMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(FALSE); + configList->setFocus(); +} + +/* + * ask for saving configuration before quitting + * TODO ask only when something changed + */ +void ConfigMainWindow::closeEvent(QCloseEvent* e) +{ + if (!conf_get_changed()) { + e->accept(); + return; + } + QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); + mb.setButtonText(QMessageBox::No, _("&Discard Changes")); + mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + switch (mb.exec()) { + case QMessageBox::Yes: + conf_write(NULL); + case QMessageBox::No: + e->accept(); + break; + case QMessageBox::Cancel: + e->ignore(); + break; + } +} + +void ConfigMainWindow::showIntro(void) +{ + static const QString str = _("Welcome to the qconf graphical kernel configuration tool for Linux.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::saveSettings(void) +{ + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + + QString entry; + switch(configList->mode) { + case singleMode : + entry = "single"; + break; + + case symbolMode : + entry = "split"; + break; + + case fullMode : + entry = "full"; + break; + + default: + break; + } + configSettings->writeEntry("/listMode", entry); + + configSettings->writeSizes("/split1", split1->sizes()); + configSettings->writeSizes("/split2", split2->sizes()); +} + +void ConfigMainWindow::conf_changed(void) +{ + if (saveAction) + saveAction->setEnabled(conf_get_changed()); +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf(_("%s \n"), progname); + exit(0); +} + +int main(int ac, char** av) +{ + ConfigMainWindow* v; + const char *name; + + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + +#ifndef LKC_DIRECT_LINK + kconfig_load(); +#endif + + progname = av[0]; + configApp = new QApplication(ac, av); + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'h': + case '?': + usage(); + } + name = av[2]; + } else + name = av[1]; + if (!name) + usage(); + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + //zconfdump(stdout); + + configSettings = new ConfigSettings(); + configSettings->beginGroup("/kconfig/qconf"); + v = new ConfigMainWindow(); + + //zconfdump(stdout); + configApp->setMainWidget(v); + configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); + configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); + v->show(); + configApp->exec(); + + configSettings->endGroup(); + delete configSettings; + + return 0; +} diff --git a/config/qconf.h b/config/qconf.h new file mode 100644 index 000000000..b3b5657b6 --- /dev/null +++ b/config/qconf.h @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#if QT_VERSION >= 300 +#include +#else +class QSettings { +public: + void beginGroup(const QString& group) { } + void endGroup(void) { } + bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const + { if (ok) *ok = FALSE; return def; } + int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const + { if (ok) *ok = FALSE; return def; } + QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const + { if (ok) *ok = FALSE; return def; } + QStringList readListEntry(const QString& key, bool* ok = 0) const + { if (ok) *ok = FALSE; return QStringList(); } + template + bool writeEntry(const QString& key, t value) + { return TRUE; } +}; +#endif + +class ConfigView; +class ConfigList; +class ConfigItem; +class ConfigLineEdit; +class ConfigMainWindow; + + +class ConfigSettings : public QSettings { +public: + QValueList readSizes(const QString& key, bool *ok); + bool writeSizes(const QString& key, const QValueList& value); +}; + +enum colIdx { + promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr +}; +enum listMode { + singleMode, menuMode, symbolMode, fullMode, listMode +}; + +class ConfigList : public QListView { + Q_OBJECT + typedef class QListView Parent; +public: + ConfigList(ConfigView* p, const char *name = 0); + void reinit(void); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + ConfigItem* findConfigItem(struct menu *); + +protected: + void keyPressEvent(QKeyEvent *e); + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseReleaseEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + void contentsMouseDoubleClickEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + +public slots: + void setRootMenu(struct menu *menu); + + void updateList(ConfigItem *item); + void setValue(ConfigItem* item, tristate val); + void changeValue(ConfigItem* item); + void updateSelection(void); + void saveSettings(void); +signals: + void menuChanged(struct menu *menu); + void menuSelected(struct menu *menu); + void parentSelected(void); + void gotFocus(struct menu *); + +public: + void updateListAll(void) + { + updateAll = true; + updateList(NULL); + updateAll = false; + } + ConfigList* listView() + { + return this; + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + int mapIdx(colIdx idx) + { + return colMap[idx]; + } + void addColumn(colIdx idx, const QString& label) + { + colMap[idx] = Parent::addColumn(label); + colRevMap[colMap[idx]] = idx; + } + void removeColumn(colIdx idx) + { + int col = colMap[idx]; + if (col >= 0) { + Parent::removeColumn(col); + colRevMap[col] = colMap[idx] = -1; + } + } + void setAllOpen(bool open); + void setParentMenu(void); + + template + void updateMenuList(P*, struct menu*); + + bool updateAll; + + QPixmap symbolYesPix, symbolModPix, symbolNoPix; + QPixmap choiceYesPix, choiceNoPix; + QPixmap menuPix, menuInvPix, menuBackPix, voidPix; + + bool showAll, showName, showRange, showData; + enum listMode mode; + struct menu *rootEntry; + QColorGroup disabledColorGroup; + QColorGroup inactivedColorGroup; + QPopupMenu* headerPopup; + +private: + int colMap[colNr]; + int colRevMap[colNr]; +}; + +class ConfigItem : public QListViewItem { + typedef class QListViewItem Parent; +public: + ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(QListView *parent, ConfigItem *after, bool v) + : Parent(parent, after), menu(0), visible(v), goParent(true) + { + init(); + } + ~ConfigItem(void); + void init(void); +#if QT_VERSION >= 300 + void okRename(int col); +#endif + void updateMenu(void); + void testUpdateMenu(bool v); + ConfigList* listView() const + { + return (ConfigList*)Parent::listView(); + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + ConfigItem* nextSibling() const + { + return (ConfigItem *)Parent::nextSibling(); + } + void setText(colIdx idx, const QString& text) + { + Parent::setText(listView()->mapIdx(idx), text); + } + QString text(colIdx idx) const + { + return Parent::text(listView()->mapIdx(idx)); + } + void setPixmap(colIdx idx, const QPixmap& pm) + { + Parent::setPixmap(listView()->mapIdx(idx), pm); + } + const QPixmap* pixmap(colIdx idx) const + { + return Parent::pixmap(listView()->mapIdx(idx)); + } + void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); + + ConfigItem* nextItem; + struct menu *menu; + bool visible; + bool goParent; +}; + +class ConfigLineEdit : public QLineEdit { + Q_OBJECT + typedef class QLineEdit Parent; +public: + ConfigLineEdit(ConfigView* parent); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + void show(ConfigItem *i); + void keyPressEvent(QKeyEvent *e); + +public: + ConfigItem *item; +}; + +class ConfigView : public QVBox { + Q_OBJECT + typedef class QVBox Parent; +public: + ConfigView(QWidget* parent, const char *name = 0); + ~ConfigView(void); + static void updateList(ConfigItem* item); + static void updateListAll(void); + + bool showAll(void) const { return list->showAll; } + bool showName(void) const { return list->showName; } + bool showRange(void) const { return list->showRange; } + bool showData(void) const { return list->showData; } +public slots: + void setShowAll(bool); + void setShowName(bool); + void setShowRange(bool); + void setShowData(bool); +signals: + void showAllChanged(bool); + void showNameChanged(bool); + void showRangeChanged(bool); + void showDataChanged(bool); +public: + ConfigList* list; + ConfigLineEdit* lineEdit; + + static ConfigView* viewList; + ConfigView* nextView; +}; + +class ConfigInfoView : public QTextBrowser { + Q_OBJECT + typedef class QTextBrowser Parent; +public: + ConfigInfoView(QWidget* parent, const char *name = 0); + bool showDebug(void) const { return _showDebug; } + +public slots: + void setInfo(struct menu *menu); + void saveSettings(void); + void setSource(const QString& name); + void setShowDebug(bool); + +signals: + void showDebugChanged(bool); + void menuSelected(struct menu *); + +protected: + void symbolInfo(void); + void menuInfo(void); + QString debug_info(struct symbol *sym); + static QString print_filter(const QString &str); + static void expr_print_help(void *data, struct symbol *sym, const char *str); + QPopupMenu* createPopupMenu(const QPoint& pos); + void contentsContextMenuEvent(QContextMenuEvent *e); + + struct symbol *sym; + struct menu *menu; + bool _showDebug; +}; + +class ConfigSearchWindow : public QDialog { + Q_OBJECT + typedef class QDialog Parent; +public: + ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); + +public slots: + void saveSettings(void); + void search(void); + +protected: + QLineEdit* editField; + QPushButton* searchButton; + QSplitter* split; + ConfigView* list; + ConfigInfoView* info; + + struct symbol **result; +}; + +class ConfigMainWindow : public QMainWindow { + Q_OBJECT + + static QAction *saveAction; + static void conf_changed(void); +public: + ConfigMainWindow(void); +public slots: + void changeMenu(struct menu *); + void setMenuLink(struct menu *); + void listFocusChanged(void); + void goBack(void); + void loadConfig(void); + void saveConfig(void); + void saveConfigAs(void); + void searchConfig(void); + void showSingleView(void); + void showSplitView(void); + void showFullView(void); + void showIntro(void); + void showAbout(void); + void saveSettings(void); + +protected: + void closeEvent(QCloseEvent *e); + + ConfigSearchWindow *searchWindow; + ConfigView *menuView; + ConfigList *menuList; + ConfigView *configView; + ConfigList *configList; + ConfigInfoView *helpText; + QToolBar *toolBar; + QAction *backAction; + QSplitter* split1; + QSplitter* split2; +}; diff --git a/config/symbol.c b/config/symbol.c new file mode 100644 index 000000000..18f3e5c33 --- /dev/null +++ b/config/symbol.c @@ -0,0 +1,973 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +struct symbol symbol_yes = { + .name = "y", + .curr = { "y", yes }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_mod = { + .name = "m", + .curr = { "m", mod }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_no = { + .name = "n", + .curr = { "n", no }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_empty = { + .name = "", + .curr = { "", no }, + .flags = SYMBOL_VALID, +}; + +struct symbol *sym_defconfig_list; +struct symbol *modules_sym; +tristate modules_val; + +struct expr *sym_env_list; + +void sym_add_default(struct symbol *sym, const char *def) +{ + struct property *prop = prop_alloc(P_DEFAULT, sym); + + prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); +} + +void sym_init(void) +{ + struct symbol *sym; + struct utsname uts; + static bool inited = false; + + if (inited) + return; + inited = true; + + uname(&uts); + + sym = sym_lookup("UNAME_RELEASE", 0); + sym->type = S_STRING; + sym->flags |= SYMBOL_AUTO; + sym_add_default(sym, uts.release); +} + +enum symbol_type sym_get_type(struct symbol *sym) +{ + enum symbol_type type = sym->type; + + if (type == S_TRISTATE) { + if (sym_is_choice_value(sym) && sym->visible == yes) + type = S_BOOLEAN; + else if (modules_val == no) + type = S_BOOLEAN; + } + return type; +} + +const char *sym_type_name(enum symbol_type type) +{ + switch (type) { + case S_BOOLEAN: + return "boolean"; + case S_TRISTATE: + return "tristate"; + case S_INT: + return "integer"; + case S_HEX: + return "hex"; + case S_STRING: + return "string"; + case S_UNKNOWN: + return "unknown"; + case S_OTHER: + break; + } + return "???"; +} + +struct property *sym_get_choice_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_choices(sym, prop) + return prop; + return NULL; +} + +struct property *sym_get_env_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_ENV) + return prop; + return NULL; +} + +struct property *sym_get_default_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +struct property *sym_get_range_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_RANGE) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +static int sym_get_range_val(struct symbol *sym, int base) +{ + sym_calc_value(sym); + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + break; + } + return strtol(sym->curr.val, NULL, base); +} + +static void sym_validate_range(struct symbol *sym) +{ + struct property *prop; + int base, val, val2; + char str[64]; + + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + return; + } + prop = sym_get_range_prop(sym); + if (!prop) + return; + val = strtol(sym->curr.val, NULL, base); + val2 = sym_get_range_val(prop->expr->left.sym, base); + if (val >= val2) { + val2 = sym_get_range_val(prop->expr->right.sym, base); + if (val <= val2) + return; + } + if (sym->type == S_INT) + sprintf(str, "%d", val2); + else + sprintf(str, "0x%x", val2); + sym->curr.val = strdup(str); +} + +static void sym_calc_visibility(struct symbol *sym) +{ + struct property *prop; + tristate tri; + + /* any prompt visible? */ + tri = no; + for_all_prompts(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + tri = EXPR_OR(tri, prop->visible.tri); + } + if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) + tri = yes; + if (sym->visible != tri) { + sym->visible = tri; + sym_set_changed(sym); + } + if (sym_is_choice_value(sym)) + return; + tri = no; + if (sym->rev_dep.expr) + tri = expr_calc_value(sym->rev_dep.expr); + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) + tri = yes; + if (sym->rev_dep.tri != tri) { + sym->rev_dep.tri = tri; + sym_set_changed(sym); + } +} + +static struct symbol *sym_calc_choice(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + + /* is the user choice visible? */ + def_sym = sym->def[S_DEF_USER].val; + if (def_sym) { + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* any of the defaults visible? */ + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri == no) + continue; + def_sym = prop_get_symbol(prop); + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* just get the first visible value */ + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, def_sym) { + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* no choice? reset tristate value */ + sym->curr.tri = no; + return NULL; +} + +void sym_calc_value(struct symbol *sym) +{ + struct symbol_value newval, oldval; + struct property *prop; + struct expr *e; + + if (!sym) + return; + + if (sym->flags & SYMBOL_VALID) + return; + sym->flags |= SYMBOL_VALID; + + oldval = sym->curr; + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + newval = symbol_empty.curr; + break; + case S_BOOLEAN: + case S_TRISTATE: + newval = symbol_no.curr; + break; + default: + sym->curr.val = sym->name; + sym->curr.tri = no; + return; + } + if (!sym_is_choice_value(sym)) + sym->flags &= ~SYMBOL_WRITE; + + sym_calc_visibility(sym); + + /* set default if recursively called */ + sym->curr = newval; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_is_choice_value(sym) && sym->visible == yes) { + prop = sym_get_choice_prop(sym); + newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; + } else { + if (sym->visible != no) { + /* if the symbol is visible use the user value + * if available, otherwise try the default value + */ + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, + sym->visible); + goto calc_newval; + } + } + if (sym->rev_dep.tri != no) + sym->flags |= SYMBOL_WRITE; + if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) { + sym->flags |= SYMBOL_WRITE; + newval.tri = EXPR_AND(expr_calc_value(prop->expr), + prop->visible.tri); + } + } + calc_newval: + newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); + } + if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) + newval.tri = yes; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (sym->visible != no) { + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.val = sym->def[S_DEF_USER].val; + break; + } + } + prop = sym_get_default_prop(sym); + if (prop) { + struct symbol *ds = prop_get_symbol(prop); + if (ds) { + sym->flags |= SYMBOL_WRITE; + sym_calc_value(ds); + newval.val = ds->curr.val; + } + } + break; + default: + ; + } + + sym->curr = newval; + if (sym_is_choice(sym) && newval.tri == yes) + sym->curr.val = sym_calc_choice(sym); + sym_validate_range(sym); + + if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { + sym_set_changed(sym); + if (modules_sym == sym) { + sym_set_all_changed(); + modules_val = modules_sym->curr.tri; + } + } + + if (sym_is_choice(sym)) { + struct symbol *choice_sym; + int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); + + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, choice_sym) { + choice_sym->flags |= flags; + if (flags & SYMBOL_CHANGED) + sym_set_changed(choice_sym); + } + } + + if (sym->flags & SYMBOL_AUTO) + sym->flags &= ~SYMBOL_WRITE; +} + +void sym_clear_all_valid(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym->flags &= ~SYMBOL_VALID; + sym_add_change_count(1); + if (modules_sym) + sym_calc_value(modules_sym); +} + +void sym_set_changed(struct symbol *sym) +{ + struct property *prop; + + sym->flags |= SYMBOL_CHANGED; + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu) + prop->menu->flags |= MENU_CHANGED; + } +} + +void sym_set_all_changed(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym_set_changed(sym); +} + +bool sym_tristate_within_range(struct symbol *sym, tristate val) +{ + int type = sym_get_type(sym); + + if (sym->visible == no) + return false; + + if (type != S_BOOLEAN && type != S_TRISTATE) + return false; + + if (type == S_BOOLEAN && val == mod) + return false; + if (sym->visible <= sym->rev_dep.tri) + return false; + if (sym_is_choice_value(sym) && sym->visible == yes) + return val == yes; + return val >= sym->rev_dep.tri && val <= sym->visible; +} + +bool sym_set_tristate_value(struct symbol *sym, tristate val) +{ + tristate oldval = sym_get_tristate_value(sym); + + if (oldval != val && !sym_tristate_within_range(sym, val)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + /* + * setting a choice value also resets the new flag of the choice + * symbol and all other choice values. + */ + if (sym_is_choice_value(sym) && val == yes) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + struct property *prop; + struct expr *e; + + cs->def[S_DEF_USER].val = sym; + cs->flags |= SYMBOL_DEF_USER; + prop = sym_get_choice_prop(cs); + for (e = prop->expr; e; e = e->left.expr) { + if (e->right.sym->visible != no) + e->right.sym->flags |= SYMBOL_DEF_USER; + } + } + + sym->def[S_DEF_USER].tri = val; + if (oldval != val) + sym_clear_all_valid(); + + return true; +} + +tristate sym_toggle_tristate_value(struct symbol *sym) +{ + tristate oldval, newval; + + oldval = newval = sym_get_tristate_value(sym); + do { + switch (newval) { + case no: + newval = mod; + break; + case mod: + newval = yes; + break; + case yes: + newval = no; + break; + } + if (sym_set_tristate_value(sym, newval)) + break; + } while (oldval != newval); + return newval; +} + +bool sym_string_valid(struct symbol *sym, const char *str) +{ + signed char ch; + + switch (sym->type) { + case S_STRING: + return true; + case S_INT: + ch = *str++; + if (ch == '-') + ch = *str++; + if (!isdigit(ch)) + return false; + if (ch == '0' && *str != 0) + return false; + while ((ch = *str++)) { + if (!isdigit(ch)) + return false; + } + return true; + case S_HEX: + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + ch = *str++; + do { + if (!isxdigit(ch)) + return false; + } while ((ch = *str++)); + return true; + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + case 'm': case 'M': + case 'n': case 'N': + return true; + } + return false; + default: + return false; + } +} + +bool sym_string_within_range(struct symbol *sym, const char *str) +{ + struct property *prop; + int val; + + switch (sym->type) { + case S_STRING: + return sym_string_valid(sym, str); + case S_INT: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 10); + return val >= sym_get_range_val(prop->expr->left.sym, 10) && + val <= sym_get_range_val(prop->expr->right.sym, 10); + case S_HEX: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 16); + return val >= sym_get_range_val(prop->expr->left.sym, 16) && + val <= sym_get_range_val(prop->expr->right.sym, 16); + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + return sym_tristate_within_range(sym, yes); + case 'm': case 'M': + return sym_tristate_within_range(sym, mod); + case 'n': case 'N': + return sym_tristate_within_range(sym, no); + } + return false; + default: + return false; + } +} + +bool sym_set_string_value(struct symbol *sym, const char *newval) +{ + const char *oldval; + char *val; + int size; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (newval[0]) { + case 'y': case 'Y': + return sym_set_tristate_value(sym, yes); + case 'm': case 'M': + return sym_set_tristate_value(sym, mod); + case 'n': case 'N': + return sym_set_tristate_value(sym, no); + } + return false; + default: + ; + } + + if (!sym_string_within_range(sym, newval)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + + oldval = sym->def[S_DEF_USER].val; + size = strlen(newval) + 1; + if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { + size += 2; + sym->def[S_DEF_USER].val = val = malloc(size); + *val++ = '0'; + *val++ = 'x'; + } else if (!oldval || strcmp(oldval, newval)) + sym->def[S_DEF_USER].val = val = malloc(size); + else + return true; + + strcpy(val, newval); + free((void *)oldval); + sym_clear_all_valid(); + + return true; +} + +const char *sym_get_string_value(struct symbol *sym) +{ + tristate val; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + return "n"; + case mod: + return "m"; + case yes: + return "y"; + } + break; + default: + ; + } + return (const char *)sym->curr.val; +} + +bool sym_is_changable(struct symbol *sym) +{ + return sym->visible > sym->rev_dep.tri; +} + +struct symbol *sym_lookup(const char *name, int flags) +{ + struct symbol *symbol; + const char *ptr; + char *new_name; + int hash = 0; + + if (name) { + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + for (ptr = name; *ptr; ptr++) + hash += *ptr; + hash &= 0xff; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (!strcmp(symbol->name, name) && + (flags ? symbol->flags & flags + : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + return symbol; + } + new_name = strdup(name); + } else { + new_name = NULL; + hash = 256; + } + + symbol = malloc(sizeof(*symbol)); + memset(symbol, 0, sizeof(*symbol)); + symbol->name = new_name; + symbol->type = S_UNKNOWN; + symbol->flags |= flags; + + symbol->next = symbol_hash[hash]; + symbol_hash[hash] = symbol; + + return symbol; +} + +struct symbol *sym_find(const char *name) +{ + struct symbol *symbol = NULL; + const char *ptr; + int hash = 0; + + if (!name) + return NULL; + + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + for (ptr = name; *ptr; ptr++) + hash += *ptr; + hash &= 0xff; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (!strcmp(symbol->name, name) && + !(symbol->flags & SYMBOL_CONST)) + break; + } + + return symbol; +} + +struct symbol **sym_re_search(const char *pattern) +{ + struct symbol *sym, **sym_arr = NULL; + int i, cnt, size; + regex_t re; + + cnt = size = 0; + /* Skip if empty */ + if (strlen(pattern) == 0) + return NULL; + if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) + return NULL; + + for_all_symbols(i, sym) { + if (sym->flags & SYMBOL_CONST || !sym->name) + continue; + if (regexec(&re, sym->name, 0, NULL, 0)) + continue; + if (cnt + 1 >= size) { + void *tmp = sym_arr; + size += 16; + sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); + if (!sym_arr) { + free(tmp); + return NULL; + } + } + sym_arr[cnt++] = sym; + } + if (sym_arr) + sym_arr[cnt] = NULL; + regfree(&re); + + return sym_arr; +} + + +static struct symbol *sym_check_expr_deps(struct expr *e) +{ + struct symbol *sym; + + if (!e) + return NULL; + switch (e->type) { + case E_OR: + case E_AND: + sym = sym_check_expr_deps(e->left.expr); + if (sym) + return sym; + return sym_check_expr_deps(e->right.expr); + case E_NOT: + return sym_check_expr_deps(e->left.expr); + case E_EQUAL: + case E_UNEQUAL: + sym = sym_check_deps(e->left.sym); + if (sym) + return sym; + return sym_check_deps(e->right.sym); + case E_SYMBOL: + return sym_check_deps(e->left.sym); + default: + break; + } + printf("Oops! How to check %d?\n", e->type); + return NULL; +} + +/* return NULL when dependencies are OK */ +static struct symbol *sym_check_sym_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + + sym2 = sym_check_expr_deps(sym->rev_dep.expr); + if (sym2) + return sym2; + + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->type == P_CHOICE || prop->type == P_SELECT) + continue; + sym2 = sym_check_expr_deps(prop->visible.expr); + if (sym2) + break; + if (prop->type != P_DEFAULT || sym_is_choice(sym)) + continue; + sym2 = sym_check_expr_deps(prop->expr); + if (sym2) + break; + } + + return sym2; +} + +static struct symbol *sym_check_choice_deps(struct symbol *choice) +{ + struct symbol *sym, *sym2; + struct property *prop; + struct expr *e; + + prop = sym_get_choice_prop(choice); + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + + choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(choice); + choice->flags &= ~SYMBOL_CHECK; + if (sym2) + goto out; + + expr_list_for_each_sym(prop->expr, e, sym) { + sym2 = sym_check_sym_deps(sym); + if (sym2) { + fprintf(stderr, " -> %s", sym->name); + break; + } + } +out: + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags &= ~SYMBOL_CHECK; + + if (sym2 && sym_is_choice_value(sym2) && + prop_get_symbol(sym_get_choice_prop(sym2)) == choice) + sym2 = choice; + + return sym2; +} + +struct symbol *sym_check_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + + if (sym->flags & SYMBOL_CHECK) { + fprintf(stderr, "%s:%d:error: found recursive dependency: %s", + sym->prop->file->name, sym->prop->lineno, + sym->name ? sym->name : ""); + return sym; + } + if (sym->flags & SYMBOL_CHECKED) + return NULL; + + if (sym_is_choice_value(sym)) { + /* for choice groups start the check with main choice symbol */ + prop = sym_get_choice_prop(sym); + sym2 = sym_check_deps(prop_get_symbol(prop)); + } else if (sym_is_choice(sym)) { + sym2 = sym_check_choice_deps(sym); + } else { + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(sym); + sym->flags &= ~SYMBOL_CHECK; + } + + if (sym2) { + fprintf(stderr, " -> %s", sym->name ? sym->name : ""); + if (sym2 == sym) { + fprintf(stderr, "\n"); + zconfnerrs++; + sym2 = NULL; + } + } + + return sym2; +} + +struct property *prop_alloc(enum prop_type type, struct symbol *sym) +{ + struct property *prop; + struct property **propp; + + prop = malloc(sizeof(*prop)); + memset(prop, 0, sizeof(*prop)); + prop->type = type; + prop->sym = sym; + prop->file = current_file; + prop->lineno = zconf_lineno(); + + /* append property to the prop list of symbol */ + if (sym) { + for (propp = &sym->prop; *propp; propp = &(*propp)->next) + ; + *propp = prop; + } + + return prop; +} + +struct symbol *prop_get_symbol(struct property *prop) +{ + if (prop->expr && (prop->expr->type == E_SYMBOL || + prop->expr->type == E_LIST)) + return prop->expr->left.sym; + return NULL; +} + +const char *prop_get_type_name(enum prop_type type) +{ + switch (type) { + case P_PROMPT: + return "prompt"; + case P_ENV: + return "env"; + case P_COMMENT: + return "comment"; + case P_MENU: + return "menu"; + case P_DEFAULT: + return "default"; + case P_CHOICE: + return "choice"; + case P_SELECT: + return "select"; + case P_RANGE: + return "range"; + case P_UNKNOWN: + break; + } + return "unknown"; +} + +void prop_add_env(const char *env) +{ + struct symbol *sym, *sym2; + struct property *prop; + char *p; + + sym = current_entry->sym; + sym->flags |= SYMBOL_AUTO; + for_all_properties(sym, prop, P_ENV) { + sym2 = prop_get_symbol(prop); + if (strcmp(sym2->name, env)) + menu_warn(current_entry, "redefining environment symbol from %s", + sym2->name); + return; + } + + prop = prop_alloc(P_ENV, sym); + prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); + + sym_env_list = expr_alloc_one(E_LIST, sym_env_list); + sym_env_list->right.sym = sym; + + p = getenv(env); + if (p) + sym_add_default(sym, p); + else + menu_warn(current_entry, "environment variable %s undefined", env); +} diff --git a/config/util.c b/config/util.c new file mode 100644 index 000000000..b6b2a46af --- /dev/null +++ b/config/util.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include "lkc.h" + +/* file already present in list? If not add it */ +struct file *file_lookup(const char *name) +{ + struct file *file; + + for (file = file_list; file; file = file->next) { + if (!strcmp(name, file->name)) + return file; + } + + file = malloc(sizeof(*file)); + memset(file, 0, sizeof(*file)); + file->name = strdup(name); + file->next = file_list; + file_list = file; + return file; +} + +/* write a dependency file as used by kbuild to track dependencies */ +int file_write_dep(const char *name) +{ + struct symbol *sym, *env_sym; + struct expr *e; + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + out = fopen("..config.tmp", "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + expr_list_for_each_sym(sym_env_list, e, sym) { + struct property *prop; + const char *value; + + prop = sym_get_env_prop(sym); + env_sym = prop_get_symbol(prop); + if (!env_sym) + continue; + value = getenv(env_sym->name); + if (!value) + value = ""; + fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); + fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); + fprintf(out, "endif\n"); + } + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + rename("..config.tmp", name); + return 0; +} + + +/* Allocate initial growable sting */ +struct gstr str_new(void) +{ + struct gstr gs; + gs.s = malloc(sizeof(char) * 64); + gs.len = 64; + strcpy(gs.s, "\0"); + return gs; +} + +/* Allocate and assign growable string */ +struct gstr str_assign(const char *s) +{ + struct gstr gs; + gs.s = strdup(s); + gs.len = strlen(s) + 1; + return gs; +} + +/* Free storage for growable string */ +void str_free(struct gstr *gs) +{ + if (gs->s) + free(gs->s); + gs->s = NULL; + gs->len = 0; +} + +/* Append to growable string */ +void str_append(struct gstr *gs, const char *s) +{ + size_t l; + if (s) { + l = strlen(gs->s) + strlen(s) + 1; + if (l > gs->len) { + gs->s = realloc(gs->s, l); + gs->len = l; + } + strcat(gs->s, s); + } +} + +/* Append printf formatted string to growable string */ +void str_printf(struct gstr *gs, const char *fmt, ...) +{ + va_list ap; + char s[10000]; /* big enough... */ + va_start(ap, fmt); + vsnprintf(s, sizeof(s), fmt, ap); + str_append(gs, s); + va_end(ap); +} + +/* Retrieve value of growable string */ +const char *str_get(struct gstr *gs) +{ + return gs->s; +} + diff --git a/config/zconf.gperf b/config/zconf.gperf new file mode 100644 index 000000000..25ef5d01c --- /dev/null +++ b/config/zconf.gperf @@ -0,0 +1,44 @@ +%language=ANSI-C +%define hash-function-name kconf_id_hash +%define lookup-function-name kconf_id_lookup +%define string-pool-name kconf_id_strings +%compare-strncmp +%enum +%pic +%struct-type + +struct kconf_id; + +%% +mainmenu, T_MAINMENU, TF_COMMAND +menu, T_MENU, TF_COMMAND +endmenu, T_ENDMENU, TF_COMMAND +source, T_SOURCE, TF_COMMAND +choice, T_CHOICE, TF_COMMAND +endchoice, T_ENDCHOICE, TF_COMMAND +comment, T_COMMENT, TF_COMMAND +config, T_CONFIG, TF_COMMAND +menuconfig, T_MENUCONFIG, TF_COMMAND +help, T_HELP, TF_COMMAND +if, T_IF, TF_COMMAND|TF_PARAM +endif, T_ENDIF, TF_COMMAND +depends, T_DEPENDS, TF_COMMAND +optional, T_OPTIONAL, TF_COMMAND +default, T_DEFAULT, TF_COMMAND, S_UNKNOWN +prompt, T_PROMPT, TF_COMMAND +tristate, T_TYPE, TF_COMMAND, S_TRISTATE +def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE +bool, T_TYPE, TF_COMMAND, S_BOOLEAN +boolean, T_TYPE, TF_COMMAND, S_BOOLEAN +def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN +int, T_TYPE, TF_COMMAND, S_INT +hex, T_TYPE, TF_COMMAND, S_HEX +string, T_TYPE, TF_COMMAND, S_STRING +select, T_SELECT, TF_COMMAND +range, T_RANGE, TF_COMMAND +option, T_OPTION, TF_COMMAND +on, T_ON, TF_PARAM +modules, T_OPT_MODULES, TF_OPTION +defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION +env, T_OPT_ENV, TF_OPTION +%% diff --git a/config/zconf.hash.c_shipped b/config/zconf.hash.c_shipped new file mode 100644 index 000000000..5c73d5133 --- /dev/null +++ b/config/zconf.hash.c_shipped @@ -0,0 +1,237 @@ +/* ANSI-C code produced by gperf version 3.0.3 */ +/* Command-line: gperf */ +/* Computed positions: -k'1,3' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +struct kconf_id; +/* maximum key range = 47, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +kconf_id_hash (register const char *str, register unsigned int len) +{ + static unsigned char asso_values[] = + { + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 11, 5, + 0, 0, 5, 49, 5, 20, 49, 49, 5, 20, + 5, 0, 30, 49, 0, 15, 0, 10, 0, 49, + 25, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval; +} + +struct kconf_id_strings_t + { + char kconf_id_strings_str2[sizeof("on")]; + char kconf_id_strings_str3[sizeof("env")]; + char kconf_id_strings_str5[sizeof("endif")]; + char kconf_id_strings_str6[sizeof("option")]; + char kconf_id_strings_str7[sizeof("endmenu")]; + char kconf_id_strings_str8[sizeof("optional")]; + char kconf_id_strings_str9[sizeof("endchoice")]; + char kconf_id_strings_str10[sizeof("range")]; + char kconf_id_strings_str11[sizeof("choice")]; + char kconf_id_strings_str12[sizeof("default")]; + char kconf_id_strings_str13[sizeof("def_bool")]; + char kconf_id_strings_str14[sizeof("help")]; + char kconf_id_strings_str15[sizeof("bool")]; + char kconf_id_strings_str16[sizeof("config")]; + char kconf_id_strings_str17[sizeof("def_tristate")]; + char kconf_id_strings_str18[sizeof("boolean")]; + char kconf_id_strings_str19[sizeof("defconfig_list")]; + char kconf_id_strings_str21[sizeof("string")]; + char kconf_id_strings_str22[sizeof("if")]; + char kconf_id_strings_str23[sizeof("int")]; + char kconf_id_strings_str26[sizeof("select")]; + char kconf_id_strings_str27[sizeof("modules")]; + char kconf_id_strings_str28[sizeof("tristate")]; + char kconf_id_strings_str29[sizeof("menu")]; + char kconf_id_strings_str31[sizeof("source")]; + char kconf_id_strings_str32[sizeof("comment")]; + char kconf_id_strings_str33[sizeof("hex")]; + char kconf_id_strings_str35[sizeof("menuconfig")]; + char kconf_id_strings_str36[sizeof("prompt")]; + char kconf_id_strings_str37[sizeof("depends")]; + char kconf_id_strings_str48[sizeof("mainmenu")]; + }; +static struct kconf_id_strings_t kconf_id_strings_contents = + { + "on", + "env", + "endif", + "option", + "endmenu", + "optional", + "endchoice", + "range", + "choice", + "default", + "def_bool", + "help", + "bool", + "config", + "def_tristate", + "boolean", + "defconfig_list", + "string", + "if", + "int", + "select", + "modules", + "tristate", + "menu", + "source", + "comment", + "hex", + "menuconfig", + "prompt", + "depends", + "mainmenu" + }; +#define kconf_id_strings ((const char *) &kconf_id_strings_contents) +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +struct kconf_id * +kconf_id_lookup (register const char *str, register unsigned int len) +{ + enum + { + TOTAL_KEYWORDS = 31, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 14, + MIN_HASH_VALUE = 2, + MAX_HASH_VALUE = 48 + }; + + static struct kconf_id wordlist[] = + { + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_ON, TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_OPT_ENV, TF_OPTION}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_OPTION, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_OPTIONAL, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_CHOICE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_TYPE, TF_COMMAND, S_STRING}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SELECT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SOURCE, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_HEX}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_PROMPT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_DEPENDS, TF_COMMAND}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = kconf_id_hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int o = wordlist[key].name; + if (o >= 0) + { + register const char *s = o + kconf_id_strings; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[key]; + } + } + } + return 0; +} + diff --git a/config/zconf.l b/config/zconf.l new file mode 100644 index 000000000..21ff69c9a --- /dev/null +++ b/config/zconf.l @@ -0,0 +1,359 @@ +%option backup nostdinit noyywrap never-interactive full ecs +%option 8bit backup nodefault perf-report perf-report +%option noinput +%x COMMAND HELP STRING PARAM +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +void new_string(void) +{ + text = malloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +void alloc_string(const char *str, int size) +{ + text = malloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} +%} + +ws [ \n\t] +n [A-Za-z0-9_] + +%% + int str = 0; + int ts, i; + +[ \t]*#.*\n | +[ \t]*\n { + current_file->lineno++; + return T_EOL; +} +[ \t]*#.* + + +[ \t]+ { + BEGIN(COMMAND); +} + +. { + unput(yytext[0]); + BEGIN(COMMAND); +} + + +{ + {n}+ { + struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + . + \n { + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } +} + +{ + "&&" return T_AND; + "||" return T_OR; + "(" return T_OPEN_PAREN; + ")" return T_CLOSE_PAREN; + "!" return T_NOT; + "=" return T_EQUAL; + "!=" return T_UNEQUAL; + \"|\' { + str = yytext[0]; + new_string(); + BEGIN(STRING); + } + \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; + --- /* ignore */ + ({n}|[-/.])+ { + struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + #.* /* comment */ + \\\n current_file->lineno++; + . + <> { + BEGIN(INITIAL); + } +} + +{ + [^'"\\\n]+/\n { + append_string(yytext, yyleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + [^'"\\\n]+ { + append_string(yytext, yyleng); + } + \\.?/\n { + append_string(yytext + 1, yyleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + \\.? { + append_string(yytext + 1, yyleng - 1); + } + \'|\" { + if (str == yytext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(yytext, 1); + } + \n { + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + <> { + BEGIN(INITIAL); + } +} + +{ + [ \t]+ { + ts = 0; + for (i = 0; i < yyleng; i++) { + if (yytext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + [ \t]*\n/[^ \t\n] { + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + [ \t]*\n { + current_file->lineno++; + append_string("\n", 1); + } + [^ \t\n].* { + while (yyleng) { + if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) + break; + yyleng--; + } + append_string(yytext, yyleng); + if (!first_ts) + first_ts = last_ts; + } + <> { + zconf_endhelp(); + return T_HELPTEXT; + } +} + +<> { + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(yyin); + yyterminate(); +} + +%% +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + yyin = zconf_fopen(name); + if (!yyin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = malloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; + current_file->flags = FILE_BUSY; +} + +void zconf_nextfile(const char *name) +{ + struct file *file = file_lookup(name); + struct buffer *buf = malloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + yyin = zconf_fopen(name); + if (!yyin) { + printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); + exit(1); + } + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + if (file->flags & FILE_BUSY) { + printf("%s:%d: do not source '%s' from itself\n", + zconf_curname(), zconf_lineno(), name); + exit(1); + } + if (file->flags & FILE_SCANNED) { + printf("%s:%d: file '%s' is already sourced from '%s'\n", + zconf_curname(), zconf_lineno(), name, + file->parent->name); + exit(1); + } + file->flags |= FILE_BUSY; + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file->flags |= FILE_SCANNED; + current_file->flags &= ~FILE_BUSY; + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} diff --git a/config/zconf.tab.c_shipped b/config/zconf.tab.c_shipped new file mode 100644 index 000000000..95df833b5 --- /dev/null +++ b/config/zconf.tab.c_shipped @@ -0,0 +1,2490 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + 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, 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_OPTIONAL = 272, + T_PROMPT = 273, + T_TYPE = 274, + T_DEFAULT = 275, + T_SELECT = 276, + T_RANGE = 277, + T_OPTION = 278, + T_ON = 279, + T_WORD = 280, + T_WORD_QUOTE = 281, + T_UNEQUAL = 282, + T_CLOSE_PAREN = 283, + T_OPEN_PAREN = 284, + T_EOL = 285, + T_OR = 286, + T_AND = 287, + T_EQUAL = 288, + T_NOT = 289 + }; +#endif +/* Tokens. */ +#define T_MAINMENU 258 +#define T_MENU 259 +#define T_ENDMENU 260 +#define T_SOURCE 261 +#define T_CHOICE 262 +#define T_ENDCHOICE 263 +#define T_COMMENT 264 +#define T_CONFIG 265 +#define T_MENUCONFIG 266 +#define T_HELP 267 +#define T_HELPTEXT 268 +#define T_IF 269 +#define T_ENDIF 270 +#define T_DEPENDS 271 +#define T_OPTIONAL 272 +#define T_PROMPT 273 +#define T_TYPE 274 +#define T_DEFAULT 275 +#define T_SELECT 276 +#define T_RANGE 277 +#define T_OPTION 278 +#define T_ON 279 +#define T_WORD 280 +#define T_WORD_QUOTE 281 +#define T_UNEQUAL 282 +#define T_CLOSE_PAREN 283 +#define T_OPEN_PAREN 284 +#define T_EOL 285 +#define T_OR 286 +#define T_AND 287 +#define T_EQUAL 288 +#define T_NOT 289 + + + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#include "zconf.hash.c" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[257]; + +static struct menu *current_menu, *current_entry; + +#define YYDEBUG 0 +#if YYDEBUG +#define YYERROR_VERBOSE +#endif + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE + +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + struct kconf_id *id; +} +/* Line 187 of yacc.c. */ + + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 259 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 35 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 46 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 110 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 180 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 289 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 6, 9, 12, 15, 20, 23, + 28, 33, 37, 39, 41, 43, 45, 47, 49, 51, + 53, 55, 57, 59, 61, 63, 67, 70, 74, 77, + 81, 84, 85, 88, 91, 94, 97, 100, 103, 107, + 112, 117, 122, 128, 132, 133, 137, 138, 141, 145, + 148, 150, 154, 155, 158, 161, 164, 167, 170, 175, + 179, 182, 187, 188, 191, 195, 197, 201, 202, 205, + 208, 211, 215, 218, 220, 224, 225, 228, 231, 234, + 238, 242, 245, 248, 251, 252, 255, 258, 261, 266, + 267, 270, 272, 274, 277, 280, 283, 285, 288, 289, + 292, 294, 298, 302, 306, 309, 313, 317, 319, 321, + 322 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 36, 0, -1, 37, -1, -1, 37, 39, -1, 37, + 53, -1, 37, 64, -1, 37, 3, 74, 76, -1, + 37, 75, -1, 37, 25, 1, 30, -1, 37, 38, + 1, 30, -1, 37, 1, 30, -1, 16, -1, 18, + -1, 19, -1, 21, -1, 17, -1, 22, -1, 20, + -1, 30, -1, 59, -1, 68, -1, 42, -1, 44, + -1, 66, -1, 25, 1, 30, -1, 1, 30, -1, + 10, 25, 30, -1, 41, 45, -1, 11, 25, 30, + -1, 43, 45, -1, -1, 45, 46, -1, 45, 47, + -1, 45, 72, -1, 45, 70, -1, 45, 40, -1, + 45, 30, -1, 19, 73, 30, -1, 18, 74, 77, + 30, -1, 20, 78, 77, 30, -1, 21, 25, 77, + 30, -1, 22, 79, 79, 77, 30, -1, 23, 48, + 30, -1, -1, 48, 25, 49, -1, -1, 33, 74, + -1, 7, 80, 30, -1, 50, 54, -1, 75, -1, + 51, 56, 52, -1, -1, 54, 55, -1, 54, 72, + -1, 54, 70, -1, 54, 30, -1, 54, 40, -1, + 18, 74, 77, 30, -1, 19, 73, 30, -1, 17, + 30, -1, 20, 25, 77, 30, -1, -1, 56, 39, + -1, 14, 78, 76, -1, 75, -1, 57, 60, 58, + -1, -1, 60, 39, -1, 60, 64, -1, 60, 53, + -1, 4, 74, 30, -1, 61, 71, -1, 75, -1, + 62, 65, 63, -1, -1, 65, 39, -1, 65, 64, + -1, 65, 53, -1, 6, 74, 30, -1, 9, 74, + 30, -1, 67, 71, -1, 12, 30, -1, 69, 13, + -1, -1, 71, 72, -1, 71, 30, -1, 71, 40, + -1, 16, 24, 78, 30, -1, -1, 74, 77, -1, + 25, -1, 26, -1, 5, 30, -1, 8, 30, -1, + 15, 30, -1, 30, -1, 76, 30, -1, -1, 14, + 78, -1, 79, -1, 79, 33, 79, -1, 79, 27, + 79, -1, 29, 78, 28, -1, 34, 78, -1, 78, + 31, 78, -1, 78, 32, 78, -1, 25, -1, 26, + -1, -1, 25, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 104, 104, 106, 108, 109, 110, 111, 112, 113, + 114, 118, 122, 122, 122, 122, 122, 122, 122, 126, + 127, 128, 129, 130, 131, 135, 136, 142, 150, 156, + 164, 174, 176, 177, 178, 179, 180, 181, 184, 192, + 198, 208, 214, 220, 223, 225, 236, 237, 242, 251, + 256, 264, 267, 269, 270, 271, 272, 273, 276, 282, + 293, 299, 309, 311, 316, 324, 332, 335, 337, 338, + 339, 344, 351, 356, 364, 367, 369, 370, 371, 374, + 382, 389, 396, 402, 409, 411, 412, 413, 416, 424, + 426, 431, 432, 435, 436, 437, 441, 442, 445, 446, + 449, 450, 451, 452, 453, 454, 455, 458, 459, 462, + 463 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", + "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt", + "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "symbol_option", "symbol_option_list", + "symbol_option_arg", "choice", "choice_entry", "choice_end", + "choice_stmt", "choice_option_list", "choice_option", "choice_block", + "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry", + "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment", + "comment_stmt", "help_start", "help", "depends_list", "depends", + "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol", + "word_opt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 35, 36, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 38, 38, 38, 38, 38, 38, 38, 39, + 39, 39, 39, 39, 39, 40, 40, 41, 42, 43, + 44, 45, 45, 45, 45, 45, 45, 45, 46, 46, + 46, 46, 46, 47, 48, 48, 49, 49, 50, 51, + 52, 53, 54, 54, 54, 54, 54, 54, 55, 55, + 55, 55, 56, 56, 57, 58, 59, 60, 60, 60, + 60, 61, 62, 63, 64, 65, 65, 65, 65, 66, + 67, 68, 69, 70, 71, 71, 71, 71, 72, 73, + 73, 74, 74, 75, 75, 75, 76, 76, 77, 77, + 78, 78, 78, 78, 78, 78, 78, 79, 79, 80, + 80 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 0, 2, 2, 2, 4, 2, 4, + 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 2, 3, 2, 3, + 2, 0, 2, 2, 2, 2, 2, 2, 3, 4, + 4, 4, 5, 3, 0, 3, 0, 2, 3, 2, + 1, 3, 0, 2, 2, 2, 2, 2, 4, 3, + 2, 4, 0, 2, 3, 1, 3, 0, 2, 2, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 3, + 3, 2, 2, 2, 0, 2, 2, 2, 4, 0, + 2, 1, 1, 2, 2, 2, 1, 2, 0, 2, + 1, 3, 3, 3, 2, 3, 3, 1, 1, 0, + 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 3, 0, 0, 1, 0, 0, 0, 0, 0, 109, + 0, 0, 0, 0, 0, 0, 12, 16, 13, 14, + 18, 15, 17, 0, 19, 0, 4, 31, 22, 31, + 23, 52, 62, 5, 67, 20, 84, 75, 6, 24, + 84, 21, 8, 11, 91, 92, 0, 0, 93, 0, + 110, 0, 94, 0, 0, 0, 107, 108, 0, 0, + 0, 100, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 7, 71, 79, 48, 80, 27, + 29, 0, 104, 0, 0, 64, 0, 0, 9, 10, + 0, 0, 0, 0, 89, 0, 0, 0, 44, 0, + 37, 36, 32, 33, 0, 35, 34, 0, 0, 89, + 0, 56, 57, 53, 55, 54, 63, 51, 50, 68, + 70, 66, 69, 65, 86, 87, 85, 76, 78, 74, + 77, 73, 97, 103, 105, 106, 102, 101, 26, 82, + 0, 98, 0, 98, 98, 98, 0, 0, 0, 83, + 60, 98, 0, 98, 0, 0, 0, 38, 90, 0, + 0, 98, 46, 43, 25, 0, 59, 0, 88, 99, + 39, 40, 41, 0, 0, 45, 58, 61, 42, 47 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 2, 25, 26, 101, 27, 28, 29, 30, + 65, 102, 103, 147, 175, 31, 32, 117, 33, 67, + 113, 68, 34, 121, 35, 69, 36, 37, 129, 38, + 71, 39, 40, 41, 104, 105, 70, 106, 142, 143, + 42, 74, 156, 60, 61, 51 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -80 +static const yytype_int16 yypact[] = +{ + -80, 2, 132, -80, -13, -1, -1, -2, -1, 9, + 33, -1, 27, 40, -3, 38, -80, -80, -80, -80, + -80, -80, -80, 71, -80, 77, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, 57, 61, -80, 63, + -80, 76, -80, 87, 101, 133, -80, -80, -3, -3, + 195, -6, -80, 136, 149, 39, 104, 65, 150, 5, + 194, 5, 167, -80, 176, -80, -80, -80, -80, -80, + -80, 68, -80, -3, -3, 176, 72, 72, -80, -80, + 177, 187, 78, -1, -1, -3, 196, 72, -80, 222, + -80, -80, -80, -80, 221, -80, -80, 205, -1, -1, + 211, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, 206, -80, -80, -80, -80, -80, + -3, 223, 209, 223, 197, 223, 72, 7, 210, -80, + -80, 223, 212, 223, 201, -3, 213, -80, -80, 214, + 215, 223, 208, -80, -80, 216, -80, 217, -80, 113, + -80, -80, -80, 218, -1, -80, -80, -80, -80, -80 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -80, -80, -80, -80, 122, -34, -80, -80, -80, -80, + 220, -80, -80, -80, -80, -80, -80, -80, 59, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, 125, + -80, -80, -80, -80, -80, 183, 219, 22, 142, -5, + 147, 192, 69, -54, -79, -80 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -82 +static const yytype_int16 yytable[] = +{ + 46, 47, 3, 49, 81, 82, 53, 136, 137, 6, + 7, 8, 9, 10, 11, 12, 13, 43, 146, 14, + 15, 86, 56, 57, 44, 45, 58, 87, 48, 134, + 135, 59, 162, 112, 50, 24, 125, 163, 125, -28, + 90, 144, -28, -28, -28, -28, -28, -28, -28, -28, + -28, 91, 54, -28, -28, 92, -28, 93, 94, 95, + 96, 97, 98, 52, 99, 55, 90, 161, 62, 100, + -49, -49, 63, -49, -49, -49, -49, 91, 64, -49, + -49, 92, 107, 108, 109, 110, 154, 73, 141, 115, + 99, 75, 126, 76, 126, 111, 133, 56, 57, 83, + 84, 169, 140, 151, -30, 90, 77, -30, -30, -30, + -30, -30, -30, -30, -30, -30, 91, 78, -30, -30, + 92, -30, 93, 94, 95, 96, 97, 98, 120, 99, + 128, 79, -2, 4, 100, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 83, 84, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 7, 8, 23, 10, 11, + 12, 13, 24, 80, 14, 15, 88, -81, 90, 179, + -81, -81, -81, -81, -81, -81, -81, -81, -81, 89, + 24, -81, -81, 92, -81, -81, -81, -81, -81, -81, + 116, 119, 99, 127, 122, 90, 130, 124, -72, -72, + -72, -72, -72, -72, -72, -72, 132, 138, -72, -72, + 92, 155, 158, 159, 160, 118, 123, 139, 131, 99, + 165, 145, 167, 148, 124, 73, 83, 84, 83, 84, + 173, 168, 83, 84, 149, 150, 153, 155, 84, 157, + 164, 174, 166, 170, 171, 172, 176, 177, 178, 66, + 114, 152, 85, 0, 0, 0, 0, 0, 0, 72 +}; + +static const yytype_int16 yycheck[] = +{ + 5, 6, 0, 8, 58, 59, 11, 86, 87, 4, + 5, 6, 7, 8, 9, 10, 11, 30, 97, 14, + 15, 27, 25, 26, 25, 26, 29, 33, 30, 83, + 84, 34, 25, 67, 25, 30, 70, 30, 72, 0, + 1, 95, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 25, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 30, 25, 25, 1, 146, 30, 30, + 5, 6, 1, 8, 9, 10, 11, 12, 1, 14, + 15, 16, 17, 18, 19, 20, 140, 30, 93, 67, + 25, 30, 70, 30, 72, 30, 28, 25, 26, 31, + 32, 155, 24, 108, 0, 1, 30, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 30, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 69, 25, + 71, 30, 0, 1, 30, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 31, 32, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 5, 6, 25, 8, 9, + 10, 11, 30, 30, 14, 15, 30, 0, 1, 174, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 30, + 30, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 68, 69, 25, 71, 69, 1, 71, 30, 4, 5, + 6, 7, 8, 9, 10, 11, 30, 30, 14, 15, + 16, 14, 143, 144, 145, 68, 69, 30, 71, 25, + 151, 25, 153, 1, 30, 30, 31, 32, 31, 32, + 161, 30, 31, 32, 13, 30, 25, 14, 32, 30, + 30, 33, 30, 30, 30, 30, 30, 30, 30, 29, + 67, 109, 60, -1, -1, -1, -1, -1, -1, 40 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 36, 37, 0, 1, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 25, 30, 38, 39, 41, 42, 43, + 44, 50, 51, 53, 57, 59, 61, 62, 64, 66, + 67, 68, 75, 30, 25, 26, 74, 74, 30, 74, + 25, 80, 30, 74, 25, 25, 25, 26, 29, 34, + 78, 79, 30, 1, 1, 45, 45, 54, 56, 60, + 71, 65, 71, 30, 76, 30, 30, 30, 30, 30, + 30, 78, 78, 31, 32, 76, 27, 33, 30, 30, + 1, 12, 16, 18, 19, 20, 21, 22, 23, 25, + 30, 40, 46, 47, 69, 70, 72, 17, 18, 19, + 20, 30, 40, 55, 70, 72, 39, 52, 75, 39, + 53, 58, 64, 75, 30, 40, 72, 39, 53, 63, + 64, 75, 30, 28, 78, 78, 79, 79, 30, 30, + 24, 74, 73, 74, 78, 25, 79, 48, 1, 13, + 30, 74, 73, 25, 78, 14, 77, 30, 77, 77, + 77, 79, 25, 30, 30, 77, 30, 77, 30, 78, + 30, 30, 30, 77, 33, 49, 30, 30, 30, 74 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 51: /* "choice_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 57: /* "if_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 62: /* "menu_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 8: + + { zconf_error("unexpected end statement"); ;} + break; + + case 9: + + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;} + break; + + case 10: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); +;} + break; + + case 11: + + { zconf_error("invalid statement"); ;} + break; + + case 25: + + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;} + break; + + case 26: + + { zconf_error("invalid option"); ;} + break; + + case 27: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +;} + break; + + case 28: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 29: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +;} + break; + + case 30: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 38: + + { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); +;} + break; + + case 39: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 40: + + { + menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); + if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[(1) - (4)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (4)].id)->stype); +;} + break; + + case 41: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 42: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 45: + + { + struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, (yyvsp[(3) - (3)].string)); + else + zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); + free((yyvsp[(2) - (3)].string)); +;} + break; + + case 46: + + { (yyval.string) = NULL; ;} + break; + + case 47: + + { (yyval.string) = (yyvsp[(2) - (2)].string); ;} + break; + + case 48: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 49: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 50: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 58: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 59: + + { + if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); + } else + YYERROR; +;} + break; + + case 60: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 61: + + { + if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +;} + break; + + case 64: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[(2) - (3)].expr)); + (yyval.menu) = menu_add_menu(); +;} + break; + + case 65: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 71: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 72: + + { + (yyval.menu) = menu_add_menu(); +;} + break; + + case 73: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +;} + break; + + case 79: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); + zconf_nextfile((yyvsp[(2) - (3)].string)); +;} + break; + + case 80: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 81: + + { + menu_end_entry(); +;} + break; + + case 82: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +;} + break; + + case 83: + + { + current_entry->help = (yyvsp[(2) - (2)].string); +;} + break; + + case 88: + + { + menu_add_dep((yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 90: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); +;} + break; + + case 93: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 94: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 95: + + { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + break; + + case 98: + + { (yyval.expr) = NULL; ;} + break; + + case 99: + + { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;} + break; + + case 100: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;} + break; + + case 101: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + break; + + case 102: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + break; + + case 103: + + { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;} + break; + + case 104: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;} + break; + + case 105: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + break; + + case 106: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + break; + + case 107: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;} + break; + + case 108: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;} + break; + + case 109: + + { (yyval.string) = NULL; ;} + break; + + +/* Line 1267 of yacc.c. */ + + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + menu_init(); + modules_sym = sym_lookup(NULL, 0); + modules_sym->type = S_BOOLEAN; + modules_sym->flags |= SYMBOL_AUTO; + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +#if YYDEBUG + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +#endif + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym->prop) { + struct property *prop; + + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); + } + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + } + return ""; +} + +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +#if YYDEBUG + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +#endif +} + +void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "choice\n"); + else + fprintf(out, "config %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } + fputc('\n', out); +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + fputs("\n", out); + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "lex.zconf.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + diff --git a/config/zconf.y b/config/zconf.y new file mode 100644 index 000000000..9710b8246 --- /dev/null +++ b/config/zconf.y @@ -0,0 +1,706 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +#include "zconf.hash.c" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[257]; + +static struct menu *current_menu, *current_entry; + +#define YYDEBUG 0 +#if YYDEBUG +#define YYERROR_VERBOSE +#endif +%} +%expect 26 + +%union +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + struct kconf_id *id; +} + +%token T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_OPTION +%token T_ON +%token T_WORD +%token T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type symbol_option_arg word_opt + +%destructor { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + $$->file->name, $$->lineno); + if (current_menu == $$) + menu_end_menu(); +} if_entry menu_entry choice_entry + +%% +input: stmt_list; + +stmt_list: + /* empty */ + | stmt_list common_stmt + | stmt_list choice_stmt + | stmt_list menu_stmt + | stmt_list T_MAINMENU prompt nl + | stmt_list end { zconf_error("unexpected end statement"); } + | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } + | stmt_list option_name error T_EOL +{ + zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} + | stmt_list error T_EOL { zconf_error("invalid statement"); } +; + +option_name: + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT +; + +common_stmt: + T_EOL + | if_stmt + | comment_stmt + | config_stmt + | menuconfig_stmt + | source_stmt +; + +option_error: + T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } + | error T_EOL { zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: + /* empty */ + | config_option_list config_option + | config_option_list symbol_option + | config_option_list depends + | config_option_list help + | config_option_list option_error + | config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + if ($1->stype != S_UNKNOWN) + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: + /* empty */ + | symbol_option_list T_WORD symbol_option_arg +{ + struct kconf_id *id = kconf_id_lookup($2, strlen($2)); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, $3); + else + zconfprint("warning: ignoring unknown option %s", $2); + free($2); +}; + +symbol_option_arg: + /* empty */ { $$ = NULL; } + | T_EQUAL prompt { $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ + struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ + $$ = menu_add_menu(); +}; + +choice_end: end +{ + if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: + /* empty */ + | choice_option_list choice_option + | choice_option_list depends + | choice_option_list help + | choice_option_list T_EOL + | choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ + if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); + } else + YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ + if ($1->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +}; + +choice_block: + /* empty */ + | choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep($2); + $$ = menu_add_menu(); +}; + +if_end: end +{ + if (zconf_endtoken($1, T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +}; + +if_stmt: if_entry if_block if_end +; + +if_block: + /* empty */ + | if_block common_stmt + | if_block menu_stmt + | if_block choice_stmt +; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_MENU, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu depends_list +{ + $$ = menu_add_menu(); +}; + +menu_end: end +{ + if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: + /* empty */ + | menu_block common_stmt + | menu_block menu_stmt + | menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ + menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ + current_entry->help = $2; +}; + +/* depends option */ + +depends_list: + /* empty */ + | depends_list depends + | depends_list T_EOL + | depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ + menu_add_dep($3); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* prompt statement */ + +prompt_stmt_opt: + /* empty */ + | prompt if_expr +{ + menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt: T_WORD + | T_WORD_QUOTE +; + +end: T_ENDMENU T_EOL { $$ = $1; } + | T_ENDCHOICE T_EOL { $$ = $1; } + | T_ENDIF T_EOL { $$ = $1; } +; + +nl: + T_EOL + | nl T_EOL +; + +if_expr: /* empty */ { $$ = NULL; } + | T_IF expr { $$ = $2; } +; + +expr: symbol { $$ = expr_alloc_symbol($1); } + | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } + | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } + | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } + | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } + | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } + | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } + | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */ { $$ = NULL; } + | T_WORD + +%% + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + menu_init(); + modules_sym = sym_lookup(NULL, 0); + modules_sym->type = S_BOOLEAN; + modules_sym->flags |= SYMBOL_AUTO; + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +#if YYDEBUG + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +#endif + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym->prop) { + struct property *prop; + + prop = prop_alloc(P_DEFAULT, modules_sym); + prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); + } + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + } + return ""; +} + +static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +#if YYDEBUG + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +#endif +} + +void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "choice\n"); + else + fprintf(out, "config %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } + fputc('\n', out); +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + fputs("\n", out); + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "lex.zconf.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" -- cgit v1.2.3 From 8975933179908dbff352d01018b5fbbf60d6c0d9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 13:44:10 +0200 Subject: make new mconf compile and update .gitignore --- .gitignore | 4 ++++ config/Makefile | 16 +++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 931ccdf1e..a42417b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ config/conf +config/lex.backup config/lex.zconf.c config/lkc_defs.h config/mconf +config/zconf.hash.c +config/zconf.output config/zconf.tab.c config/zconf.tab.h prereq.mk @@ -15,6 +18,7 @@ root_*/ bin_*/ build_*/ config/*.o +config/lxdialog/*.o make.log dl/ package/*/info.mk diff --git a/config/Makefile b/config/Makefile index 1f6debc8f..ae7a293dd 100644 --- a/config/Makefile +++ b/config/Makefile @@ -36,9 +36,9 @@ endif endif CONF_SRC =conf.c -MCONF_SRC =mconf.c checklist.c menubox.c textbox.c yesno.c inputbox.c util.c msgbox.c -SHARED_SRC=zconf.tab.c glob.c -SHARED_DEPS:=lkc.h lkc_proto.h lkc_defs.h expr.h zconf.tab.h glob.h +MCONF_SRC =mconf.c $(wildcard lxdialog/*.c) +SHARED_SRC=zconf.tab.c +SHARED_DEPS:=lkc.h lkc_proto.h lkc_defs.h expr.h zconf.tab.h CONF_OBJS =$(patsubst %.c,%.o, $(CONF_SRC)) MCONF_OBJS=$(patsubst %.c,%.o, $(MCONF_SRC)) SHARED_OBJS=$(patsubst %.c,%.o, $(SHARED_SRC)) @@ -72,13 +72,16 @@ ifdef LKC_GENPARSER %.tab.c %.tab.h: %.y bison -t -d -v -b $* -p $(notdir $*) $< +%.hash.c: %.gperf + gperf < $< > $@ + lex.%.c: %.l flex -P$(notdir $*) -o$@ $< lex.zconf.o: lex.zconf.c $(SHARED_DEPS) $(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@ -zconf.tab.o: zconf.tab.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(SHARED_DEPS) +zconf.tab.o: zconf.tab.c zconf.hash.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(SHARED_DEPS) $(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@ else @@ -89,7 +92,10 @@ lex.zconf.o: lex.zconf.c $(SHARED_DEPS) lex.zconf.c: lex.zconf.c_shipped $(CP) lex.zconf.c_shipped lex.zconf.c -zconf.tab.o: zconf.tab.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(SHARED_DEPS) +zconf.hash.c: zconf.hash.c_shipped + $(CP) zconf.hash.c_shipped zconf.hash.c + +zconf.tab.o: zconf.tab.c zconf.hash.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(SHARED_DEPS) $(HOSTCC) $(HOSTCFLAGS) -I. -c $< -o $@ zconf.tab.c: zconf.tab.c_shipped -- cgit v1.2.3 From 6645191ee698b1a928f898b6cd90b73b98979028 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 13:50:15 +0200 Subject: drop the CONFIG_ prefixing for .config --- config/confdata.c | 55 +++++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/config/confdata.c b/config/confdata.c index a04da3459..7cc195cbd 100644 --- a/config/confdata.c +++ b/config/confdata.c @@ -219,22 +219,20 @@ load: sym = NULL; switch (line[0]) { case '#': - if (memcmp(line + 2, "CONFIG_", 7)) - continue; - p = strchr(line + 9, ' '); + p = strchr(line + 2, ' '); if (!p) continue; *p++ = 0; if (strncmp(p, "is not set", 10)) continue; if (def == S_DEF_USER) { - sym = sym_find(line + 9); + sym = sym_find(line + 2); if (!sym) { sym_add_change_count(1); break; } } else { - sym = sym_lookup(line + 9, 0); + sym = sym_lookup(line + 2, 0); if (sym->type == S_UNKNOWN) sym->type = S_BOOLEAN; } @@ -251,12 +249,8 @@ load: ; } break; - case 'C': - if (memcmp(line, "CONFIG_", 7)) { - conf_warning("unexpected data"); - continue; - } - p = strchr(line + 7, '='); + default: + p = strchr(line, '='); if (!p) continue; *p++ = 0; @@ -267,13 +261,13 @@ load: *p2 = 0; } if (def == S_DEF_USER) { - sym = sym_find(line + 7); + sym = sym_find(line); if (!sym) { sym_add_change_count(1); break; } } else { - sym = sym_lookup(line + 7, 0); + sym = sym_lookup(line, 0); if (sym->type == S_UNKNOWN) sym->type = S_OTHER; } @@ -286,9 +280,6 @@ load: case '\r': case '\n': break; - default: - conf_warning("unexpected data"); - continue; } if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); @@ -489,19 +480,19 @@ int conf_write(const char *name) case S_TRISTATE: switch (sym_get_tristate_value(sym)) { case no: - fprintf(out, "# CONFIG_%s is not set\n", sym->name); + fprintf(out, "# %s is not set\n", sym->name); break; case mod: - fprintf(out, "CONFIG_%s=m\n", sym->name); + fprintf(out, "%s=m\n", sym->name); break; case yes: - fprintf(out, "CONFIG_%s=y\n", sym->name); + fprintf(out, "%s=y\n", sym->name); break; } break; case S_STRING: str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%s=\"", sym->name); + fprintf(out, "%s=\"", sym->name); while (1) { l = strcspn(str, "\"\\"); if (l) { @@ -517,12 +508,12 @@ int conf_write(const char *name) case S_HEX: str = sym_get_string_value(sym); if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { - fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out, "%s=%s\n", sym->name, str); break; } case S_INT: str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out, "%s=%s\n", sym->name, str); break; } } @@ -726,19 +717,19 @@ int conf_write_autoconf(void) case no: break; case mod: - fprintf(out, "CONFIG_%s=m\n", sym->name); - fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); + fprintf(out, "%s=m\n", sym->name); + fprintf(out_h, "#define %s_MODULE 1\n", sym->name); break; case yes: - fprintf(out, "CONFIG_%s=y\n", sym->name); - fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); + fprintf(out, "%s=y\n", sym->name); + fprintf(out_h, "#define %s 1\n", sym->name); break; } break; case S_STRING: str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%s=\"", sym->name); - fprintf(out_h, "#define CONFIG_%s \"", sym->name); + fprintf(out, "%s=\"", sym->name); + fprintf(out_h, "#define %s \"", sym->name); while (1) { l = strcspn(str, "\"\\"); if (l) { @@ -758,14 +749,14 @@ int conf_write_autoconf(void) case S_HEX: str = sym_get_string_value(sym); if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { - fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); + fprintf(out, "%s=%s\n", sym->name, str); + fprintf(out_h, "#define %s 0x%s\n", sym->name, str); break; } case S_INT: str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); + fprintf(out, "%s=%s\n", sym->name, str); + fprintf(out_h, "#define %s %s\n", sym->name, str); break; default: break; -- cgit v1.2.3 From 6797b1d93206b3615a22fb003f7d656a041549b9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 14:05:31 +0200 Subject: drop dead code formerly used for qt and gtk support in mconf --- config/POTFILES.in | 12 - config/gconf.c | 1632 ------------------------------------------------ config/gconf.glade | 648 ------------------- config/qconf.cc | 1765 ---------------------------------------------------- config/qconf.h | 334 ---------- 5 files changed, 4391 deletions(-) delete mode 100644 config/POTFILES.in delete mode 100644 config/gconf.c delete mode 100644 config/gconf.glade delete mode 100644 config/qconf.cc delete mode 100644 config/qconf.h diff --git a/config/POTFILES.in b/config/POTFILES.in deleted file mode 100644 index 967457396..000000000 --- a/config/POTFILES.in +++ /dev/null @@ -1,12 +0,0 @@ -scripts/kconfig/lxdialog/checklist.c -scripts/kconfig/lxdialog/inputbox.c -scripts/kconfig/lxdialog/menubox.c -scripts/kconfig/lxdialog/textbox.c -scripts/kconfig/lxdialog/util.c -scripts/kconfig/lxdialog/yesno.c -scripts/kconfig/mconf.c -scripts/kconfig/conf.c -scripts/kconfig/confdata.c -scripts/kconfig/gconf.c -scripts/kconfig/gconf.glade.h -scripts/kconfig/qconf.cc diff --git a/config/gconf.c b/config/gconf.c deleted file mode 100644 index 199b22bb4..000000000 --- a/config/gconf.c +++ /dev/null @@ -1,1632 +0,0 @@ -/* Hey EMACS -*- linux-c -*- */ -/* - * - * Copyright (C) 2002-2003 Romain Lievin - * Released under the terms of the GNU GPL v2.0. - * - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "lkc.h" -#include "images.c" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -//#define DEBUG - -enum { - SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW -}; - -static gint view_mode = FULL_VIEW; -static gboolean show_name = TRUE; -static gboolean show_range = TRUE; -static gboolean show_value = TRUE; -static gboolean show_all = FALSE; -static gboolean show_debug = FALSE; -static gboolean resizeable = FALSE; - -GtkWidget *main_wnd = NULL; -GtkWidget *tree1_w = NULL; // left frame -GtkWidget *tree2_w = NULL; // right frame -GtkWidget *text_w = NULL; -GtkWidget *hpaned = NULL; -GtkWidget *vpaned = NULL; -GtkWidget *back_btn = NULL; -GtkWidget *save_btn = NULL; -GtkWidget *save_menu_item = NULL; - -GtkTextTag *tag1, *tag2; -GdkColor color; - -GtkTreeStore *tree1, *tree2, *tree; -GtkTreeModel *model1, *model2; -static GtkTreeIter *parents[256]; -static gint indent; - -static struct menu *current; // current node for SINGLE view -static struct menu *browsed; // browsed node for SPLIT view - -enum { - COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, - COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, - COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, - COL_NUMBER -}; - -static void display_list(void); -static void display_tree(struct menu *menu); -static void display_tree_part(void); -static void update_tree(struct menu *src, GtkTreeIter * dst); -static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); -static gchar **fill_row(struct menu *menu); -static void conf_changed(void); - -/* Helping/Debugging Functions */ - - -const char *dbg_print_stype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == S_UNKNOWN) - strcpy(buf, "unknown"); - if (val == S_BOOLEAN) - strcpy(buf, "boolean"); - if (val == S_TRISTATE) - strcpy(buf, "tristate"); - if (val == S_INT) - strcpy(buf, "int"); - if (val == S_HEX) - strcpy(buf, "hex"); - if (val == S_STRING) - strcpy(buf, "string"); - if (val == S_OTHER) - strcpy(buf, "other"); - -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_flags(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val & SYMBOL_CONST) - strcat(buf, "const/"); - if (val & SYMBOL_CHECK) - strcat(buf, "check/"); - if (val & SYMBOL_CHOICE) - strcat(buf, "choice/"); - if (val & SYMBOL_CHOICEVAL) - strcat(buf, "choiceval/"); - if (val & SYMBOL_VALID) - strcat(buf, "valid/"); - if (val & SYMBOL_OPTIONAL) - strcat(buf, "optional/"); - if (val & SYMBOL_WRITE) - strcat(buf, "write/"); - if (val & SYMBOL_CHANGED) - strcat(buf, "changed/"); - if (val & SYMBOL_AUTO) - strcat(buf, "auto/"); - - buf[strlen(buf) - 1] = '\0'; -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_ptype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == P_UNKNOWN) - strcpy(buf, "unknown"); - if (val == P_PROMPT) - strcpy(buf, "prompt"); - if (val == P_COMMENT) - strcpy(buf, "comment"); - if (val == P_MENU) - strcpy(buf, "menu"); - if (val == P_DEFAULT) - strcpy(buf, "default"); - if (val == P_CHOICE) - strcpy(buf, "choice"); - -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - - -void replace_button_icon(GladeXML * xml, GdkDrawable * window, - GtkStyle * style, gchar * btn_name, gchar ** xpm) -{ - GdkPixmap *pixmap; - GdkBitmap *mask; - GtkToolButton *button; - GtkWidget *image; - - pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, - &style->bg[GTK_STATE_NORMAL], - xpm); - - button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); - image = gtk_image_new_from_pixmap(pixmap, mask); - gtk_widget_show(image); - gtk_tool_button_set_icon_widget(button, image); -} - -/* Main Window Initialization */ -void init_main_window(const gchar * glade_file) -{ - GladeXML *xml; - GtkWidget *widget; - GtkTextBuffer *txtbuf; - char title[256]; - GtkStyle *style; - - xml = glade_xml_new(glade_file, "window1", NULL); - if (!xml) - g_error(_("GUI loading failed !\n")); - glade_xml_signal_autoconnect(xml); - - main_wnd = glade_xml_get_widget(xml, "window1"); - hpaned = glade_xml_get_widget(xml, "hpaned1"); - vpaned = glade_xml_get_widget(xml, "vpaned1"); - tree1_w = glade_xml_get_widget(xml, "treeview1"); - tree2_w = glade_xml_get_widget(xml, "treeview2"); - text_w = glade_xml_get_widget(xml, "textview3"); - - back_btn = glade_xml_get_widget(xml, "button1"); - gtk_widget_set_sensitive(back_btn, FALSE); - - widget = glade_xml_get_widget(xml, "show_name1"); - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, - show_name); - - widget = glade_xml_get_widget(xml, "show_range1"); - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, - show_range); - - widget = glade_xml_get_widget(xml, "show_data1"); - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, - show_value); - - save_btn = glade_xml_get_widget(xml, "button3"); - save_menu_item = glade_xml_get_widget(xml, "save1"); - conf_set_changed_callback(conf_changed); - - style = gtk_widget_get_style(main_wnd); - widget = glade_xml_get_widget(xml, "toolbar1"); - -#if 0 /* Use stock Gtk icons instead */ - replace_button_icon(xml, main_wnd->window, style, - "button1", (gchar **) xpm_back); - replace_button_icon(xml, main_wnd->window, style, - "button2", (gchar **) xpm_load); - replace_button_icon(xml, main_wnd->window, style, - "button3", (gchar **) xpm_save); -#endif - replace_button_icon(xml, main_wnd->window, style, - "button4", (gchar **) xpm_single_view); - replace_button_icon(xml, main_wnd->window, style, - "button5", (gchar **) xpm_split_view); - replace_button_icon(xml, main_wnd->window, style, - "button6", (gchar **) xpm_tree_view); - -#if 0 - switch (view_mode) { - case SINGLE_VIEW: - widget = glade_xml_get_widget(xml, "button4"); - g_signal_emit_by_name(widget, "clicked"); - break; - case SPLIT_VIEW: - widget = glade_xml_get_widget(xml, "button5"); - g_signal_emit_by_name(widget, "clicked"); - break; - case FULL_VIEW: - widget = glade_xml_get_widget(xml, "button6"); - g_signal_emit_by_name(widget, "clicked"); - break; - } -#endif - txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); - tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", - "foreground", "red", - "weight", PANGO_WEIGHT_BOLD, - NULL); - tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", - /*"style", PANGO_STYLE_OBLIQUE, */ - NULL); - - sprintf(title, _("Linux Kernel v%s Configuration"), - getenv("KERNELVERSION")); - gtk_window_set_title(GTK_WINDOW(main_wnd), title); - - gtk_widget_show(main_wnd); -} - -void init_tree_model(void) -{ - gint i; - - tree = tree2 = gtk_tree_store_new(COL_NUMBER, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER, GDK_TYPE_COLOR, - G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN); - model2 = GTK_TREE_MODEL(tree2); - - for (parents[0] = NULL, i = 1; i < 256; i++) - parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); - - tree1 = gtk_tree_store_new(COL_NUMBER, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER, GDK_TYPE_COLOR, - G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN); - model1 = GTK_TREE_MODEL(tree1); -} - -void init_left_tree(void) -{ - GtkTreeView *view = GTK_TREE_VIEW(tree1_w); - GtkCellRenderer *renderer; - GtkTreeSelection *sel; - GtkTreeViewColumn *column; - - gtk_tree_view_set_model(view, model1); - gtk_tree_view_set_headers_visible(view, TRUE); - gtk_tree_view_set_rules_hint(view, FALSE); - - column = gtk_tree_view_column_new(); - gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, _("Options")); - - renderer = gtk_cell_renderer_toggle_new(); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), - renderer, FALSE); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), - renderer, - "active", COL_BTNACT, - "inconsistent", COL_BTNINC, - "visible", COL_BTNVIS, - "radio", COL_BTNRAD, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), - renderer, FALSE); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), - renderer, - "text", COL_OPTION, - "foreground-gdk", - COL_COLOR, NULL); - - sel = gtk_tree_view_get_selection(view); - gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); - gtk_widget_realize(tree1_w); -} - -static void renderer_edited(GtkCellRendererText * cell, - const gchar * path_string, - const gchar * new_text, gpointer user_data); -static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle, - gchar * arg1, gpointer user_data); - -void init_right_tree(void) -{ - GtkTreeView *view = GTK_TREE_VIEW(tree2_w); - GtkCellRenderer *renderer; - GtkTreeSelection *sel; - GtkTreeViewColumn *column; - gint i; - - gtk_tree_view_set_model(view, model2); - gtk_tree_view_set_headers_visible(view, TRUE); - gtk_tree_view_set_rules_hint(view, FALSE); - - column = gtk_tree_view_column_new(); - gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, _("Options")); - - renderer = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), - renderer, FALSE); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), - renderer, - "pixbuf", COL_PIXBUF, - "visible", COL_PIXVIS, NULL); - renderer = gtk_cell_renderer_toggle_new(); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), - renderer, FALSE); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), - renderer, - "active", COL_BTNACT, - "inconsistent", COL_BTNINC, - "visible", COL_BTNVIS, - "radio", COL_BTNRAD, NULL); - /*g_signal_connect(G_OBJECT(renderer), "toggled", - G_CALLBACK(renderer_toggled), NULL); */ - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), - renderer, FALSE); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), - renderer, - "text", COL_OPTION, - "foreground-gdk", - COL_COLOR, NULL); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(view, -1, - _("Name"), renderer, - "text", COL_NAME, - "foreground-gdk", - COL_COLOR, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(view, -1, - "N", renderer, - "text", COL_NO, - "foreground-gdk", - COL_COLOR, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(view, -1, - "M", renderer, - "text", COL_MOD, - "foreground-gdk", - COL_COLOR, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(view, -1, - "Y", renderer, - "text", COL_YES, - "foreground-gdk", - COL_COLOR, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes(view, -1, - _("Value"), renderer, - "text", COL_VALUE, - "editable", - COL_EDIT, - "foreground-gdk", - COL_COLOR, NULL); - g_signal_connect(G_OBJECT(renderer), "edited", - G_CALLBACK(renderer_edited), NULL); - - column = gtk_tree_view_get_column(view, COL_NAME); - gtk_tree_view_column_set_visible(column, show_name); - column = gtk_tree_view_get_column(view, COL_NO); - gtk_tree_view_column_set_visible(column, show_range); - column = gtk_tree_view_get_column(view, COL_MOD); - gtk_tree_view_column_set_visible(column, show_range); - column = gtk_tree_view_get_column(view, COL_YES); - gtk_tree_view_column_set_visible(column, show_range); - column = gtk_tree_view_get_column(view, COL_VALUE); - gtk_tree_view_column_set_visible(column, show_value); - - if (resizeable) { - for (i = 0; i < COL_VALUE; i++) { - column = gtk_tree_view_get_column(view, i); - gtk_tree_view_column_set_resizable(column, TRUE); - } - } - - sel = gtk_tree_view_get_selection(view); - gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); -} - - -/* Utility Functions */ - - -static void text_insert_help(struct menu *menu) -{ - GtkTextBuffer *buffer; - GtkTextIter start, end; - const char *prompt = _(menu_get_prompt(menu)); - gchar *name; - const char *help; - - help = menu_get_help(menu); - - /* Gettextize if the help text not empty */ - if ((help != 0) && (help[0] != 0)) - help = _(help); - - if (menu->sym && menu->sym->name) - name = g_strdup_printf(menu->sym->name); - else - name = g_strdup(""); - - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); - gtk_text_buffer_get_bounds(buffer, &start, &end); - gtk_text_buffer_delete(buffer, &start, &end); - gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); - - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, - NULL); - gtk_text_buffer_insert_at_cursor(buffer, " ", 1); - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1, - NULL); - gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2, - NULL); -} - - -static void text_insert_msg(const char *title, const char *message) -{ - GtkTextBuffer *buffer; - GtkTextIter start, end; - const char *msg = message; - - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); - gtk_text_buffer_get_bounds(buffer, &start, &end); - gtk_text_buffer_delete(buffer, &start, &end); - gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); - - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, - NULL); - gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, - NULL); -} - - -/* Main Windows Callbacks */ - -void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); -gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, - gpointer user_data) -{ - GtkWidget *dialog, *label; - gint result; - - if (!conf_get_changed()) - return FALSE; - - dialog = gtk_dialog_new_with_buttons(_("Warning !"), - GTK_WINDOW(main_wnd), - (GtkDialogFlags) - (GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT), - GTK_STOCK_OK, - GTK_RESPONSE_YES, - GTK_STOCK_NO, - GTK_RESPONSE_NO, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, NULL); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), - GTK_RESPONSE_CANCEL); - - label = gtk_label_new(_("\nSave configuration ?\n")); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show(label); - - result = gtk_dialog_run(GTK_DIALOG(dialog)); - switch (result) { - case GTK_RESPONSE_YES: - on_save_activate(NULL, NULL); - return FALSE; - case GTK_RESPONSE_NO: - return FALSE; - case GTK_RESPONSE_CANCEL: - case GTK_RESPONSE_DELETE_EVENT: - default: - gtk_widget_destroy(dialog); - return TRUE; - } - - return FALSE; -} - - -void on_window1_destroy(GtkObject * object, gpointer user_data) -{ - gtk_main_quit(); -} - - -void -on_window1_size_request(GtkWidget * widget, - GtkRequisition * requisition, gpointer user_data) -{ - static gint old_h; - gint w, h; - - if (widget->window == NULL) - gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); - else - gdk_window_get_size(widget->window, &w, &h); - - if (h == old_h) - return; - old_h = h; - - gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); -} - - -/* Menu & Toolbar Callbacks */ - - -static void -load_filename(GtkFileSelection * file_selector, gpointer user_data) -{ - const gchar *fn; - - fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION - (user_data)); - - if (conf_read(fn)) - text_insert_msg(_("Error"), _("Unable to load configuration !")); - else - display_tree(&rootmenu); -} - -void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkWidget *fs; - - fs = gtk_file_selection_new(_("Load file...")); - g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), - "clicked", - G_CALLBACK(load_filename), (gpointer) fs); - g_signal_connect_swapped(GTK_OBJECT - (GTK_FILE_SELECTION(fs)->ok_button), - "clicked", G_CALLBACK(gtk_widget_destroy), - (gpointer) fs); - g_signal_connect_swapped(GTK_OBJECT - (GTK_FILE_SELECTION(fs)->cancel_button), - "clicked", G_CALLBACK(gtk_widget_destroy), - (gpointer) fs); - gtk_widget_show(fs); -} - - -void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - if (conf_write(NULL)) - text_insert_msg(_("Error"), _("Unable to save configuration !")); -} - - -static void -store_filename(GtkFileSelection * file_selector, gpointer user_data) -{ - const gchar *fn; - - fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION - (user_data)); - - if (conf_write(fn)) - text_insert_msg(_("Error"), _("Unable to save configuration !")); - - gtk_widget_destroy(GTK_WIDGET(user_data)); -} - -void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkWidget *fs; - - fs = gtk_file_selection_new(_("Save file as...")); - g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), - "clicked", - G_CALLBACK(store_filename), (gpointer) fs); - g_signal_connect_swapped(GTK_OBJECT - (GTK_FILE_SELECTION(fs)->ok_button), - "clicked", G_CALLBACK(gtk_widget_destroy), - (gpointer) fs); - g_signal_connect_swapped(GTK_OBJECT - (GTK_FILE_SELECTION(fs)->cancel_button), - "clicked", G_CALLBACK(gtk_widget_destroy), - (gpointer) fs); - gtk_widget_show(fs); -} - - -void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - if (!on_window1_delete_event(NULL, NULL, NULL)) - gtk_widget_destroy(GTK_WIDGET(main_wnd)); -} - - -void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkTreeViewColumn *col; - - show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); - if (col) - gtk_tree_view_column_set_visible(col, show_name); -} - - -void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkTreeViewColumn *col; - - show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); - if (col) - gtk_tree_view_column_set_visible(col, show_range); - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); - if (col) - gtk_tree_view_column_set_visible(col, show_range); - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); - if (col) - gtk_tree_view_column_set_visible(col, show_range); - -} - - -void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkTreeViewColumn *col; - - show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); - if (col) - gtk_tree_view_column_set_visible(col, show_value); -} - - -void -on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - show_all = GTK_CHECK_MENU_ITEM(menuitem)->active; - - gtk_tree_store_clear(tree2); - display_tree(&rootmenu); // instead of update_tree to speed-up -} - - -void -on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active; - update_tree(&rootmenu, NULL); -} - - -void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkWidget *dialog; - const gchar *intro_text = _( - "Welcome to gkc, the GTK+ graphical kernel configuration tool\n" - "for Linux.\n" - "For each option, a blank box indicates the feature is disabled, a\n" - "check indicates it is enabled, and a dot indicates that it is to\n" - "be compiled as a module. Clicking on the box will cycle through the three states.\n" - "\n" - "If you do not see an option (e.g., a device driver) that you\n" - "believe should be present, try turning on Show All Options\n" - "under the Options menu.\n" - "Although there is no cross reference yet to help you figure out\n" - "what other options must be enabled to support the option you\n" - "are interested in, you can still view the help of a grayed-out\n" - "option.\n" - "\n" - "Toggling Show Debug Info under the Options menu will show \n" - "the dependencies, which you can then match by examining other options."); - - dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, intro_text); - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", - G_CALLBACK(gtk_widget_destroy), - GTK_OBJECT(dialog)); - gtk_widget_show_all(dialog); -} - - -void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkWidget *dialog; - const gchar *about_text = - _("gkc is copyright (c) 2002 Romain Lievin .\n" - "Based on the source code from Roman Zippel.\n"); - - dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, about_text); - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", - G_CALLBACK(gtk_widget_destroy), - GTK_OBJECT(dialog)); - gtk_widget_show_all(dialog); -} - - -void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - GtkWidget *dialog; - const gchar *license_text = - _("gkc is released under the terms of the GNU GPL v2.\n" - "For more information, please see the source code or\n" - "visit http://www.fsf.org/licenses/licenses.html\n"); - - dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, license_text); - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", - G_CALLBACK(gtk_widget_destroy), - GTK_OBJECT(dialog)); - gtk_widget_show_all(dialog); -} - - -void on_back_clicked(GtkButton * button, gpointer user_data) -{ - enum prop_type ptype; - - current = current->parent; - ptype = current->prompt ? current->prompt->type : P_UNKNOWN; - if (ptype != P_MENU) - current = current->parent; - display_tree_part(); - - if (current == &rootmenu) - gtk_widget_set_sensitive(back_btn, FALSE); -} - - -void on_load_clicked(GtkButton * button, gpointer user_data) -{ - on_load1_activate(NULL, user_data); -} - - -void on_single_clicked(GtkButton * button, gpointer user_data) -{ - view_mode = SINGLE_VIEW; - gtk_paned_set_position(GTK_PANED(hpaned), 0); - gtk_widget_hide(tree1_w); - current = &rootmenu; - display_tree_part(); -} - - -void on_split_clicked(GtkButton * button, gpointer user_data) -{ - gint w, h; - view_mode = SPLIT_VIEW; - gtk_widget_show(tree1_w); - gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); - gtk_paned_set_position(GTK_PANED(hpaned), w / 2); - if (tree2) - gtk_tree_store_clear(tree2); - display_list(); - - /* Disable back btn, like in full mode. */ - gtk_widget_set_sensitive(back_btn, FALSE); -} - - -void on_full_clicked(GtkButton * button, gpointer user_data) -{ - view_mode = FULL_VIEW; - gtk_paned_set_position(GTK_PANED(hpaned), 0); - gtk_widget_hide(tree1_w); - if (tree2) - gtk_tree_store_clear(tree2); - display_tree(&rootmenu); - gtk_widget_set_sensitive(back_btn, FALSE); -} - - -void on_collapse_clicked(GtkButton * button, gpointer user_data) -{ - gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); -} - - -void on_expand_clicked(GtkButton * button, gpointer user_data) -{ - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); -} - - -/* CTree Callbacks */ - -/* Change hex/int/string value in the cell */ -static void renderer_edited(GtkCellRendererText * cell, - const gchar * path_string, - const gchar * new_text, gpointer user_data) -{ - GtkTreePath *path = gtk_tree_path_new_from_string(path_string); - GtkTreeIter iter; - const char *old_def, *new_def; - struct menu *menu; - struct symbol *sym; - - if (!gtk_tree_model_get_iter(model2, &iter, path)) - return; - - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); - sym = menu->sym; - - gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); - new_def = new_text; - - sym_set_string_value(sym, new_def); - - update_tree(&rootmenu, NULL); - - gtk_tree_path_free(path); -} - -/* Change the value of a symbol and update the tree */ -static void change_sym_value(struct menu *menu, gint col) -{ - struct symbol *sym = menu->sym; - tristate oldval, newval; - - if (!sym) - return; - - if (col == COL_NO) - newval = no; - else if (col == COL_MOD) - newval = mod; - else if (col == COL_YES) - newval = yes; - else - return; - - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - oldval = sym_get_tristate_value(sym); - if (!sym_tristate_within_range(sym, newval)) - newval = yes; - sym_set_tristate_value(sym, newval); - if (view_mode == FULL_VIEW) - update_tree(&rootmenu, NULL); - else if (view_mode == SPLIT_VIEW) { - update_tree(browsed, NULL); - display_list(); - } - else if (view_mode == SINGLE_VIEW) - display_tree_part(); //fixme: keep exp/coll - break; - case S_INT: - case S_HEX: - case S_STRING: - default: - break; - } -} - -static void toggle_sym_value(struct menu *menu) -{ - if (!menu->sym) - return; - - sym_toggle_tristate_value(menu->sym); - if (view_mode == FULL_VIEW) - update_tree(&rootmenu, NULL); - else if (view_mode == SPLIT_VIEW) { - update_tree(browsed, NULL); - display_list(); - } - else if (view_mode == SINGLE_VIEW) - display_tree_part(); //fixme: keep exp/coll -} - -static void renderer_toggled(GtkCellRendererToggle * cell, - gchar * path_string, gpointer user_data) -{ - GtkTreePath *path, *sel_path = NULL; - GtkTreeIter iter, sel_iter; - GtkTreeSelection *sel; - struct menu *menu; - - path = gtk_tree_path_new_from_string(path_string); - if (!gtk_tree_model_get_iter(model2, &iter, path)) - return; - - sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w)); - if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter)) - sel_path = gtk_tree_model_get_path(model2, &sel_iter); - if (!sel_path) - goto out1; - if (gtk_tree_path_compare(path, sel_path)) - goto out2; - - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); - toggle_sym_value(menu); - - out2: - gtk_tree_path_free(sel_path); - out1: - gtk_tree_path_free(path); -} - -static gint column2index(GtkTreeViewColumn * column) -{ - gint i; - - for (i = 0; i < COL_NUMBER; i++) { - GtkTreeViewColumn *col; - - col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); - if (col == column) - return i; - } - - return -1; -} - - -/* User click: update choice (full) or goes down (single) */ -gboolean -on_treeview2_button_press_event(GtkWidget * widget, - GdkEventButton * event, gpointer user_data) -{ - GtkTreeView *view = GTK_TREE_VIEW(widget); - GtkTreePath *path; - GtkTreeViewColumn *column; - GtkTreeIter iter; - struct menu *menu; - gint col; - -#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK - gint tx = (gint) event->x; - gint ty = (gint) event->y; - gint cx, cy; - - gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, - &cy); -#else - gtk_tree_view_get_cursor(view, &path, &column); -#endif - if (path == NULL) - return FALSE; - - if (!gtk_tree_model_get_iter(model2, &iter, path)) - return FALSE; - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); - - col = column2index(column); - if (event->type == GDK_2BUTTON_PRESS) { - enum prop_type ptype; - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - - if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { - // goes down into menu - current = menu; - display_tree_part(); - gtk_widget_set_sensitive(back_btn, TRUE); - } else if ((col == COL_OPTION)) { - toggle_sym_value(menu); - gtk_tree_view_expand_row(view, path, TRUE); - } - } else { - if (col == COL_VALUE) { - toggle_sym_value(menu); - gtk_tree_view_expand_row(view, path, TRUE); - } else if (col == COL_NO || col == COL_MOD - || col == COL_YES) { - change_sym_value(menu, col); - gtk_tree_view_expand_row(view, path, TRUE); - } - } - - return FALSE; -} - -/* Key pressed: update choice */ -gboolean -on_treeview2_key_press_event(GtkWidget * widget, - GdkEventKey * event, gpointer user_data) -{ - GtkTreeView *view = GTK_TREE_VIEW(widget); - GtkTreePath *path; - GtkTreeViewColumn *column; - GtkTreeIter iter; - struct menu *menu; - gint col; - - gtk_tree_view_get_cursor(view, &path, &column); - if (path == NULL) - return FALSE; - - if (event->keyval == GDK_space) { - if (gtk_tree_view_row_expanded(view, path)) - gtk_tree_view_collapse_row(view, path); - else - gtk_tree_view_expand_row(view, path, FALSE); - return TRUE; - } - if (event->keyval == GDK_KP_Enter) { - } - if (widget == tree1_w) - return FALSE; - - gtk_tree_model_get_iter(model2, &iter, path); - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); - - if (!strcasecmp(event->string, "n")) - col = COL_NO; - else if (!strcasecmp(event->string, "m")) - col = COL_MOD; - else if (!strcasecmp(event->string, "y")) - col = COL_YES; - else - col = -1; - change_sym_value(menu, col); - - return FALSE; -} - - -/* Row selection changed: update help */ -void -on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) -{ - GtkTreeSelection *selection; - GtkTreeIter iter; - struct menu *menu; - - selection = gtk_tree_view_get_selection(treeview); - if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); - text_insert_help(menu); - } -} - - -/* User click: display sub-tree in the right frame. */ -gboolean -on_treeview1_button_press_event(GtkWidget * widget, - GdkEventButton * event, gpointer user_data) -{ - GtkTreeView *view = GTK_TREE_VIEW(widget); - GtkTreePath *path; - GtkTreeViewColumn *column; - GtkTreeIter iter; - struct menu *menu; - - gint tx = (gint) event->x; - gint ty = (gint) event->y; - gint cx, cy; - - gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, - &cy); - if (path == NULL) - return FALSE; - - gtk_tree_model_get_iter(model1, &iter, path); - gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); - - if (event->type == GDK_2BUTTON_PRESS) { - toggle_sym_value(menu); - current = menu; - display_tree_part(); - } else { - browsed = menu; - display_tree_part(); - } - - gtk_widget_realize(tree2_w); - gtk_tree_view_set_cursor(view, path, NULL, FALSE); - gtk_widget_grab_focus(tree2_w); - - return FALSE; -} - - -/* Fill a row of strings */ -static gchar **fill_row(struct menu *menu) -{ - static gchar *row[COL_NUMBER]; - struct symbol *sym = menu->sym; - const char *def; - int stype; - tristate val; - enum prop_type ptype; - int i; - - for (i = COL_OPTION; i <= COL_COLOR; i++) - g_free(row[i]); - bzero(row, sizeof(row)); - - row[COL_OPTION] = - g_strdup_printf("%s %s", _(menu_get_prompt(menu)), - sym && sym_has_value(sym) ? "(NEW)" : ""); - - if (show_all && !menu_is_visible(menu)) - row[COL_COLOR] = g_strdup("DarkGray"); - else - row[COL_COLOR] = g_strdup("Black"); - - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - switch (ptype) { - case P_MENU: - row[COL_PIXBUF] = (gchar *) xpm_menu; - if (view_mode == SINGLE_VIEW) - row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); - break; - case P_COMMENT: - row[COL_PIXBUF] = (gchar *) xpm_void; - row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); - break; - default: - row[COL_PIXBUF] = (gchar *) xpm_void; - row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); - row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); - break; - } - - if (!sym) - return row; - row[COL_NAME] = g_strdup(sym->name); - - sym_calc_value(sym); - sym->flags &= ~SYMBOL_CHANGED; - - if (sym_is_choice(sym)) { // parse childs for getting final value - struct menu *child; - struct symbol *def_sym = sym_get_choice_value(sym); - struct menu *def_menu = NULL; - - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); - - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child) - && child->sym == def_sym) - def_menu = child; - } - - if (def_menu) - row[COL_VALUE] = - g_strdup(_(menu_get_prompt(def_menu))); - } - if (sym->flags & SYMBOL_CHOICEVAL) - row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); - - stype = sym_get_type(sym); - switch (stype) { - case S_BOOLEAN: - if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) - row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); - if (sym_is_choice(sym)) - break; - case S_TRISTATE: - val = sym_get_tristate_value(sym); - switch (val) { - case no: - row[COL_NO] = g_strdup("N"); - row[COL_VALUE] = g_strdup("N"); - row[COL_BTNACT] = GINT_TO_POINTER(FALSE); - row[COL_BTNINC] = GINT_TO_POINTER(FALSE); - break; - case mod: - row[COL_MOD] = g_strdup("M"); - row[COL_VALUE] = g_strdup("M"); - row[COL_BTNINC] = GINT_TO_POINTER(TRUE); - break; - case yes: - row[COL_YES] = g_strdup("Y"); - row[COL_VALUE] = g_strdup("Y"); - row[COL_BTNACT] = GINT_TO_POINTER(TRUE); - row[COL_BTNINC] = GINT_TO_POINTER(FALSE); - break; - } - - if (val != no && sym_tristate_within_range(sym, no)) - row[COL_NO] = g_strdup("_"); - if (val != mod && sym_tristate_within_range(sym, mod)) - row[COL_MOD] = g_strdup("_"); - if (val != yes && sym_tristate_within_range(sym, yes)) - row[COL_YES] = g_strdup("_"); - break; - case S_INT: - case S_HEX: - case S_STRING: - def = sym_get_string_value(sym); - row[COL_VALUE] = g_strdup(def); - row[COL_EDIT] = GINT_TO_POINTER(TRUE); - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); - break; - } - - return row; -} - - -/* Set the node content with a row of strings */ -static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) -{ - GdkColor color; - gboolean success; - GdkPixbuf *pix; - - pix = gdk_pixbuf_new_from_xpm_data((const char **) - row[COL_PIXBUF]); - - gdk_color_parse(row[COL_COLOR], &color); - gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, - FALSE, FALSE, &success); - - gtk_tree_store_set(tree, node, - COL_OPTION, row[COL_OPTION], - COL_NAME, row[COL_NAME], - COL_NO, row[COL_NO], - COL_MOD, row[COL_MOD], - COL_YES, row[COL_YES], - COL_VALUE, row[COL_VALUE], - COL_MENU, (gpointer) menu, - COL_COLOR, &color, - COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), - COL_PIXBUF, pix, - COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), - COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), - COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), - COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), - COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), - -1); - - g_object_unref(pix); -} - - -/* Add a node to the tree */ -static void place_node(struct menu *menu, char **row) -{ - GtkTreeIter *parent = parents[indent - 1]; - GtkTreeIter *node = parents[indent]; - - gtk_tree_store_append(tree, node, parent); - set_node(node, menu, row); -} - - -/* Find a node in the GTK+ tree */ -static GtkTreeIter found; - -/* - * Find a menu in the GtkTree starting at parent. - */ -GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, - struct menu *tofind) -{ - GtkTreeIter iter; - GtkTreeIter *child = &iter; - gboolean valid; - GtkTreeIter *ret; - - valid = gtk_tree_model_iter_children(model2, child, parent); - while (valid) { - struct menu *menu; - - gtk_tree_model_get(model2, child, 6, &menu, -1); - - if (menu == tofind) { - memcpy(&found, child, sizeof(GtkTreeIter)); - return &found; - } - - ret = gtktree_iter_find_node(child, tofind); - if (ret) - return ret; - - valid = gtk_tree_model_iter_next(model2, child); - } - - return NULL; -} - - -/* - * Update the tree by adding/removing entries - * Does not change other nodes - */ -static void update_tree(struct menu *src, GtkTreeIter * dst) -{ - struct menu *child1; - GtkTreeIter iter, tmp; - GtkTreeIter *child2 = &iter; - gboolean valid; - GtkTreeIter *sibling; - struct symbol *sym; - struct property *prop; - struct menu *menu1, *menu2; - - if (src == &rootmenu) - indent = 1; - - valid = gtk_tree_model_iter_children(model2, child2, dst); - for (child1 = src->list; child1; child1 = child1->next) { - - prop = child1->prompt; - sym = child1->sym; - - reparse: - menu1 = child1; - if (valid) - gtk_tree_model_get(model2, child2, COL_MENU, - &menu2, -1); - else - menu2 = NULL; // force adding of a first child - -#ifdef DEBUG - printf("%*c%s | %s\n", indent, ' ', - menu1 ? menu_get_prompt(menu1) : "nil", - menu2 ? menu_get_prompt(menu2) : "nil"); -#endif - - if (!menu_is_visible(child1) && !show_all) { // remove node - if (gtktree_iter_find_node(dst, menu1) != NULL) { - memcpy(&tmp, child2, sizeof(GtkTreeIter)); - valid = gtk_tree_model_iter_next(model2, - child2); - gtk_tree_store_remove(tree2, &tmp); - if (!valid) - return; // next parent - else - goto reparse; // next child - } else - continue; - } - - if (menu1 != menu2) { - if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node - if (!valid && !menu2) - sibling = NULL; - else - sibling = child2; - gtk_tree_store_insert_before(tree2, - child2, - dst, sibling); - set_node(child2, menu1, fill_row(menu1)); - if (menu2 == NULL) - valid = TRUE; - } else { // remove node - memcpy(&tmp, child2, sizeof(GtkTreeIter)); - valid = gtk_tree_model_iter_next(model2, - child2); - gtk_tree_store_remove(tree2, &tmp); - if (!valid) - return; // next parent - else - goto reparse; // next child - } - } else if (sym && (sym->flags & SYMBOL_CHANGED)) { - set_node(child2, menu1, fill_row(menu1)); - } - - indent++; - update_tree(child1, child2); - indent--; - - valid = gtk_tree_model_iter_next(model2, child2); - } -} - - -/* Display the whole tree (single/split/full view) */ -static void display_tree(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - enum prop_type ptype; - - if (menu == &rootmenu) { - indent = 1; - current = &rootmenu; - } - - for (child = menu->list; child; child = child->next) { - prop = child->prompt; - sym = child->sym; - ptype = prop ? prop->type : P_UNKNOWN; - - if (sym) - sym->flags &= ~SYMBOL_CHANGED; - - if ((view_mode == SPLIT_VIEW) - && !(child->flags & MENU_ROOT) && (tree == tree1)) - continue; - - if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) - && (tree == tree2)) - continue; - - if (menu_is_visible(child) || show_all) - place_node(child, fill_row(child)); -#ifdef DEBUG - printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); - printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); - dbg_print_ptype(ptype); - printf(" | "); - if (sym) { - dbg_print_stype(sym->type); - printf(" | "); - dbg_print_flags(sym->flags); - printf("\n"); - } else - printf("\n"); -#endif - if ((view_mode != FULL_VIEW) && (ptype == P_MENU) - && (tree == tree2)) - continue; -/* - if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) - || (view_mode == FULL_VIEW) - || (view_mode == SPLIT_VIEW))*/ - if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) - || (view_mode == FULL_VIEW) - || (view_mode == SPLIT_VIEW)) { - indent++; - display_tree(child); - indent--; - } - } -} - -/* Display a part of the tree starting at current node (single/split view) */ -static void display_tree_part(void) -{ - if (tree2) - gtk_tree_store_clear(tree2); - if (view_mode == SINGLE_VIEW) - display_tree(current); - else if (view_mode == SPLIT_VIEW) - display_tree(browsed); - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); -} - -/* Display the list in the left frame (split view) */ -static void display_list(void) -{ - if (tree1) - gtk_tree_store_clear(tree1); - - tree = tree1; - display_tree(&rootmenu); - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); - tree = tree2; -} - -void fixup_rootmenu(struct menu *menu) -{ - struct menu *child; - static int menu_cnt = 0; - - menu->flags |= MENU_ROOT; - for (child = menu->list; child; child = child->next) { - if (child->prompt && child->prompt->type == P_MENU) { - menu_cnt++; - fixup_rootmenu(child); - menu_cnt--; - } else if (!menu_cnt) - fixup_rootmenu(child); - } -} - - -/* Main */ -int main(int ac, char *av[]) -{ - const char *name; - char *env; - gchar *glade_file; - -#ifndef LKC_DIRECT_LINK - kconfig_load(); -#endif - - bindtextdomain(PACKAGE, LOCALEDIR); - bind_textdomain_codeset(PACKAGE, "UTF-8"); - textdomain(PACKAGE); - - /* GTK stuffs */ - gtk_set_locale(); - gtk_init(&ac, &av); - glade_init(); - - //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); - //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); - - /* Determine GUI path */ - env = getenv(SRCTREE); - if (env) - glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); - else if (av[0][0] == '/') - glade_file = g_strconcat(av[0], ".glade", NULL); - else - glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); - - /* Load the interface and connect signals */ - init_main_window(glade_file); - init_tree_model(); - init_left_tree(); - init_right_tree(); - - /* Conf stuffs */ - if (ac > 1 && av[1][0] == '-') { - switch (av[1][1]) { - case 'a': - //showAll = 1; - break; - case 'h': - case '?': - printf("%s \n", av[0]); - exit(0); - } - name = av[2]; - } else - name = av[1]; - - conf_parse(name); - fixup_rootmenu(&rootmenu); - conf_read(NULL); - - switch (view_mode) { - case SINGLE_VIEW: - display_tree_part(); - break; - case SPLIT_VIEW: - display_list(); - break; - case FULL_VIEW: - display_tree(&rootmenu); - break; - } - - gtk_main(); - - return 0; -} - -static void conf_changed(void) -{ - bool changed = conf_get_changed(); - gtk_widget_set_sensitive(save_btn, changed); - gtk_widget_set_sensitive(save_menu_item, changed); -} diff --git a/config/gconf.glade b/config/gconf.glade deleted file mode 100644 index 803233fdd..000000000 --- a/config/gconf.glade +++ /dev/null @@ -1,648 +0,0 @@ - - - - - - - True - Gtk Kernel Configurator - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - - - - - - - True - False - 0 - - - - True - - - - True - _File - True - - - - - - - True - Load a config file - _Load - True - - - - - - True - gtk-open - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Save the config in .config - _Save - True - - - - - - True - gtk-save - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - Save the config in a file - Save _as - True - - - - - True - gtk-save-as - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - _Quit - True - - - - - - True - gtk-quit - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - - True - _Options - True - - - - - - - True - Show name - Show _name - True - False - - - - - - - True - Show range (Y/M/N) - Show _range - True - False - - - - - - - True - Show value of the option - Show _data - True - False - - - - - - - True - - - - - - True - Show all options - Show all _options - True - False - - - - - - - True - Show masked options - Show _debug info - True - False - - - - - - - - - - - True - _Help - True - - - - - - - True - _Introduction - True - - - - - - True - gtk-dialog-question - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _About - True - - - - - - True - gtk-properties - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _License - True - - - - - True - gtk-justify-fill - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - - - - 0 - False - False - - - - - - True - GTK_SHADOW_OUT - GTK_POS_LEFT - GTK_POS_TOP - - - - True - GTK_ORIENTATION_HORIZONTAL - GTK_TOOLBAR_BOTH - True - True - - - - True - Goes up of one level (single view) - Back - True - gtk-undo - True - True - False - - - - False - True - - - - - - True - True - True - False - - - - True - - - - - False - False - - - - - - True - Load a config file - Load - True - gtk-open - True - True - False - - - - False - True - - - - - - True - Save a config file - Save - True - gtk-save - True - True - False - - - - False - True - - - - - - True - True - True - False - - - - True - - - - - False - False - - - - - - True - Single view - Single - True - gtk-missing-image - True - True - False - - - - False - True - - - - - - True - Split view - Split - True - gtk-missing-image - True - True - False - - - - False - True - - - - - - True - Full view - Full - True - gtk-missing-image - True - True - False - - - - False - True - - - - - - True - True - True - False - - - - True - - - - - False - False - - - - - - True - Collapse the whole tree in the right frame - Collapse - True - gtk-remove - True - True - False - - - - False - True - - - - - - True - Expand the whole tree in the right frame - Expand - True - gtk-add - True - True - False - - - - False - True - - - - - - - 0 - False - False - - - - - - 1 - True - True - 0 - - - - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - - - - - - - - True - False - - - - - - True - True - 0 - - - - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - False - False - True - - - - - - - - True - False - - - - - - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_WORD - True - 0 - 0 - 0 - 0 - 0 - 0 - Sorry, no help available for this option yet. - - - - - True - True - - - - - True - True - - - - - 0 - True - True - - - - - - - diff --git a/config/qconf.cc b/config/qconf.cc deleted file mode 100644 index ce7d508c7..000000000 --- a/config/qconf.cc +++ /dev/null @@ -1,1765 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "lkc.h" -#include "qconf.h" - -#include "qconf.moc" -#include "images.c" - -#ifdef _ -# undef _ -# define _ qgettext -#endif - -static QApplication *configApp; -static ConfigSettings *configSettings; - -QAction *ConfigMainWindow::saveAction; - -static inline QString qgettext(const char* str) -{ - return QString::fromLocal8Bit(gettext(str)); -} - -static inline QString qgettext(const QString& str) -{ - return QString::fromLocal8Bit(gettext(str.latin1())); -} - -/** - * Reads a list of integer values from the application settings. - */ -QValueList ConfigSettings::readSizes(const QString& key, bool *ok) -{ - QValueList result; - QStringList entryList = readListEntry(key, ok); - if (ok) { - QStringList::Iterator it; - for (it = entryList.begin(); it != entryList.end(); ++it) - result.push_back((*it).toInt()); - } - - return result; -} - -/** - * Writes a list of integer values to the application settings. - */ -bool ConfigSettings::writeSizes(const QString& key, const QValueList& value) -{ - QStringList stringList; - QValueList::ConstIterator it; - - for (it = value.begin(); it != value.end(); ++it) - stringList.push_back(QString::number(*it)); - return writeEntry(key, stringList); -} - - -#if QT_VERSION >= 300 -/* - * set the new data - * TODO check the value - */ -void ConfigItem::okRename(int col) -{ - Parent::okRename(col); - sym_set_string_value(menu->sym, text(dataColIdx).latin1()); - listView()->updateList(this); -} -#endif - -/* - * update the displayed of a menu entry - */ -void ConfigItem::updateMenu(void) -{ - ConfigList* list; - struct symbol* sym; - struct property *prop; - QString prompt; - int type; - tristate expr; - - list = listView(); - if (goParent) { - setPixmap(promptColIdx, list->menuBackPix); - prompt = ".."; - goto set_prompt; - } - - sym = menu->sym; - prop = menu->prompt; - prompt = _(menu_get_prompt(menu)); - - if (prop) switch (prop->type) { - case P_MENU: - if (list->mode == singleMode || list->mode == symbolMode) { - /* a menuconfig entry is displayed differently - * depending whether it's at the view root or a child. - */ - if (sym && list->rootEntry == menu) - break; - setPixmap(promptColIdx, list->menuPix); - } else { - if (sym) - break; - setPixmap(promptColIdx, 0); - } - goto set_prompt; - case P_COMMENT: - setPixmap(promptColIdx, 0); - goto set_prompt; - default: - ; - } - if (!sym) - goto set_prompt; - - setText(nameColIdx, QString::fromLocal8Bit(sym->name)); - - type = sym_get_type(sym); - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - char ch; - - if (!sym_is_changable(sym) && !list->showAll) { - setPixmap(promptColIdx, 0); - setText(noColIdx, QString::null); - setText(modColIdx, QString::null); - setText(yesColIdx, QString::null); - break; - } - expr = sym_get_tristate_value(sym); - switch (expr) { - case yes: - if (sym_is_choice_value(sym) && type == S_BOOLEAN) - setPixmap(promptColIdx, list->choiceYesPix); - else - setPixmap(promptColIdx, list->symbolYesPix); - setText(yesColIdx, "Y"); - ch = 'Y'; - break; - case mod: - setPixmap(promptColIdx, list->symbolModPix); - setText(modColIdx, "M"); - ch = 'M'; - break; - default: - if (sym_is_choice_value(sym) && type == S_BOOLEAN) - setPixmap(promptColIdx, list->choiceNoPix); - else - setPixmap(promptColIdx, list->symbolNoPix); - setText(noColIdx, "N"); - ch = 'N'; - break; - } - if (expr != no) - setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); - if (expr != mod) - setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); - if (expr != yes) - setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); - - setText(dataColIdx, QChar(ch)); - break; - case S_INT: - case S_HEX: - case S_STRING: - const char* data; - - data = sym_get_string_value(sym); - -#if QT_VERSION >= 300 - int i = list->mapIdx(dataColIdx); - if (i >= 0) - setRenameEnabled(i, TRUE); -#endif - setText(dataColIdx, data); - if (type == S_STRING) - prompt = QString("%1: %2").arg(prompt).arg(data); - else - prompt = QString("(%2) %1").arg(prompt).arg(data); - break; - } - if (!sym_has_value(sym) && visible) - prompt += _(" (NEW)"); -set_prompt: - setText(promptColIdx, prompt); -} - -void ConfigItem::testUpdateMenu(bool v) -{ - ConfigItem* i; - - visible = v; - if (!menu) - return; - - sym_calc_value(menu->sym); - if (menu->flags & MENU_CHANGED) { - /* the menu entry changed, so update all list items */ - menu->flags &= ~MENU_CHANGED; - for (i = (ConfigItem*)menu->data; i; i = i->nextItem) - i->updateMenu(); - } else if (listView()->updateAll) - updateMenu(); -} - -void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) -{ - ConfigList* list = listView(); - - if (visible) { - if (isSelected() && !list->hasFocus() && list->mode == menuMode) - Parent::paintCell(p, list->inactivedColorGroup, column, width, align); - else - Parent::paintCell(p, cg, column, width, align); - } else - Parent::paintCell(p, list->disabledColorGroup, column, width, align); -} - -/* - * construct a menu entry - */ -void ConfigItem::init(void) -{ - if (menu) { - ConfigList* list = listView(); - nextItem = (ConfigItem*)menu->data; - menu->data = this; - - if (list->mode != fullMode) - setOpen(TRUE); - sym_calc_value(menu->sym); - } - updateMenu(); -} - -/* - * destruct a menu entry - */ -ConfigItem::~ConfigItem(void) -{ - if (menu) { - ConfigItem** ip = (ConfigItem**)&menu->data; - for (; *ip; ip = &(*ip)->nextItem) { - if (*ip == this) { - *ip = nextItem; - break; - } - } - } -} - -ConfigLineEdit::ConfigLineEdit(ConfigView* parent) - : Parent(parent) -{ - connect(this, SIGNAL(lostFocus()), SLOT(hide())); -} - -void ConfigLineEdit::show(ConfigItem* i) -{ - item = i; - if (sym_get_string_value(item->menu->sym)) - setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); - else - setText(QString::null); - Parent::show(); - setFocus(); -} - -void ConfigLineEdit::keyPressEvent(QKeyEvent* e) -{ - switch (e->key()) { - case Qt::Key_Escape: - break; - case Qt::Key_Return: - case Qt::Key_Enter: - sym_set_string_value(item->menu->sym, text().latin1()); - parent()->updateList(item); - break; - default: - Parent::keyPressEvent(e); - return; - } - e->accept(); - parent()->list->setFocus(); - hide(); -} - -ConfigList::ConfigList(ConfigView* p, const char *name) - : Parent(p, name), - updateAll(false), - symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), - choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), - menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), - showAll(false), showName(false), showRange(false), showData(false), - rootEntry(0), headerPopup(0) -{ - int i; - - setSorting(-1); - setRootIsDecorated(TRUE); - disabledColorGroup = palette().active(); - disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); - inactivedColorGroup = palette().active(); - inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); - - connect(this, SIGNAL(selectionChanged(void)), - SLOT(updateSelection(void))); - - if (name) { - configSettings->beginGroup(name); - showAll = configSettings->readBoolEntry("/showAll", false); - showName = configSettings->readBoolEntry("/showName", false); - showRange = configSettings->readBoolEntry("/showRange", false); - showData = configSettings->readBoolEntry("/showData", false); - configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); - } - - for (i = 0; i < colNr; i++) - colMap[i] = colRevMap[i] = -1; - addColumn(promptColIdx, _("Option")); - - reinit(); -} - -void ConfigList::reinit(void) -{ - removeColumn(dataColIdx); - removeColumn(yesColIdx); - removeColumn(modColIdx); - removeColumn(noColIdx); - removeColumn(nameColIdx); - - if (showName) - addColumn(nameColIdx, _("Name")); - if (showRange) { - addColumn(noColIdx, "N"); - addColumn(modColIdx, "M"); - addColumn(yesColIdx, "Y"); - } - if (showData) - addColumn(dataColIdx, _("Value")); - - updateListAll(); -} - -void ConfigList::saveSettings(void) -{ - if (name()) { - configSettings->beginGroup(name()); - configSettings->writeEntry("/showName", showName); - configSettings->writeEntry("/showRange", showRange); - configSettings->writeEntry("/showData", showData); - configSettings->writeEntry("/showAll", showAll); - configSettings->endGroup(); - } -} - -ConfigItem* ConfigList::findConfigItem(struct menu *menu) -{ - ConfigItem* item = (ConfigItem*)menu->data; - - for (; item; item = item->nextItem) { - if (this == item->listView()) - break; - } - - return item; -} - -void ConfigList::updateSelection(void) -{ - struct menu *menu; - enum prop_type type; - - ConfigItem* item = (ConfigItem*)selectedItem(); - if (!item) - return; - - menu = item->menu; - emit menuChanged(menu); - if (!menu) - return; - type = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (mode == menuMode && type == P_MENU) - emit menuSelected(menu); -} - -void ConfigList::updateList(ConfigItem* item) -{ - ConfigItem* last = 0; - - if (!rootEntry) { - if (mode != listMode) - goto update; - QListViewItemIterator it(this); - ConfigItem* item; - - for (; it.current(); ++it) { - item = (ConfigItem*)it.current(); - if (!item->menu) - continue; - item->testUpdateMenu(menu_is_visible(item->menu)); - } - return; - } - - if (rootEntry != &rootmenu && (mode == singleMode || - (mode == symbolMode && rootEntry->parent != &rootmenu))) { - item = firstChild(); - if (!item) - item = new ConfigItem(this, 0, true); - last = item; - } - if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && - rootEntry->sym && rootEntry->prompt) { - item = last ? last->nextSibling() : firstChild(); - if (!item) - item = new ConfigItem(this, last, rootEntry, true); - else - item->testUpdateMenu(true); - - updateMenuList(item, rootEntry); - triggerUpdate(); - return; - } -update: - updateMenuList(this, rootEntry); - triggerUpdate(); -} - -void ConfigList::setValue(ConfigItem* item, tristate val) -{ - struct symbol* sym; - int type; - tristate oldval; - - sym = item->menu ? item->menu->sym : 0; - if (!sym) - return; - - type = sym_get_type(sym); - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - oldval = sym_get_tristate_value(sym); - - if (!sym_set_tristate_value(sym, val)) - return; - if (oldval == no && item->menu->list) - item->setOpen(TRUE); - parent()->updateList(item); - break; - } -} - -void ConfigList::changeValue(ConfigItem* item) -{ - struct symbol* sym; - struct menu* menu; - int type, oldexpr, newexpr; - - menu = item->menu; - if (!menu) - return; - sym = menu->sym; - if (!sym) { - if (item->menu->list) - item->setOpen(!item->isOpen()); - return; - } - - type = sym_get_type(sym); - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - oldexpr = sym_get_tristate_value(sym); - newexpr = sym_toggle_tristate_value(sym); - if (item->menu->list) { - if (oldexpr == newexpr) - item->setOpen(!item->isOpen()); - else if (oldexpr == no) - item->setOpen(TRUE); - } - if (oldexpr != newexpr) - parent()->updateList(item); - break; - case S_INT: - case S_HEX: - case S_STRING: -#if QT_VERSION >= 300 - if (colMap[dataColIdx] >= 0) - item->startRename(colMap[dataColIdx]); - else -#endif - parent()->lineEdit->show(item); - break; - } -} - -void ConfigList::setRootMenu(struct menu *menu) -{ - enum prop_type type; - - if (rootEntry == menu) - return; - type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (type != P_MENU) - return; - updateMenuList(this, 0); - rootEntry = menu; - updateListAll(); - setSelected(currentItem(), hasFocus()); - ensureItemVisible(currentItem()); -} - -void ConfigList::setParentMenu(void) -{ - ConfigItem* item; - struct menu *oldroot; - - oldroot = rootEntry; - if (rootEntry == &rootmenu) - return; - setRootMenu(menu_get_parent_menu(rootEntry->parent)); - - QListViewItemIterator it(this); - for (; (item = (ConfigItem*)it.current()); it++) { - if (item->menu == oldroot) { - setCurrentItem(item); - ensureItemVisible(item); - break; - } - } -} - -/* - * update all the children of a menu entry - * removes/adds the entries from the parent widget as necessary - * - * parent: either the menu list widget or a menu entry widget - * menu: entry to be updated - */ -template -void ConfigList::updateMenuList(P* parent, struct menu* menu) -{ - struct menu* child; - ConfigItem* item; - ConfigItem* last; - bool visible; - enum prop_type type; - - if (!menu) { - while ((item = parent->firstChild())) - delete item; - return; - } - - last = parent->firstChild(); - if (last && !last->goParent) - last = 0; - for (child = menu->list; child; child = child->next) { - item = last ? last->nextSibling() : parent->firstChild(); - type = child->prompt ? child->prompt->type : P_UNKNOWN; - - switch (mode) { - case menuMode: - if (!(child->flags & MENU_ROOT)) - goto hide; - break; - case symbolMode: - if (child->flags & MENU_ROOT) - goto hide; - break; - default: - break; - } - - visible = menu_is_visible(child); - if (showAll || visible) { - if (!child->sym && !child->list && !child->prompt) - continue; - if (!item || item->menu != child) - item = new ConfigItem(parent, last, child, visible); - else - item->testUpdateMenu(visible); - - if (mode == fullMode || mode == menuMode || type != P_MENU) - updateMenuList(item, child); - else - updateMenuList(item, 0); - last = item; - continue; - } - hide: - if (item && item->menu == child) { - last = parent->firstChild(); - if (last == item) - last = 0; - else while (last->nextSibling() != item) - last = last->nextSibling(); - delete item; - } - } -} - -void ConfigList::keyPressEvent(QKeyEvent* ev) -{ - QListViewItem* i = currentItem(); - ConfigItem* item; - struct menu *menu; - enum prop_type type; - - if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { - emit parentSelected(); - ev->accept(); - return; - } - - if (!i) { - Parent::keyPressEvent(ev); - return; - } - item = (ConfigItem*)i; - - switch (ev->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - if (item->goParent) { - emit parentSelected(); - break; - } - menu = item->menu; - if (!menu) - break; - type = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (type == P_MENU && rootEntry != menu && - mode != fullMode && mode != menuMode) { - emit menuSelected(menu); - break; - } - case Qt::Key_Space: - changeValue(item); - break; - case Qt::Key_N: - setValue(item, no); - break; - case Qt::Key_M: - setValue(item, mod); - break; - case Qt::Key_Y: - setValue(item, yes); - break; - default: - Parent::keyPressEvent(ev); - return; - } - ev->accept(); -} - -void ConfigList::contentsMousePressEvent(QMouseEvent* e) -{ - //QPoint p(contentsToViewport(e->pos())); - //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); - Parent::contentsMousePressEvent(e); -} - -void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) -{ - QPoint p(contentsToViewport(e->pos())); - ConfigItem* item = (ConfigItem*)itemAt(p); - struct menu *menu; - enum prop_type ptype; - const QPixmap* pm; - int idx, x; - - if (!item) - goto skip; - - menu = item->menu; - x = header()->offset() + p.x(); - idx = colRevMap[header()->sectionAt(x)]; - switch (idx) { - case promptColIdx: - pm = item->pixmap(promptColIdx); - if (pm) { - int off = header()->sectionPos(0) + itemMargin() + - treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); - if (x >= off && x < off + pm->width()) { - if (item->goParent) { - emit parentSelected(); - break; - } else if (!menu) - break; - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (ptype == P_MENU && rootEntry != menu && - mode != fullMode && mode != menuMode) - emit menuSelected(menu); - else - changeValue(item); - } - } - break; - case noColIdx: - setValue(item, no); - break; - case modColIdx: - setValue(item, mod); - break; - case yesColIdx: - setValue(item, yes); - break; - case dataColIdx: - changeValue(item); - break; - } - -skip: - //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); - Parent::contentsMouseReleaseEvent(e); -} - -void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) -{ - //QPoint p(contentsToViewport(e->pos())); - //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); - Parent::contentsMouseMoveEvent(e); -} - -void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) -{ - QPoint p(contentsToViewport(e->pos())); - ConfigItem* item = (ConfigItem*)itemAt(p); - struct menu *menu; - enum prop_type ptype; - - if (!item) - goto skip; - if (item->goParent) { - emit parentSelected(); - goto skip; - } - menu = item->menu; - if (!menu) - goto skip; - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) - emit menuSelected(menu); - else if (menu->sym) - changeValue(item); - -skip: - //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); - Parent::contentsMouseDoubleClickEvent(e); -} - -void ConfigList::focusInEvent(QFocusEvent *e) -{ - struct menu *menu = NULL; - - Parent::focusInEvent(e); - - ConfigItem* item = (ConfigItem *)currentItem(); - if (item) { - setSelected(item, TRUE); - menu = item->menu; - } - emit gotFocus(menu); -} - -void ConfigList::contextMenuEvent(QContextMenuEvent *e) -{ - if (e->y() <= header()->geometry().bottom()) { - if (!headerPopup) { - QAction *action; - - headerPopup = new QPopupMenu(this); - action = new QAction(NULL, _("Show Name"), 0, this); - action->setToggleAction(TRUE); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowName(bool))); - connect(parent(), SIGNAL(showNameChanged(bool)), - action, SLOT(setOn(bool))); - action->setOn(showName); - action->addTo(headerPopup); - action = new QAction(NULL, _("Show Range"), 0, this); - action->setToggleAction(TRUE); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowRange(bool))); - connect(parent(), SIGNAL(showRangeChanged(bool)), - action, SLOT(setOn(bool))); - action->setOn(showRange); - action->addTo(headerPopup); - action = new QAction(NULL, _("Show Data"), 0, this); - action->setToggleAction(TRUE); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowData(bool))); - connect(parent(), SIGNAL(showDataChanged(bool)), - action, SLOT(setOn(bool))); - action->setOn(showData); - action->addTo(headerPopup); - } - headerPopup->exec(e->globalPos()); - e->accept(); - } else - e->ignore(); -} - -ConfigView* ConfigView::viewList; - -ConfigView::ConfigView(QWidget* parent, const char *name) - : Parent(parent, name) -{ - list = new ConfigList(this, name); - lineEdit = new ConfigLineEdit(this); - lineEdit->hide(); - - this->nextView = viewList; - viewList = this; -} - -ConfigView::~ConfigView(void) -{ - ConfigView** vp; - - for (vp = &viewList; *vp; vp = &(*vp)->nextView) { - if (*vp == this) { - *vp = nextView; - break; - } - } -} - -void ConfigView::setShowAll(bool b) -{ - if (list->showAll != b) { - list->showAll = b; - list->updateListAll(); - emit showAllChanged(b); - } -} - -void ConfigView::setShowName(bool b) -{ - if (list->showName != b) { - list->showName = b; - list->reinit(); - emit showNameChanged(b); - } -} - -void ConfigView::setShowRange(bool b) -{ - if (list->showRange != b) { - list->showRange = b; - list->reinit(); - emit showRangeChanged(b); - } -} - -void ConfigView::setShowData(bool b) -{ - if (list->showData != b) { - list->showData = b; - list->reinit(); - emit showDataChanged(b); - } -} - -void ConfigList::setAllOpen(bool open) -{ - QListViewItemIterator it(this); - - for (; it.current(); it++) - it.current()->setOpen(open); -} - -void ConfigView::updateList(ConfigItem* item) -{ - ConfigView* v; - - for (v = viewList; v; v = v->nextView) - v->list->updateList(item); -} - -void ConfigView::updateListAll(void) -{ - ConfigView* v; - - for (v = viewList; v; v = v->nextView) - v->list->updateListAll(); -} - -ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) - : Parent(parent, name), sym(0), menu(0) -{ - if (name) { - configSettings->beginGroup(name); - _showDebug = configSettings->readBoolEntry("/showDebug", false); - configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); - } -} - -void ConfigInfoView::saveSettings(void) -{ - if (name()) { - configSettings->beginGroup(name()); - configSettings->writeEntry("/showDebug", showDebug()); - configSettings->endGroup(); - } -} - -void ConfigInfoView::setShowDebug(bool b) -{ - if (_showDebug != b) { - _showDebug = b; - if (menu) - menuInfo(); - else if (sym) - symbolInfo(); - emit showDebugChanged(b); - } -} - -void ConfigInfoView::setInfo(struct menu *m) -{ - if (menu == m) - return; - menu = m; - sym = NULL; - if (!menu) - clear(); - else - menuInfo(); -} - -void ConfigInfoView::setSource(const QString& name) -{ - const char *p = name.latin1(); - - menu = NULL; - sym = NULL; - - switch (p[0]) { - case 'm': - struct menu *m; - - if (sscanf(p, "m%p", &m) == 1 && menu != m) { - menu = m; - menuInfo(); - emit menuSelected(menu); - } - break; - case 's': - struct symbol *s; - - if (sscanf(p, "s%p", &s) == 1 && sym != s) { - sym = s; - symbolInfo(); - } - break; - } -} - -void ConfigInfoView::symbolInfo(void) -{ - QString str; - - str += "Symbol: "; - str += print_filter(sym->name); - str += "

value: "; - str += print_filter(sym_get_string_value(sym)); - str += "
visibility: "; - str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; - str += "
"; - str += debug_info(sym); - - setText(str); -} - -void ConfigInfoView::menuInfo(void) -{ - struct symbol* sym; - QString head, debug, help; - - sym = menu->sym; - if (sym) { - if (menu->prompt) { - head += ""; - head += print_filter(_(menu->prompt->text)); - head += ""; - if (sym->name) { - head += " ("; - if (showDebug()) - head += QString().sprintf("", sym); - head += print_filter(sym->name); - if (showDebug()) - head += ""; - head += ")"; - } - } else if (sym->name) { - head += ""; - if (showDebug()) - head += QString().sprintf("", sym); - head += print_filter(sym->name); - if (showDebug()) - head += ""; - head += ""; - } - head += "

"; - - if (showDebug()) - debug = debug_info(sym); - - help = menu_get_help(menu); - /* Gettextize if the help text not empty */ - if (help.isEmpty()) - help = print_filter(menu_get_help(menu)); - else - help = print_filter(_(menu_get_help(menu))); - } else if (menu->prompt) { - head += ""; - head += print_filter(_(menu->prompt->text)); - head += "

"; - if (showDebug()) { - if (menu->prompt->visible.expr) { - debug += "  dep: "; - expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); - debug += "

"; - } - } - } - if (showDebug()) - debug += QString().sprintf("defined at %s:%d

", menu->file->name, menu->lineno); - - setText(head + debug + help); -} - -QString ConfigInfoView::debug_info(struct symbol *sym) -{ - QString debug; - - debug += "type: "; - debug += print_filter(sym_type_name(sym->type)); - if (sym_is_choice(sym)) - debug += " (choice)"; - debug += "
"; - if (sym->rev_dep.expr) { - debug += "reverse dep: "; - expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); - debug += "
"; - } - for (struct property *prop = sym->prop; prop; prop = prop->next) { - switch (prop->type) { - case P_PROMPT: - case P_MENU: - debug += QString().sprintf("prompt: ", prop->menu); - debug += print_filter(_(prop->text)); - debug += "
"; - break; - case P_DEFAULT: - case P_SELECT: - case P_RANGE: - case P_ENV: - debug += prop_get_type_name(prop->type); - debug += ": "; - expr_print(prop->expr, expr_print_help, &debug, E_NONE); - debug += "
"; - break; - case P_CHOICE: - if (sym_is_choice(sym)) { - debug += "choice: "; - expr_print(prop->expr, expr_print_help, &debug, E_NONE); - debug += "
"; - } - break; - default: - debug += "unknown property: "; - debug += prop_get_type_name(prop->type); - debug += "
"; - } - if (prop->visible.expr) { - debug += "    dep: "; - expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); - debug += "
"; - } - } - debug += "
"; - - return debug; -} - -QString ConfigInfoView::print_filter(const QString &str) -{ - QRegExp re("[<>&\"\\n]"); - QString res = str; - for (int i = 0; (i = res.find(re, i)) >= 0;) { - switch (res[i].latin1()) { - case '<': - res.replace(i, 1, "<"); - i += 4; - break; - case '>': - res.replace(i, 1, ">"); - i += 4; - break; - case '&': - res.replace(i, 1, "&"); - i += 5; - break; - case '"': - res.replace(i, 1, """); - i += 6; - break; - case '\n': - res.replace(i, 1, "
"); - i += 4; - break; - } - } - return res; -} - -void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) -{ - QString* text = reinterpret_cast(data); - QString str2 = print_filter(str); - - if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { - *text += QString().sprintf("", sym); - *text += str2; - *text += ""; - } else - *text += str2; -} - -QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) -{ - QPopupMenu* popup = Parent::createPopupMenu(pos); - QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup); - action->setToggleAction(TRUE); - connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); - connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); - action->setOn(showDebug()); - popup->insertSeparator(); - action->addTo(popup); - return popup; -} - -void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) -{ - Parent::contentsContextMenuEvent(e); -} - -ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) - : Parent(parent, name), result(NULL) -{ - setCaption("Search Config"); - - QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); - QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); - layout2->addWidget(new QLabel(_("Find:"), this)); - editField = new QLineEdit(this); - connect(editField, SIGNAL(returnPressed()), SLOT(search())); - layout2->addWidget(editField); - searchButton = new QPushButton(_("Search"), this); - searchButton->setAutoDefault(FALSE); - connect(searchButton, SIGNAL(clicked()), SLOT(search())); - layout2->addWidget(searchButton); - layout1->addLayout(layout2); - - split = new QSplitter(this); - split->setOrientation(Qt::Vertical); - list = new ConfigView(split, name); - list->list->mode = listMode; - info = new ConfigInfoView(split, name); - connect(list->list, SIGNAL(menuChanged(struct menu *)), - info, SLOT(setInfo(struct menu *))); - connect(list->list, SIGNAL(menuChanged(struct menu *)), - parent, SLOT(setMenuLink(struct menu *))); - - layout1->addWidget(split); - - if (name) { - int x, y, width, height; - bool ok; - - configSettings->beginGroup(name); - width = configSettings->readNumEntry("/window width", parent->width() / 2); - height = configSettings->readNumEntry("/window height", parent->height() / 2); - resize(width, height); - x = configSettings->readNumEntry("/window x", 0, &ok); - if (ok) - y = configSettings->readNumEntry("/window y", 0, &ok); - if (ok) - move(x, y); - QValueList sizes = configSettings->readSizes("/split", &ok); - if (ok) - split->setSizes(sizes); - configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); - } -} - -void ConfigSearchWindow::saveSettings(void) -{ - if (name()) { - configSettings->beginGroup(name()); - configSettings->writeEntry("/window x", pos().x()); - configSettings->writeEntry("/window y", pos().y()); - configSettings->writeEntry("/window width", size().width()); - configSettings->writeEntry("/window height", size().height()); - configSettings->writeSizes("/split", split->sizes()); - configSettings->endGroup(); - } -} - -void ConfigSearchWindow::search(void) -{ - struct symbol **p; - struct property *prop; - ConfigItem *lastItem = NULL; - - free(result); - list->list->clear(); - info->clear(); - - result = sym_re_search(editField->text().latin1()); - if (!result) - return; - for (p = result; *p; p++) { - for_all_prompts((*p), prop) - lastItem = new ConfigItem(list->list, lastItem, prop->menu, - menu_is_visible(prop->menu)); - } -} - -/* - * Construct the complete config widget - */ -ConfigMainWindow::ConfigMainWindow(void) - : searchWindow(0) -{ - QMenuBar* menu; - bool ok; - int x, y, width, height; - char title[256]; - - QDesktopWidget *d = configApp->desktop(); - snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"), - getenv("KERNELVERSION")); - setCaption(title); - - width = configSettings->readNumEntry("/window width", d->width() - 64); - height = configSettings->readNumEntry("/window height", d->height() - 64); - resize(width, height); - x = configSettings->readNumEntry("/window x", 0, &ok); - if (ok) - y = configSettings->readNumEntry("/window y", 0, &ok); - if (ok) - move(x, y); - - split1 = new QSplitter(this); - split1->setOrientation(Qt::Horizontal); - setCentralWidget(split1); - - menuView = new ConfigView(split1, "menu"); - menuList = menuView->list; - - split2 = new QSplitter(split1); - split2->setOrientation(Qt::Vertical); - - // create config tree - configView = new ConfigView(split2, "config"); - configList = configView->list; - - helpText = new ConfigInfoView(split2, "help"); - helpText->setTextFormat(Qt::RichText); - - setTabOrder(configList, helpText); - configList->setFocus(); - - menu = menuBar(); - toolBar = new QToolBar("Tools", this); - - backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this); - connect(backAction, SIGNAL(activated()), SLOT(goBack())); - backAction->setEnabled(FALSE); - QAction *quitAction = new QAction("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); - connect(quitAction, SIGNAL(activated()), SLOT(close())); - QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); - connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); - saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); - connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); - conf_set_changed_callback(conf_changed); - // Set saveAction's initial state - conf_changed(); - QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this); - connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); - QAction *searchAction = new QAction("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); - connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); - QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); - connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); - QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); - connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); - QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); - connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); - - QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this); - showNameAction->setToggleAction(TRUE); - connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); - connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); - showNameAction->setOn(configView->showName()); - QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this); - showRangeAction->setToggleAction(TRUE); - connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); - connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); - showRangeAction->setOn(configList->showRange); - QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this); - showDataAction->setToggleAction(TRUE); - connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); - connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); - showDataAction->setOn(configList->showData); - QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this); - showAllAction->setToggleAction(TRUE); - connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool))); - connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool))); - showAllAction->setOn(configList->showAll); - QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this); - showDebugAction->setToggleAction(TRUE); - connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); - connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); - showDebugAction->setOn(helpText->showDebug()); - - QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this); - connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); - QAction *showAboutAction = new QAction(NULL, _("About"), 0, this); - connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); - - // init tool bar - backAction->addTo(toolBar); - toolBar->addSeparator(); - loadAction->addTo(toolBar); - saveAction->addTo(toolBar); - toolBar->addSeparator(); - singleViewAction->addTo(toolBar); - splitViewAction->addTo(toolBar); - fullViewAction->addTo(toolBar); - - // create config menu - QPopupMenu* config = new QPopupMenu(this); - menu->insertItem(_("&File"), config); - loadAction->addTo(config); - saveAction->addTo(config); - saveAsAction->addTo(config); - config->insertSeparator(); - quitAction->addTo(config); - - // create edit menu - QPopupMenu* editMenu = new QPopupMenu(this); - menu->insertItem(_("&Edit"), editMenu); - searchAction->addTo(editMenu); - - // create options menu - QPopupMenu* optionMenu = new QPopupMenu(this); - menu->insertItem(_("&Option"), optionMenu); - showNameAction->addTo(optionMenu); - showRangeAction->addTo(optionMenu); - showDataAction->addTo(optionMenu); - optionMenu->insertSeparator(); - showAllAction->addTo(optionMenu); - showDebugAction->addTo(optionMenu); - - // create help menu - QPopupMenu* helpMenu = new QPopupMenu(this); - menu->insertSeparator(); - menu->insertItem(_("&Help"), helpMenu); - showIntroAction->addTo(helpMenu); - showAboutAction->addTo(helpMenu); - - connect(configList, SIGNAL(menuChanged(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(configList, SIGNAL(menuSelected(struct menu *)), - SLOT(changeMenu(struct menu *))); - connect(configList, SIGNAL(parentSelected()), - SLOT(goBack())); - connect(menuList, SIGNAL(menuChanged(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(menuSelected(struct menu *)), - SLOT(changeMenu(struct menu *))); - - connect(configList, SIGNAL(gotFocus(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(gotFocus(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(gotFocus(struct menu *)), - SLOT(listFocusChanged(void))); - connect(helpText, SIGNAL(menuSelected(struct menu *)), - SLOT(setMenuLink(struct menu *))); - - QString listMode = configSettings->readEntry("/listMode", "symbol"); - if (listMode == "single") - showSingleView(); - else if (listMode == "full") - showFullView(); - else /*if (listMode == "split")*/ - showSplitView(); - - // UI setup done, restore splitter positions - QValueList sizes = configSettings->readSizes("/split1", &ok); - if (ok) - split1->setSizes(sizes); - - sizes = configSettings->readSizes("/split2", &ok); - if (ok) - split2->setSizes(sizes); -} - -void ConfigMainWindow::loadConfig(void) -{ - QString s = QFileDialog::getOpenFileName(conf_get_configname(), NULL, this); - if (s.isNull()) - return; - if (conf_read(QFile::encodeName(s))) - QMessageBox::information(this, "qconf", _("Unable to load configuration!")); - ConfigView::updateListAll(); -} - -void ConfigMainWindow::saveConfig(void) -{ - if (conf_write(NULL)) - QMessageBox::information(this, "qconf", _("Unable to save configuration!")); -} - -void ConfigMainWindow::saveConfigAs(void) -{ - QString s = QFileDialog::getSaveFileName(conf_get_configname(), NULL, this); - if (s.isNull()) - return; - if (conf_write(QFile::encodeName(s))) - QMessageBox::information(this, "qconf", _("Unable to save configuration!")); -} - -void ConfigMainWindow::searchConfig(void) -{ - if (!searchWindow) - searchWindow = new ConfigSearchWindow(this, "search"); - searchWindow->show(); -} - -void ConfigMainWindow::changeMenu(struct menu *menu) -{ - configList->setRootMenu(menu); - if (configList->rootEntry->parent == &rootmenu) - backAction->setEnabled(FALSE); - else - backAction->setEnabled(TRUE); -} - -void ConfigMainWindow::setMenuLink(struct menu *menu) -{ - struct menu *parent; - ConfigList* list = NULL; - ConfigItem* item; - - if (!menu_is_visible(menu) && !configView->showAll()) - return; - - switch (configList->mode) { - case singleMode: - list = configList; - parent = menu_get_parent_menu(menu); - if (!parent) - return; - list->setRootMenu(parent); - break; - case symbolMode: - if (menu->flags & MENU_ROOT) { - configList->setRootMenu(menu); - configList->clearSelection(); - list = menuList; - } else { - list = configList; - parent = menu_get_parent_menu(menu->parent); - if (!parent) - return; - item = menuList->findConfigItem(parent); - if (item) { - menuList->setSelected(item, TRUE); - menuList->ensureItemVisible(item); - } - list->setRootMenu(parent); - } - break; - case fullMode: - list = configList; - break; - default: - break; - } - - if (list) { - item = list->findConfigItem(menu); - if (item) { - list->setSelected(item, TRUE); - list->ensureItemVisible(item); - list->setFocus(); - } - } -} - -void ConfigMainWindow::listFocusChanged(void) -{ - if (menuList->mode == menuMode) - configList->clearSelection(); -} - -void ConfigMainWindow::goBack(void) -{ - ConfigItem* item; - - configList->setParentMenu(); - if (configList->rootEntry == &rootmenu) - backAction->setEnabled(FALSE); - item = (ConfigItem*)menuList->selectedItem(); - while (item) { - if (item->menu == configList->rootEntry) { - menuList->setSelected(item, TRUE); - break; - } - item = (ConfigItem*)item->parent(); - } -} - -void ConfigMainWindow::showSingleView(void) -{ - menuView->hide(); - menuList->setRootMenu(0); - configList->mode = singleMode; - if (configList->rootEntry == &rootmenu) - configList->updateListAll(); - else - configList->setRootMenu(&rootmenu); - configList->setAllOpen(TRUE); - configList->setFocus(); -} - -void ConfigMainWindow::showSplitView(void) -{ - configList->mode = symbolMode; - if (configList->rootEntry == &rootmenu) - configList->updateListAll(); - else - configList->setRootMenu(&rootmenu); - configList->setAllOpen(TRUE); - configApp->processEvents(); - menuList->mode = menuMode; - menuList->setRootMenu(&rootmenu); - menuList->setAllOpen(TRUE); - menuView->show(); - menuList->setFocus(); -} - -void ConfigMainWindow::showFullView(void) -{ - menuView->hide(); - menuList->setRootMenu(0); - configList->mode = fullMode; - if (configList->rootEntry == &rootmenu) - configList->updateListAll(); - else - configList->setRootMenu(&rootmenu); - configList->setAllOpen(FALSE); - configList->setFocus(); -} - -/* - * ask for saving configuration before quitting - * TODO ask only when something changed - */ -void ConfigMainWindow::closeEvent(QCloseEvent* e) -{ - if (!conf_get_changed()) { - e->accept(); - return; - } - QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, - QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); - mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); - mb.setButtonText(QMessageBox::No, _("&Discard Changes")); - mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); - switch (mb.exec()) { - case QMessageBox::Yes: - conf_write(NULL); - case QMessageBox::No: - e->accept(); - break; - case QMessageBox::Cancel: - e->ignore(); - break; - } -} - -void ConfigMainWindow::showIntro(void) -{ - static const QString str = _("Welcome to the qconf graphical kernel configuration tool for Linux.\n\n" - "For each option, a blank box indicates the feature is disabled, a check\n" - "indicates it is enabled, and a dot indicates that it is to be compiled\n" - "as a module. Clicking on the box will cycle through the three states.\n\n" - "If you do not see an option (e.g., a device driver) that you believe\n" - "should be present, try turning on Show All Options under the Options menu.\n" - "Although there is no cross reference yet to help you figure out what other\n" - "options must be enabled to support the option you are interested in, you can\n" - "still view the help of a grayed-out option.\n\n" - "Toggling Show Debug Info under the Options menu will show the dependencies,\n" - "which you can then match by examining other options.\n\n"); - - QMessageBox::information(this, "qconf", str); -} - -void ConfigMainWindow::showAbout(void) -{ - static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" - "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); - - QMessageBox::information(this, "qconf", str); -} - -void ConfigMainWindow::saveSettings(void) -{ - configSettings->writeEntry("/window x", pos().x()); - configSettings->writeEntry("/window y", pos().y()); - configSettings->writeEntry("/window width", size().width()); - configSettings->writeEntry("/window height", size().height()); - - QString entry; - switch(configList->mode) { - case singleMode : - entry = "single"; - break; - - case symbolMode : - entry = "split"; - break; - - case fullMode : - entry = "full"; - break; - - default: - break; - } - configSettings->writeEntry("/listMode", entry); - - configSettings->writeSizes("/split1", split1->sizes()); - configSettings->writeSizes("/split2", split2->sizes()); -} - -void ConfigMainWindow::conf_changed(void) -{ - if (saveAction) - saveAction->setEnabled(conf_get_changed()); -} - -void fixup_rootmenu(struct menu *menu) -{ - struct menu *child; - static int menu_cnt = 0; - - menu->flags |= MENU_ROOT; - for (child = menu->list; child; child = child->next) { - if (child->prompt && child->prompt->type == P_MENU) { - menu_cnt++; - fixup_rootmenu(child); - menu_cnt--; - } else if (!menu_cnt) - fixup_rootmenu(child); - } -} - -static const char *progname; - -static void usage(void) -{ - printf(_("%s \n"), progname); - exit(0); -} - -int main(int ac, char** av) -{ - ConfigMainWindow* v; - const char *name; - - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - -#ifndef LKC_DIRECT_LINK - kconfig_load(); -#endif - - progname = av[0]; - configApp = new QApplication(ac, av); - if (ac > 1 && av[1][0] == '-') { - switch (av[1][1]) { - case 'h': - case '?': - usage(); - } - name = av[2]; - } else - name = av[1]; - if (!name) - usage(); - - conf_parse(name); - fixup_rootmenu(&rootmenu); - conf_read(NULL); - //zconfdump(stdout); - - configSettings = new ConfigSettings(); - configSettings->beginGroup("/kconfig/qconf"); - v = new ConfigMainWindow(); - - //zconfdump(stdout); - configApp->setMainWidget(v); - configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); - configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); - v->show(); - configApp->exec(); - - configSettings->endGroup(); - delete configSettings; - - return 0; -} diff --git a/config/qconf.h b/config/qconf.h deleted file mode 100644 index b3b5657b6..000000000 --- a/config/qconf.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#if QT_VERSION >= 300 -#include -#else -class QSettings { -public: - void beginGroup(const QString& group) { } - void endGroup(void) { } - bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const - { if (ok) *ok = FALSE; return def; } - int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const - { if (ok) *ok = FALSE; return def; } - QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const - { if (ok) *ok = FALSE; return def; } - QStringList readListEntry(const QString& key, bool* ok = 0) const - { if (ok) *ok = FALSE; return QStringList(); } - template - bool writeEntry(const QString& key, t value) - { return TRUE; } -}; -#endif - -class ConfigView; -class ConfigList; -class ConfigItem; -class ConfigLineEdit; -class ConfigMainWindow; - - -class ConfigSettings : public QSettings { -public: - QValueList readSizes(const QString& key, bool *ok); - bool writeSizes(const QString& key, const QValueList& value); -}; - -enum colIdx { - promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr -}; -enum listMode { - singleMode, menuMode, symbolMode, fullMode, listMode -}; - -class ConfigList : public QListView { - Q_OBJECT - typedef class QListView Parent; -public: - ConfigList(ConfigView* p, const char *name = 0); - void reinit(void); - ConfigView* parent(void) const - { - return (ConfigView*)Parent::parent(); - } - ConfigItem* findConfigItem(struct menu *); - -protected: - void keyPressEvent(QKeyEvent *e); - void contentsMousePressEvent(QMouseEvent *e); - void contentsMouseReleaseEvent(QMouseEvent *e); - void contentsMouseMoveEvent(QMouseEvent *e); - void contentsMouseDoubleClickEvent(QMouseEvent *e); - void focusInEvent(QFocusEvent *e); - void contextMenuEvent(QContextMenuEvent *e); - -public slots: - void setRootMenu(struct menu *menu); - - void updateList(ConfigItem *item); - void setValue(ConfigItem* item, tristate val); - void changeValue(ConfigItem* item); - void updateSelection(void); - void saveSettings(void); -signals: - void menuChanged(struct menu *menu); - void menuSelected(struct menu *menu); - void parentSelected(void); - void gotFocus(struct menu *); - -public: - void updateListAll(void) - { - updateAll = true; - updateList(NULL); - updateAll = false; - } - ConfigList* listView() - { - return this; - } - ConfigItem* firstChild() const - { - return (ConfigItem *)Parent::firstChild(); - } - int mapIdx(colIdx idx) - { - return colMap[idx]; - } - void addColumn(colIdx idx, const QString& label) - { - colMap[idx] = Parent::addColumn(label); - colRevMap[colMap[idx]] = idx; - } - void removeColumn(colIdx idx) - { - int col = colMap[idx]; - if (col >= 0) { - Parent::removeColumn(col); - colRevMap[col] = colMap[idx] = -1; - } - } - void setAllOpen(bool open); - void setParentMenu(void); - - template - void updateMenuList(P*, struct menu*); - - bool updateAll; - - QPixmap symbolYesPix, symbolModPix, symbolNoPix; - QPixmap choiceYesPix, choiceNoPix; - QPixmap menuPix, menuInvPix, menuBackPix, voidPix; - - bool showAll, showName, showRange, showData; - enum listMode mode; - struct menu *rootEntry; - QColorGroup disabledColorGroup; - QColorGroup inactivedColorGroup; - QPopupMenu* headerPopup; - -private: - int colMap[colNr]; - int colRevMap[colNr]; -}; - -class ConfigItem : public QListViewItem { - typedef class QListViewItem Parent; -public: - ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v) - : Parent(parent, after), menu(m), visible(v), goParent(false) - { - init(); - } - ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) - : Parent(parent, after), menu(m), visible(v), goParent(false) - { - init(); - } - ConfigItem(QListView *parent, ConfigItem *after, bool v) - : Parent(parent, after), menu(0), visible(v), goParent(true) - { - init(); - } - ~ConfigItem(void); - void init(void); -#if QT_VERSION >= 300 - void okRename(int col); -#endif - void updateMenu(void); - void testUpdateMenu(bool v); - ConfigList* listView() const - { - return (ConfigList*)Parent::listView(); - } - ConfigItem* firstChild() const - { - return (ConfigItem *)Parent::firstChild(); - } - ConfigItem* nextSibling() const - { - return (ConfigItem *)Parent::nextSibling(); - } - void setText(colIdx idx, const QString& text) - { - Parent::setText(listView()->mapIdx(idx), text); - } - QString text(colIdx idx) const - { - return Parent::text(listView()->mapIdx(idx)); - } - void setPixmap(colIdx idx, const QPixmap& pm) - { - Parent::setPixmap(listView()->mapIdx(idx), pm); - } - const QPixmap* pixmap(colIdx idx) const - { - return Parent::pixmap(listView()->mapIdx(idx)); - } - void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); - - ConfigItem* nextItem; - struct menu *menu; - bool visible; - bool goParent; -}; - -class ConfigLineEdit : public QLineEdit { - Q_OBJECT - typedef class QLineEdit Parent; -public: - ConfigLineEdit(ConfigView* parent); - ConfigView* parent(void) const - { - return (ConfigView*)Parent::parent(); - } - void show(ConfigItem *i); - void keyPressEvent(QKeyEvent *e); - -public: - ConfigItem *item; -}; - -class ConfigView : public QVBox { - Q_OBJECT - typedef class QVBox Parent; -public: - ConfigView(QWidget* parent, const char *name = 0); - ~ConfigView(void); - static void updateList(ConfigItem* item); - static void updateListAll(void); - - bool showAll(void) const { return list->showAll; } - bool showName(void) const { return list->showName; } - bool showRange(void) const { return list->showRange; } - bool showData(void) const { return list->showData; } -public slots: - void setShowAll(bool); - void setShowName(bool); - void setShowRange(bool); - void setShowData(bool); -signals: - void showAllChanged(bool); - void showNameChanged(bool); - void showRangeChanged(bool); - void showDataChanged(bool); -public: - ConfigList* list; - ConfigLineEdit* lineEdit; - - static ConfigView* viewList; - ConfigView* nextView; -}; - -class ConfigInfoView : public QTextBrowser { - Q_OBJECT - typedef class QTextBrowser Parent; -public: - ConfigInfoView(QWidget* parent, const char *name = 0); - bool showDebug(void) const { return _showDebug; } - -public slots: - void setInfo(struct menu *menu); - void saveSettings(void); - void setSource(const QString& name); - void setShowDebug(bool); - -signals: - void showDebugChanged(bool); - void menuSelected(struct menu *); - -protected: - void symbolInfo(void); - void menuInfo(void); - QString debug_info(struct symbol *sym); - static QString print_filter(const QString &str); - static void expr_print_help(void *data, struct symbol *sym, const char *str); - QPopupMenu* createPopupMenu(const QPoint& pos); - void contentsContextMenuEvent(QContextMenuEvent *e); - - struct symbol *sym; - struct menu *menu; - bool _showDebug; -}; - -class ConfigSearchWindow : public QDialog { - Q_OBJECT - typedef class QDialog Parent; -public: - ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); - -public slots: - void saveSettings(void); - void search(void); - -protected: - QLineEdit* editField; - QPushButton* searchButton; - QSplitter* split; - ConfigView* list; - ConfigInfoView* info; - - struct symbol **result; -}; - -class ConfigMainWindow : public QMainWindow { - Q_OBJECT - - static QAction *saveAction; - static void conf_changed(void); -public: - ConfigMainWindow(void); -public slots: - void changeMenu(struct menu *); - void setMenuLink(struct menu *); - void listFocusChanged(void); - void goBack(void); - void loadConfig(void); - void saveConfig(void); - void saveConfigAs(void); - void searchConfig(void); - void showSingleView(void); - void showSplitView(void); - void showFullView(void); - void showIntro(void); - void showAbout(void); - void saveSettings(void); - -protected: - void closeEvent(QCloseEvent *e); - - ConfigSearchWindow *searchWindow; - ConfigView *menuView; - ConfigList *menuList; - ConfigView *configView; - ConfigList *configList; - ConfigInfoView *helpText; - QToolBar *toolBar; - QAction *backAction; - QSplitter* split1; - QSplitter* split2; -}; -- cgit v1.2.3 From a9d14d2f99c232b769c423ef40e903087a3f7877 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 14:31:31 +0200 Subject: hook in ADK version extraction, rename some stuff --- Config.in | 4 ++++ Makefile | 3 +++ config/confdata.c | 4 ++-- config/mconf.c | 16 ++++++++-------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Config.in b/Config.in index 3db3c8159..2f741cdc9 100644 --- a/Config.in +++ b/Config.in @@ -1,6 +1,10 @@ # This file is part of the OpenADK project. OpenADK is copyrighted # material, please see the LICENCE file in the top-level directory. +config ADKVERSION + string + option env="ADKVERSION" + mainmenu "OpenADK Configuration" config MODULES diff --git a/Makefile b/Makefile index 4fea27925..dfef6791e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ # This file is part of the OpenADK project. OpenADK is copyrighted # material, please see the LICENCE file in the top-level directory. +ADKVERSION= 0.1.0 +export ADKVERSION + GMAKE?= $(PWD)/scripts/make GMAKE_FMK= ${GMAKE} -f $(PWD)/mk/build.mk GMAKE_INV= ${GMAKE_FMK} --no-print-directory diff --git a/config/confdata.c b/config/confdata.c index 7cc195cbd..e869f2d9a 100644 --- a/config/confdata.c +++ b/config/confdata.c @@ -434,7 +434,7 @@ int conf_write(const char *name) if (!out) return 1; - sym = sym_lookup("KERNELVERSION", 0); + sym = sym_lookup("ADKVERSION", 0); sym_calc_value(sym); time(&now); env = getenv("KCONFIG_NOTIMESTAMP"); @@ -689,7 +689,7 @@ int conf_write_autoconf(void) return 1; } - sym = sym_lookup("KERNELVERSION", 0); + sym = sym_lookup("ADKVERSION", 0); sym_calc_value(sym); time(&now); fprintf(out, "#\n" diff --git a/config/mconf.c b/config/mconf.c index 25b60bc11..9516a5715 100644 --- a/config/mconf.c +++ b/config/mconf.c @@ -364,10 +364,10 @@ static void set_config_filename(const char *config_filename) int size; struct symbol *sym; - sym = sym_lookup("KERNELVERSION", 0); + sym = sym_lookup("ADKVERSION", 0); sym_calc_value(sym); size = snprintf(menu_backtitle, sizeof(menu_backtitle), - _("%s - Linux Kernel v%s Configuration"), + _("%s - OpenADK v%s Configuration"), config_filename, sym_get_string_value(sym)); if (size >= sizeof(menu_backtitle)) menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; @@ -904,7 +904,7 @@ int main(int ac, char **av) if (conf_get_changed()) res = dialog_yesno(NULL, _("Do you wish to save your " - "new kernel configuration?\n" + "new OpenADK configuration?\n" " to continue."), 6, 60); else @@ -916,20 +916,20 @@ int main(int ac, char **av) case 0: if (conf_write(filename)) { fprintf(stderr, _("\n\n" - "Error during writing of the kernel configuration.\n" - "Your kernel configuration changes were NOT saved." + "Error during writing of the OpenADK configuration.\n" + "Your OpenADK configuration changes were NOT saved." "\n\n")); return 1; } case -1: printf(_("\n\n" - "*** End of Linux kernel configuration.\n" - "*** Execute 'make' to build the kernel or try 'make help'." + "*** End of OpenADK configuration.\n" + "*** Execute 'make' to build the firmware or try 'make help'." "\n\n")); break; default: fprintf(stderr, _("\n\n" - "Your kernel configuration changes were NOT saved." + "Your OpenADK configuration changes were NOT saved." "\n\n")); } -- cgit v1.2.3 From 5bb02383f8f840353a7e4f64afd0bc22cbec875d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 14:40:05 +0200 Subject: add TODO entry about suboptimal mconf help texts --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 895f3c6a7..86140051d 100644 --- a/TODO +++ b/TODO @@ -17,3 +17,4 @@ - network scripts for wireless client / ap - network scripts for pppoe - publish via trac+git +- customise mconf help texts to better fit for OpenADK -- cgit v1.2.3 From d2b13826a9e485b520c232914d9c68c1a9e1f8bc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 14:47:35 +0200 Subject: drop all leading whitespaces in symbol prompts The new mconf ignores them anyway, so make it stop warning about it. --- package/apr/Config.in | 2 +- package/bogofilter/Config.in | 4 ++-- package/fetchmail/Config.in | 2 +- package/freeradius-server/Config.in | 28 +++++++++++----------- package/irssi/Config.in | 2 +- package/lighttpd/Config.in | 34 +++++++++++++-------------- package/mksh/Config.in | 2 +- package/mpd/Config.in | 10 ++++---- package/nano/Config.in | 2 +- package/olsrd/Config.in | 8 +++---- package/opensips/Config.in | 46 ++++++++++++++++++------------------- package/portmap/Config.in | 2 +- package/quagga/Config.in | 12 +++++----- package/rrdcollect/Config.in | 4 ++-- package/squid/Config.in | 16 ++++++------- package/subversion/Config.in | 2 +- package/tinyproxy/Config.in | 6 ++--- package/ulogd/Config.in | 10 ++++---- 18 files changed, 96 insertions(+), 96 deletions(-) diff --git a/package/apr/Config.in b/package/apr/Config.in index f6c5e0708..5a875e10e 100644 --- a/package/apr/Config.in +++ b/package/apr/Config.in @@ -8,7 +8,7 @@ config ADK_PACKAGE_APR http://apr.apache.org config ADK_PACKAGE_APR_THREADING - prompt " Enable threading support" + prompt "Enable threading support" bool default n depends on ADK_PACKAGE_APR diff --git a/package/bogofilter/Config.in b/package/bogofilter/Config.in index 503345cc3..922f17376 100644 --- a/package/bogofilter/Config.in +++ b/package/bogofilter/Config.in @@ -12,13 +12,13 @@ config ADK_PACKAGE_BOGOFILTER config ADK_PACKAGE_BOGOFILTER_BOGOUTIL - prompt " include bogoutil in firmware image and package file" + prompt "include bogoutil in firmware image and package file" bool default n depends on ADK_PACKAGE_BOGOFILTER config ADK_PACKAGE_BOGOFILTER_BOGOTUNE - prompt " include bogotune in firmware image and package file" + prompt "include bogotune in firmware image and package file" bool default n depends on ADK_PACKAGE_BOGOFILTER diff --git a/package/fetchmail/Config.in b/package/fetchmail/Config.in index 1cdb42cc6..5319a963f 100644 --- a/package/fetchmail/Config.in +++ b/package/fetchmail/Config.in @@ -9,7 +9,7 @@ config ADK_PACKAGE_FETCHMAIL Known to be full of security holes, beware. config ADK_PACKAGE_FETCHMAIL_SSL - bool " Enable SSL/TLS support" + bool "Enable SSL/TLS support" depends on ADK_PACKAGE_FETCHMAIL select ADK_PACKAGE_LIBOPENSSL default n diff --git a/package/freeradius-server/Config.in b/package/freeradius-server/Config.in index 344472c22..d7dc0cb03 100644 --- a/package/freeradius-server/Config.in +++ b/package/freeradius-server/Config.in @@ -10,74 +10,74 @@ config ADK_PACKAGE_FREERADIUS_SERVER http://www.freeradius.org/ config ADK_PACKAGE_FREERADIUS_DEMOCERTS - prompt " freeradius-democerts.......... Demo certificates to test the server" + prompt "freeradius-democerts.......... Demo certificates to test the server" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_CHAP - prompt " freeradius-mod-chap........... CHAP module" + prompt "freeradius-mod-chap........... CHAP module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_DETAIL - prompt " freeradius-mod-detail......... Detailed accounting module" + prompt "freeradius-mod-detail......... Detailed accounting module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_DIGEST - prompt " freeradius-mod-digest......... Digest authentication" + prompt "freeradius-mod-digest......... Digest authentication" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_FILES - prompt " freeradius-mod-files.......... Module using local files for authorization" + prompt "freeradius-mod-files.......... Module using local files for authorization" tristate default y depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_LDAP - prompt " freeradius-mod-ldap........... LDAP module" + prompt "freeradius-mod-ldap........... LDAP module" tristate default n select ADK_PACKAGE_LIBOPENLDAP depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_MSCHAP - prompt " freeradius-mod-mschap......... MS-CHAP and MS-CHAPv2 module" + prompt "freeradius-mod-mschap......... MS-CHAP and MS-CHAPv2 module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_PAP - prompt " freeradius-mod-pap............ PAP module" + prompt "freeradius-mod-pap............ PAP module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_PREPROCESS - prompt " freeradius-mod-preprocess..... Request pre-processing module" + prompt "freeradius-mod-preprocess..... Request pre-processing module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_REALM - prompt " freeradius-mod-realm.......... Realms handling module" + prompt "freeradius-mod-realm.......... Realms handling module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_SQL - prompt " freeradius-mod-sql............ Base SQL module" + prompt "freeradius-mod-sql............ Base SQL module" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER config ADK_PACKAGE_FREERADIUS_MOD_SQL_MYSQL - prompt " freeradius-mod-sql-mysql.... MySQL module" + prompt "freeradius-mod-sql-mysql.... MySQL module" tristate default n depends on ADK_CXX @@ -85,14 +85,14 @@ config ADK_PACKAGE_FREERADIUS_MOD_SQL_MYSQL select ADK_PACKAGE_LIBMYSQLCLIENT config ADK_PACKAGE_FREERADIUS_MOD_SQL_PGSQL - prompt " freeradius-mod-sql-pgsql.... PostgreSQL module" + prompt "freeradius-mod-sql-pgsql.... PostgreSQL module" tristate default n depends on ADK_PACKAGE_FREERADIUS_MOD_SQL select ADK_PACKAGE_LIBPQ config ADK_PACKAGE_FREERADIUS_UTILS - prompt " freeradius-utils.............. Misc. client utilities" + prompt "freeradius-utils.............. Misc. client utilities" tristate default n depends on ADK_PACKAGE_FREERADIUS_SERVER diff --git a/package/irssi/Config.in b/package/irssi/Config.in index f60e946ee..79047c471 100644 --- a/package/irssi/Config.in +++ b/package/irssi/Config.in @@ -10,7 +10,7 @@ config ADK_PACKAGE_IRSSI http://irssi.org config ADK_PACKAGE_IRSSI_SSL - bool " Enable SSL/TLS support" + bool "Enable SSL/TLS support" depends on ADK_PACKAGE_IRSSI select ADK_PACKAGE_LIBOPENSSL default n diff --git a/package/lighttpd/Config.in b/package/lighttpd/Config.in index f83aebb46..b56fa8bff 100644 --- a/package/lighttpd/Config.in +++ b/package/lighttpd/Config.in @@ -11,103 +11,103 @@ config ADK_PACKAGE_LIGHTTPD http://www.lighttpd.net/ config ADK_COMPILE_LIGHTTPD_WITH_OPENSSL - bool " Use OpenSSL for https support" + bool "Use OpenSSL for https support" default y depends on ADK_PACKAGE_LIGHTTPD select ADK_PACKAGE_LIBOPENSSL config ADK_PACKAGE_LIGHTTPD_MOD_ACCESSLOG - prompt " lighttpd-mod-accesslog........ Access logging module" + prompt "lighttpd-mod-accesslog........ Access logging module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_ALIAS - prompt " lighttpd-mod-alias............ Directory alias module" + prompt "lighttpd-mod-alias............ Directory alias module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_AUTH - prompt " lighttpd-mod-auth............. Authentication module" + prompt "lighttpd-mod-auth............. Authentication module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_CGI - prompt " lighttpd-mod-cgi.............. CGI module" + prompt "lighttpd-mod-cgi.............. CGI module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_EVASIVE - prompt " lighttpd-mod-evasive.......... Evasive module" + prompt "lighttpd-mod-evasive.......... Evasive module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_EXPIRE - prompt " lighttpd-mod-expire........... Expire module" + prompt "lighttpd-mod-expire........... Expire module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_FASTCGI - prompt " lighttpd-mod-fastcgi.......... FastCGI module" + prompt "lighttpd-mod-fastcgi.......... FastCGI module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_PROXY - prompt " lighttpd-mod-proxy............ Proxy module" + prompt "lighttpd-mod-proxy............ Proxy module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_REDIRECT - prompt " lighttpd-mod-redirect......... URL redirection module" + prompt "lighttpd-mod-redirect......... URL redirection module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_REWRITE - prompt " lighttpd-mod-rewrite.......... URL rewriting module" + prompt "lighttpd-mod-rewrite.......... URL rewriting module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SETENV - prompt " lighttpd-mod-setenv........... Environment variable setting module" + prompt "lighttpd-mod-setenv........... Environment variable setting module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SIMPLE_VHOST - prompt " lighttpd-mod-simple-vhost..... Simple virtual hosting module" + prompt "lighttpd-mod-simple-vhost..... Simple virtual hosting module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_SSI - prompt " lighttpd-mod-ssi.............. SSI module" + prompt "lighttpd-mod-ssi.............. SSI module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_STATUS - prompt " lighttpd-mod-status........... Server status display module" + prompt "lighttpd-mod-status........... Server status display module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_USERTRACK - prompt " lighttpd-mod-usertrack........ User tracking module" + prompt "lighttpd-mod-usertrack........ User tracking module" tristate default n depends on ADK_PACKAGE_LIGHTTPD config ADK_PACKAGE_LIGHTTPD_MOD_WEBDAV - prompt " lighttpd-mod-webdav........... webdav module" + prompt "lighttpd-mod-webdav........... webdav module" tristate default n depends on ADK_PACKAGE_LIGHTTPD diff --git a/package/mksh/Config.in b/package/mksh/Config.in index dacca6427..50578b0d2 100644 --- a/package/mksh/Config.in +++ b/package/mksh/Config.in @@ -21,7 +21,7 @@ config ADK_PACKAGE_MKSH http://mirbsd.de/mksh config ADK_PACKAGE_MKSH_FULL - bool " Include all features" + bool "Include all features" depends on ADK_PACKAGE_MKSH default y help diff --git a/package/mpd/Config.in b/package/mpd/Config.in index 0d0cde14a..89a98f24e 100644 --- a/package/mpd/Config.in +++ b/package/mpd/Config.in @@ -15,7 +15,7 @@ config ADK_PACKAGE_MPD http://www.musicpd.org/ config ADK_COMPILE_MPD_WITH_MP3 - prompt " MP3 support" + prompt "MP3 support" bool default y depends on ADK_PACKAGE_MPD @@ -25,7 +25,7 @@ config ADK_COMPILE_MPD_WITH_MP3 Enable mp3 support (libmad). config ADK_COMPILE_MPD_WITH_MP4 - prompt " MP4/AAC support" + prompt "MP4/AAC support" bool default y depends on ADK_PACKAGE_MPD @@ -34,7 +34,7 @@ config ADK_COMPILE_MPD_WITH_MP4 Enable mp4/aac support (libfaad2). config ADK_COMPILE_MPD_OGG - prompt " Ogg/Vorbis Support" + prompt "Ogg/Vorbis Support" tristate depends on ADK_PACKAGE_MPD select ADK_COMPILE_MPD_WITH_OGG if ADK_COMPILE_MPD_OGG_FLOAT @@ -73,7 +73,7 @@ config ADK_COMPILE_MPD_WITH_TREMOR Can not be used with shout plugin. config ADK_COMPILE_MPD_WITH_FLAC - prompt " FLAC Support" + prompt "FLAC Support" bool default y depends on ADK_PACKAGE_MPD @@ -82,7 +82,7 @@ config ADK_COMPILE_MPD_WITH_FLAC Enable flac support (libflac). config ADK_COMPILE_MPD_WITH_SHOUT - prompt " Shout Support (Streaming support)" + prompt "Shout Support (Streaming support)" bool default y depends on ADK_PACKAGE_MPD diff --git a/package/nano/Config.in b/package/nano/Config.in index 19b9ca6d9..9ba6cc157 100644 --- a/package/nano/Config.in +++ b/package/nano/Config.in @@ -9,7 +9,7 @@ config ADK_PACKAGE_NANO http://www.nano-editor.org/ config ADK_PACKAGE_NANO_TINY - prompt " only compile a minimal nano (using --enable-tiny)" + prompt "only compile a minimal nano (using --enable-tiny)" bool default y depends on ADK_PACKAGE_NANO diff --git a/package/olsrd/Config.in b/package/olsrd/Config.in index a4f25efe3..4d8d47429 100644 --- a/package/olsrd/Config.in +++ b/package/olsrd/Config.in @@ -10,25 +10,25 @@ config ADK_PACKAGE_OLSRD http://www.olsr.org/ config ADK_PACKAGE_OLSRD_MOD_DYN_GW - prompt " olsrd-mod-dyn-gw.............. Dynamic internet gateway plugin" + prompt "olsrd-mod-dyn-gw.............. Dynamic internet gateway plugin" tristate default n depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_HTTPINFO - prompt " olsrd-mod-httpinfo............ Small informative web server plugin" + prompt "olsrd-mod-httpinfo............ Small informative web server plugin" tristate default n depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_NAMESERVICE - prompt " olsrd-mod-nameservice......... Lightweight hostname resolver plugin" + prompt "olsrd-mod-nameservice......... Lightweight hostname resolver plugin" tristate default n depends on ADK_PACKAGE_OLSRD config ADK_PACKAGE_OLSRD_MOD_TAS - prompt " olsrd-mod-tas................. Tiny Application Server (TAS) plugin for olsrd" + prompt "olsrd-mod-tas................. Tiny Application Server (TAS) plugin for olsrd" tristate default n depends on ADK_PACKAGE_OLSRD diff --git a/package/opensips/Config.in b/package/opensips/Config.in index fce57634e..31c565218 100644 --- a/package/opensips/Config.in +++ b/package/opensips/Config.in @@ -10,7 +10,7 @@ config ADK_PACKAGE_OPENSIPS configurable, free SIP server. config ADK_PACKAGE_OPENSIPS_MOD_ACCOUNTING - prompt " opensips-mod-acc............... Accounting support" + prompt "opensips-mod-acc............... Accounting support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -18,7 +18,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_ACCOUNTING Enable accounting support config ADK_PACKAGE_OPENSIPS_MOD_AUTH - prompt " opensips-mod-auth.............. Authentication support" + prompt "opensips-mod-auth.............. Authentication support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -26,7 +26,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AUTH Enable authentication support config ADK_PACKAGE_OPENSIPS_MOD_AUTH_DB - prompt " opensips-mod-auth-db......... Authentication with database support" + prompt "opensips-mod-auth-db......... Authentication with database support" tristate default n depends on ADK_PACKAGE_OPENSIPS_MOD_AUTH @@ -34,7 +34,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AUTH_DB Enable authentication with database support config ADK_PACKAGE_OPENSIPS_MOD_AVPOPS - prompt " opensips-mod-avpops............ AVP options support" + prompt "opensips-mod-avpops............ AVP options support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -42,7 +42,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_AVPOPS Enable AVP options support config ADK_PACKAGE_OPENSIPS_MOD_DISPATCHER - prompt " opensips-mod-dispatcher........ dispatcher support" + prompt "opensips-mod-dispatcher........ dispatcher support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -50,7 +50,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_DISPATCHER Enable dispatcher options support config ADK_PACKAGE_OPENSIPS_MOD_DIVERSION - prompt " opensips-mod-diversion......... diversion support" + prompt "opensips-mod-diversion......... diversion support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -58,7 +58,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_DIVERSION Enable diversion options support config ADK_PACKAGE_OPENSIPS_MOD_FLATSTORE - prompt " opensips-mod-flatstore......... flatstore support" + prompt "opensips-mod-flatstore......... flatstore support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -66,7 +66,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_FLATSTORE Enable flatstore support config ADK_PACKAGE_OPENSIPS_MOD_GFLAGS - prompt " opensips-mod-gflags............ gflags support" + prompt "opensips-mod-gflags............ gflags support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -74,7 +74,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_GFLAGS Enable GFlags support config ADK_PACKAGE_OPENSIPS_MOD_GROUP - prompt " opensips-mod-group............. group support" + prompt "opensips-mod-group............. group support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -82,7 +82,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_GROUP Enable group support config ADK_PACKAGE_OPENSIPS_MOD_MEDIAPROXY - prompt " opensips-mod-mediaproxy........ Mediaproxy support" + prompt "opensips-mod-mediaproxy........ Mediaproxy support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -90,7 +90,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_MEDIAPROXY Enable mediaproxy support config ADK_PACKAGE_OPENSIPS_MOD_MSILO - prompt " opensips-mod-msilo............. MSilo support" + prompt "opensips-mod-msilo............. MSilo support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -98,7 +98,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_MSILO Enable msilo support config ADK_PACKAGE_OPENSIPS_MOD_NATHELPER - prompt " opensips-mod-nathelper......... NAT helper support" + prompt "opensips-mod-nathelper......... NAT helper support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -106,7 +106,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_NATHELPER NAT helper support config ADK_PACKAGE_OPENSIPS_MOD_OPTIONS - prompt " opensips-mod-options........... options support" + prompt "opensips-mod-options........... options support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -114,7 +114,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_OPTIONS Enable options support config ADK_PACKAGE_OPENSIPS_MOD_PDT - prompt " opensips-mod-pdt............... PDT support" + prompt "opensips-mod-pdt............... PDT support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -122,7 +122,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PDT Enable pdt support config ADK_PACKAGE_OPENSIPS_MOD_PERMISSIONS - prompt " opensips-mod-permissions....... Permissions support" + prompt "opensips-mod-permissions....... Permissions support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -130,7 +130,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PERMISSIONS Enable permissions support config ADK_PACKAGE_OPENSIPS_MOD_PIKE - prompt " opensips-mod-pike.............. PIKE support" + prompt "opensips-mod-pike.............. PIKE support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -138,7 +138,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_PIKE Enable pike support config ADK_PACKAGE_OPENSIPS_MOD_SMS - prompt " opensips-mod-sms............... SMS support" + prompt "opensips-mod-sms............... SMS support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -146,7 +146,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_SMS SMS support config ADK_PACKAGE_OPENSIPS_MOD_SPEEDDIAL - prompt " opensips-mod-speeddial......... Speed Dial support" + prompt "opensips-mod-speeddial......... Speed Dial support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -154,7 +154,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_SPEEDDIAL Speed Dial support config ADK_PACKAGE_OPENSIPS_MOD_UAC - prompt " opensips-mod-uac............... UAC support" + prompt "opensips-mod-uac............... UAC support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -162,7 +162,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_UAC Enable UAC support config ADK_PACKAGE_OPENSIPS_MOD_UAC_REDIRECT - prompt " opensips-mod-uac............... UAC redirect support" + prompt "opensips-mod-uac............... UAC redirect support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -170,7 +170,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_UAC_REDIRECT Enable UAC redirect support config ADK_PACKAGE_OPENSIPS_MOD_URI - prompt " opensips-mod-uri............... URI support" + prompt "opensips-mod-uri............... URI support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -178,7 +178,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_URI Enable URI support config ADK_PACKAGE_OPENSIPS_MOD_URI_DB - prompt " opensips-mod-uri-db............ URI database support" + prompt "opensips-mod-uri-db............ URI database support" tristate default n depends on ADK_PACKAGE_OPENSIPS @@ -186,7 +186,7 @@ config ADK_PACKAGE_OPENSIPS_MOD_URI_DB Enable URI database support config ADK_PACKAGE_OPENSIPS_MOD_XLOG - prompt " opensips-mod-xlog.............. Logging support" + prompt "opensips-mod-xlog.............. Logging support" tristate default n depends on ADK_PACKAGE_OPENSIPS diff --git a/package/portmap/Config.in b/package/portmap/Config.in index ac4415a05..cc5169ce9 100644 --- a/package/portmap/Config.in +++ b/package/portmap/Config.in @@ -8,7 +8,7 @@ config ADK_PACKAGE_PORTMAP to make RPC calls. Services that use RPC include NFS and NIS. config ADK_PACKAGE_PORTMAP_LIBWRAP - bool " Use tcp_wrappers" + bool "Use tcp_wrappers" default n depends on ADK_PACKAGE_PORTMAP select ADK_PACKAGE_LIBWRAP diff --git a/package/quagga/Config.in b/package/quagga/Config.in index 331e38ca6..446d7ab9e 100644 --- a/package/quagga/Config.in +++ b/package/quagga/Config.in @@ -13,7 +13,7 @@ config ADK_PACKAGE_QUAGGA http://www.quagga.net/ config ADK_PACKAGE_QUAGGA_BGPD - prompt " quagga-bgpd................... BGPv4, BGPv4+, BGPv4- routing engine" + prompt "quagga-bgpd................... BGPv4, BGPv4+, BGPv4- routing engine" tristate default n depends on ADK_PACKAGE_QUAGGA @@ -22,7 +22,7 @@ config ADK_PACKAGE_QUAGGA_BGPD software. config ADK_PACKAGE_QUAGGA_OSPFD - prompt " quagga-ospfd.................. OSPFv2 routing engine" + prompt "quagga-ospfd.................. OSPFv2 routing engine" tristate default n depends on ADK_PACKAGE_QUAGGA @@ -30,7 +30,7 @@ config ADK_PACKAGE_QUAGGA_OSPFD An OSPFv2 (IPv4) routing engine for use with Quagga routing software. config ADK_PACKAGE_QUAGGA_OSPF6D - prompt " quagga-ospf6d................. OSPFv3 routing engine" + prompt "quagga-ospf6d................. OSPFv3 routing engine" tristate default n depends on ADK_PACKAGE_QUAGGA @@ -39,7 +39,7 @@ config ADK_PACKAGE_QUAGGA_OSPF6D An OSPFv3 (IPv6) routing engine for use with Quagga routing software. config ADK_PACKAGE_QUAGGA_RIPD - prompt " quagga-ripd................... RIP routing engine" + prompt "quagga-ripd................... RIP routing engine" tristate default n depends on ADK_PACKAGE_QUAGGA @@ -47,7 +47,7 @@ config ADK_PACKAGE_QUAGGA_RIPD A RIP (IPv4) routing engine for use with Quagga routing software. config ADK_PACKAGE_QUAGGA_RIPNGD - prompt " quagga-ripngd................. RIPNG routing engine" + prompt "quagga-ripngd................. RIPNG routing engine" tristate default n depends on ADK_PACKAGE_QUAGGA @@ -56,7 +56,7 @@ config ADK_PACKAGE_QUAGGA_RIPNGD A RIPNG (IPv6) routing engine for use with Quagga routing software. config ADK_PACKAGE_QUAGGA_VTYSH - prompt " quagga-vtysh.................. integrated shell for Quagga routing software" + prompt "quagga-vtysh.................. integrated shell for Quagga routing software" tristate default n depends on ADK_PACKAGE_QUAGGA diff --git a/package/rrdcollect/Config.in b/package/rrdcollect/Config.in index 240cddc3b..1c35e092a 100644 --- a/package/rrdcollect/Config.in +++ b/package/rrdcollect/Config.in @@ -1,5 +1,5 @@ config ADK_PACKAGE_RRDCOLLECT - prompt " rrdcollect...................... Round-Robin Database (RRD) collecting daemon" + prompt "rrdcollect...................... Round-Robin Database (RRD) collecting daemon" tristate default n depends on ADK_PACKAGE_LIBRRD || ADK_PACKAGE_LIBRRD1 @@ -15,7 +15,7 @@ config ADK_PACKAGE_RRDCOLLECT This package contains only the deamon program. config ADK_PACKAGE_RRDCOLLECT_EXAMPLE - prompt " rrdcollect-example.......... Example setup for RRD collecting daemon above" + prompt "rrdcollect-example.......... Example setup for RRD collecting daemon above" tristate default n depends on ADK_PACKAGE_RRDCOLLECT diff --git a/package/squid/Config.in b/package/squid/Config.in index 29e4e7489..483b27468 100644 --- a/package/squid/Config.in +++ b/package/squid/Config.in @@ -16,56 +16,56 @@ config ADK_PACKAGE_SQUID menu "squid............................. proxy and web cache modules" config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_GETPWNAM - prompt " squid-mod-basic-auth-getpwnam....... getpwnam basic authentication helper" + prompt "squid-mod-basic-auth-getpwnam....... getpwnam basic authentication helper" tristate depends on ADK_PACKAGE_SQUID help Password basic authentication helper config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_NCSA - prompt " squid-mod-basic-auth-ncsa........... NCSA basic authentication helper" + prompt "squid-mod-basic-auth-ncsa........... NCSA basic authentication helper" tristate depends on ADK_PACKAGE_SQUID help NCSA basic authentication helper config ADK_PACKAGE_SQUID_MOD_BASIC_AUTH_SMB - prompt " squid-mod-basic-auth-smb............ Samba basic authentication helper" + prompt "squid-mod-basic-auth-smb............ Samba basic authentication helper" tristate depends on ADK_PACKAGE_SQUID help Samba basic authentication helper config ADK_PACKAGE_SQUID_MOD_DIGEST_AUTH_PASSWORD - prompt " squid-mod-digest-auth-password...... Password digest authentication ehlper" + prompt "squid-mod-digest-auth-password...... Password digest authentication ehlper" tristate depends on ADK_PACKAGE_SQUID help Password digest authentication helper config ADK_PACKAGE_SQUID_MOD_EXTERNAL_ACL_IP_USER - prompt " squid-mod-external-acl-ip_user...... IP user external ACL helper" + prompt "squid-mod-external-acl-ip_user...... IP user external ACL helper" tristate depends on ADK_PACKAGE_SQUID help IP user external ACL helper config ADK_PACKAGE_SQUID_MOD_EXTERNAL_ACL_UNIX_GROUP - prompt " squid-mod-external-acl-unix-group... Unix group external ACL helper" + prompt "squid-mod-external-acl-unix-group... Unix group external ACL helper" tristate depends on ADK_PACKAGE_SQUID help Unix group external ACL helper config ADK_PACKAGE_SQUID_MOD_NTLM_AUTH_FAKEAUTH - prompt " squid-mod-ntlm-auth-fakeauth........ Fakeauth NTLM authentication helper" + prompt "squid-mod-ntlm-auth-fakeauth........ Fakeauth NTLM authentication helper" tristate depends on ADK_PACKAGE_SQUID help Fakeauth NTLM authentication helper config ADK_PACKAGE_SQUID_MOD_NTLM_AUTH_SMB_AUTH - prompt " squid-mod-ntlm-auth-smb-auth........ Samba NTLM authentication helper" + prompt "squid-mod-ntlm-auth-smb-auth........ Samba NTLM authentication helper" tristate depends on ADK_PACKAGE_SQUID help diff --git a/package/subversion/Config.in b/package/subversion/Config.in index b8e07d595..a7bb57950 100644 --- a/package/subversion/Config.in +++ b/package/subversion/Config.in @@ -12,7 +12,7 @@ config ADK_PACKAGE_SUBVERSION http://subversion.tigris.org config ADK_PACKAGE_SUBVERSION_NEON - prompt " Enable interaction with remote repositories over WebDAV" + prompt "Enable interaction with remote repositories over WebDAV" bool default n depends on ADK_PACKAGE_SUBVERSION diff --git a/package/tinyproxy/Config.in b/package/tinyproxy/Config.in index fd3a449f1..293d8ec69 100644 --- a/package/tinyproxy/Config.in +++ b/package/tinyproxy/Config.in @@ -10,19 +10,19 @@ config ADK_PACKAGE_TINYPROXY http://tinyproxy.sourceforge.net config ADK_COMPILE_TINYPROXY_WITH_TRANSPARENT_PROXY - prompt " Enable transparent proxying" + prompt "Enable transparent proxying" bool default y depends on ADK_PACKAGE_TINYPROXY config ADK_COMPILE_TINYPROXY_WITH_FILTER - prompt " Enable filtering support" + prompt "Enable filtering support" bool default y depends on ADK_PACKAGE_TINYPROXY config ADK_COMPILE_TINYPROXY_WITH_UPSTREAM - prompt " Enable upstream support" + prompt "Enable upstream support" bool default y depends on ADK_PACKAGE_TINYPROXY diff --git a/package/ulogd/Config.in b/package/ulogd/Config.in index 20a276bee..dc0949777 100644 --- a/package/ulogd/Config.in +++ b/package/ulogd/Config.in @@ -11,7 +11,7 @@ config ADK_PACKAGE_ULOGD http://gnumonks.org/projects/ulogd config ADK_PACKAGE_ULOGD_MOD_MYSQL - prompt " ulogd-mod-mysql............... Output plugin for logging into a MySQL database" + prompt "ulogd-mod-mysql............... Output plugin for logging into a MySQL database" tristate default n depends on ADK_CXX @@ -19,28 +19,28 @@ config ADK_PACKAGE_ULOGD_MOD_MYSQL select ADK_PACKAGE_LIBMYSQLCLIENT config ADK_PACKAGE_ULOGD_MOD_PCAP - prompt " ulogd-mod-pcap................. Output plugin for logging into pcap format" + prompt "ulogd-mod-pcap................. Output plugin for logging into pcap format" tristate default n depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBPCAP config ADK_PACKAGE_ULOGD_MOD_PGSQL - prompt " ulogd-mod-pgsql............... Output plugin for logging into a PostgreSQL database" + prompt "ulogd-mod-pgsql............... Output plugin for logging into a PostgreSQL database" tristate default n depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBPQ config ADK_PACKAGE_ULOGD_MOD_SQLITE - prompt " ulogd-mod-sqlite.............. Output plugin for logging into an SQLite database" + prompt "ulogd-mod-sqlite.............. Output plugin for logging into an SQLite database" tristate default n depends on ADK_PACKAGE_ULOGD select ADK_PACKAGE_LIBSQLITE config ADK_PACKAGE_ULOGD_MOD_EXTRA - prompt " ulogd-mod-extra............... All other plugins" + prompt "ulogd-mod-extra............... All other plugins" tristate default n depends on ADK_PACKAGE_ULOGD -- cgit v1.2.3 From 02fabc4618d78d960bae068196aa2890bdb9296b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 15:01:07 +0200 Subject: further renaming (s/Linux Kernel/OpenADK/) --- config/confdata.c | 6 +++--- config/zconf.tab.c_shipped | 2 +- config/zconf.y | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/confdata.c b/config/confdata.c index e869f2d9a..4a79c72bb 100644 --- a/config/confdata.c +++ b/config/confdata.c @@ -443,7 +443,7 @@ int conf_write(const char *name) fprintf(out, _("#\n" "# Automatically generated make config: don't edit\n" - "# Linux kernel version: %s\n" + "# OpenADK version: %s\n" "%s%s" "#\n"), sym_get_string_value(sym), @@ -694,13 +694,13 @@ int conf_write_autoconf(void) time(&now); fprintf(out, "#\n" "# Automatically generated make config: don't edit\n" - "# Linux kernel version: %s\n" + "# OpenADK version: %s\n" "# %s" "#\n", sym_get_string_value(sym), ctime(&now)); fprintf(out_h, "/*\n" " * Automatically generated C config: don't edit\n" - " * Linux kernel version: %s\n" + " * OpenADK version: %s\n" " * %s" " */\n" "#define AUTOCONF_INCLUDED\n", diff --git a/config/zconf.tab.c_shipped b/config/zconf.tab.c_shipped index 95df833b5..3bdcb3a97 100644 --- a/config/zconf.tab.c_shipped +++ b/config/zconf.tab.c_shipped @@ -2259,7 +2259,7 @@ void conf_parse(const char *name) modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; - rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + rootmenu.prompt = menu_add_prompt(P_MENU, "OpenADK Configuration", NULL); #if YYDEBUG if (getenv("ZCONF_DEBUG")) diff --git a/config/zconf.y b/config/zconf.y index 9710b8246..b4240c846 100644 --- a/config/zconf.y +++ b/config/zconf.y @@ -476,7 +476,7 @@ void conf_parse(const char *name) modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; - rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + rootmenu.prompt = menu_add_prompt(P_MENU, "OpenADK Configuration", NULL); #if YYDEBUG if (getenv("ZCONF_DEBUG")) -- cgit v1.2.3 From cda64efca568ec61c064b44f494f58f7a08bd4e7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 2 Aug 2009 15:01:15 +0200 Subject: force entering the config/ subdir in ANY case This is a general thing: when depending on binaries in subdirs AND dependency checking for those binaries is done from within the subdir Makefile (i.e. the decision about whether to recompile or not), we always have to force entering the subdir or otherwise no check is performed if the upper level dependency ("does the subdir binary exist?") is met. --- mk/build.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mk/build.mk b/mk/build.mk index c74e16045..399d57216 100644 --- a/mk/build.mk +++ b/mk/build.mk @@ -158,6 +158,9 @@ all: menuconfig # configuration # --------------------------------------------------------------------------- +# force entering the subdir, as dependency checking is done there +.PHONY: $(CONFIG)/conf $(CONFIG)/mconf + $(CONFIG)/conf: @$(MAKE) -C $(CONFIG) conf -- cgit v1.2.3 From 33c93b411498519da25f21b24abd1b1cb2308d19 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Aug 2009 13:24:30 +0200 Subject: ignore .cfg* --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 931ccdf1e..bdba437cd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ toolchain_build_*/ .prereq_done .config* .cfg/ +.cfg.*/ cross_*/ root_*/ bin_*/ -- cgit v1.2.3 From d376828e62b314c66ebb26cb3e3fa9d6b4f7a93a Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Aug 2009 13:25:56 +0200 Subject: add git package --- package/Config.in | 1 + package/Depends.mk | 11 +---------- package/Makefile | 1 + package/git/Config.in | 9 +++++++++ package/git/Makefile | 37 +++++++++++++++++++++++++++++++++++++ package/git/patches/patch-Makefile | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 package/git/Config.in create mode 100644 package/git/Makefile create mode 100644 package/git/patches/patch-Makefile diff --git a/package/Config.in b/package/Config.in index 96aeec3aa..eb1f5aa65 100644 --- a/package/Config.in +++ b/package/Config.in @@ -245,6 +245,7 @@ menu "Misc" source "package/cups/Config.in" source "package/fakeidentd/Config.in" source "package/gkrellmd/Config.in" +source "package/git/Config.in" source "package/net-snmp/Config.in" source "package/nut/Config.in" source "package/openldap/Config.in" diff --git a/package/Depends.mk b/package/Depends.mk index 9a45f5823..ef792d9df 100644 --- a/package/Depends.mk +++ b/package/Depends.mk @@ -47,6 +47,7 @@ gatling-compile: libowfat-compile libiconv-compile gcc-compile: gmp-compile mpfr-compile gdb-compile: ncurses-compile readline-compile gettext-compile: libiconv-compile libpthread-compile +git-compile: openssl-compile curl-compile expat-compile gkrellmd-compile: glib-compile glib-compile: gettext-compile libiconv-compile gmediaserver-compile: id3lib-compile libupnp-compile @@ -245,22 +246,12 @@ apr-compile: libpthread-compile endif asterisk-compile: ncurses-compile openssl-compile zlib-compile curl-compile popt-compile -ifneq ($(ADK_PACKAGE_ASTERISK_CHAN_BLUETOOTH),) -asterisk-compile: bluez-compile -endif ifneq ($(ADK_PACKAGE_ASTERISK_CODEC_SPEEX),) asterisk-compile: speex-compile endif ifneq ($(ADK_PACKAGE_ASTERISK_PGSQL),) asterisk-compile: postgresql-compile endif -ifneq ($(ADK_PACKAGE_ASTERISK_MYSQL),) -asterisk-compile: mysql-compile -endif -ifneq ($(ADK_PACKAGE_ASTERISK_SQLITE),) -asterisk-compile: sqlite-compile -endif - freeradius-client-compile: openssl-compile freeradius-server-compile: libtool-compile openssl-compile diff --git a/package/Makefile b/package/Makefile index 68d6cc5f5..a51c4b42f 100644 --- a/package/Makefile +++ b/package/Makefile @@ -102,6 +102,7 @@ package-$(ADK_PACKAGE_GCC) += gcc package-$(ADK_PACKAGE_GDB) += gdb package-$(ADK_PACKAGE_GDBSERVER) += gdbserver package-$(ADK_PACKAGE_GETTEXT) += gettext +package-$(ADK_PACKAGE_GIT) += git package-$(ADK_PACKAGE_GKRELLMD) += gkrellmd package-$(ADK_PACKAGE_GLIB) += glib ifeq (${ADK_TARGET_LIB_GLIBC},y) diff --git a/package/git/Config.in b/package/git/Config.in new file mode 100644 index 000000000..0ee3e3ea3 --- /dev/null +++ b/package/git/Config.in @@ -0,0 +1,9 @@ +config ADK_PACKAGE_GIT + prompt "git............................... fast version control system" + tristate + select ADK_PACKAGE_LIBOPENSSL + select ADK_PACKAGE_LIBCURL + select ADK_PACKAGE_LIBEXPAT + default n + help + Fast version control system. diff --git a/package/git/Makefile b/package/git/Makefile new file mode 100644 index 000000000..9df88b92b --- /dev/null +++ b/package/git/Makefile @@ -0,0 +1,37 @@ +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +include $(TOPDIR)/rules.mk + +PKG_NAME:= git +PKG_VERSION:= 1.6.3.3 +PKG_RELEASE:= 1 +PKG_MD5SUM:= a634d76881f3bd6b92cb1892ea5f88fe +PKG_DESCR:= fast version control system +PKG_SECTION:= misc +PKG_DEPENDS:= openssl curl +PKG_URL:= http://git-scm.com +PKG_SITES:= http://kernel.org/pub/software/scm/git/ + +include $(TOPDIR)/mk/package.mk + +$(eval $(call PKG_template,GIT,${PKG_NAME},$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) + +TCFLAGS+= -DNO_NSEC -DNO_TCLTK -DNO_PERL +CONFIGURE_STYLE:= gnu +CONFIGURE_ENV+= ac_cv_c_c99_format=yes \ + ac_cv_fread_reads_directories=no \ + ac_cv_snprintf_returns_bogus=no +BUILD_STYLE:= auto +INSTALL_STYLE:= auto + +post-install: + $(INSTALL_DIR) $(IDIR_GIT)/usr/bin $(IDIR_GIT)/usr/sbin/git-core + $(CP) $(WRKINST)/usr/bin/git $(IDIR_GIT)/usr/bin + $(CP) $(WRKINST)/usr/bin/git-shell $(IDIR_GIT)/usr/bin + $(CP) $(WRKINST)/usr/bin/git-receive-pack $(IDIR_GIT)/usr/bin + $(CP) $(WRKINST)/usr/bin/git-upload-pack $(IDIR_GIT)/usr/bin + $(CP) $(WRKINST)/usr/bin/git-upload-archive $(IDIR_GIT)/usr/bin + ${CP} $(WRKINST)/usr/sbin/git-core/* $(IDIR_GIT)/usr/sbin/git-core + +include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/git/patches/patch-Makefile b/package/git/patches/patch-Makefile new file mode 100644 index 000000000..46b1488e5 --- /dev/null +++ b/package/git/patches/patch-Makefile @@ -0,0 +1,32 @@ +use symlinks instead of hardlinks +--- git-1.6.3.3.orig/Makefile 2009-06-22 08:24:25.000000000 +0200 ++++ git-1.6.3.3/Makefile 2009-07-24 20:59:26.186421458 +0200 +@@ -215,7 +215,7 @@ bindir_relative = bin + bindir = $(prefix)/$(bindir_relative) + mandir = share/man + infodir = share/info +-gitexecdir = libexec/git-core ++gitexecdir = bin + sharedir = $(prefix)/share + template_dir = share/git-core/templates + htmldir = share/doc/git-doc +@@ -1239,7 +1239,6 @@ builtin-help.o: builtin-help.c common-cm + + $(BUILT_INS): git$X + $(QUIET_BUILT_IN)$(RM) $@ && \ +- ln git$X $@ 2>/dev/null || \ + ln -s git$X $@ 2>/dev/null || \ + cp git$X $@ + +@@ -1554,11 +1553,9 @@ endif + execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ + { $(RM) "$$execdir/git-add$X" && \ + test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \ +- ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \ + cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \ + { for p in $(filter-out git-add$X,$(BUILT_INS)); do \ + $(RM) "$$execdir/$$p" && \ +- ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \ + ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \ + cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \ + done; } && \ -- cgit v1.2.3 From 4e4a2f5a1d86ce0e2b79a8b8f6b150226913582f Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Aug 2009 14:22:26 +0200 Subject: rename some description --- target/Config.in | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/Config.in b/target/Config.in index b2c29d0d0..d569d629e 100644 --- a/target/Config.in +++ b/target/Config.in @@ -346,6 +346,7 @@ config ADK_TARGET_ROOTFS_INITRAMFS ADK_LINUX_MIPS64EL_QEMU || \ ADK_LINUX_RESCUE || \ ADK_LINUX_MIPS64_LEMOTE + select ADK_KERNEL_BLK_DEV_INITRD help create an read-only initramfs system. @@ -393,12 +394,13 @@ config ADK_TARGET_ROOTFS_EXT2_CF inside your hardware and want to boot from it. config ADK_TARGET_ROOTFS_EXT2 - bool "read-write filesystem for qemu emulator" + bool "Ext2 read-write filesystem" depends on ADK_LINUX_QEMU || \ - ADK_LINUX_XSCALE_ZAURUS + ADK_LINUX_XSCALE_ZAURUS || \ + ADK_LINUX_MIPS64_LEMOTE select ADK_KERNEL_EXT2_FS help - Use this option if you compile for qemu. + Use this option if your rootfs is ext2. endchoice config ADK_SSP -- cgit v1.2.3 From 1c47490f586071528b387edc46e531c88bd77dc7 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Aug 2009 14:23:21 +0200 Subject: update openswan, try to use both IPsec implementations --- package/openswan/Config.in | 20 +++++++ package/openswan/Makefile | 70 ++++++++++------------ package/openswan/patches/patch-Makefile_inc | 19 +++++- .../patches/patch-programs_Makefile_program | 6 +- .../patches/patch-programs_ikeping_ikeping_c | 6 +- target/linux/config/Config.in.ipsec | 52 ++++++++++++++++ target/linux/config/Config.in.network | 1 + 7 files changed, 128 insertions(+), 46 deletions(-) create mode 100644 target/linux/config/Config.in.ipsec diff --git a/package/openswan/Config.in b/package/openswan/Config.in index 9bb43fa5c..172d02679 100644 --- a/package/openswan/Config.in +++ b/package/openswan/Config.in @@ -8,3 +8,23 @@ config ADK_PACKAGE_OPENSWAN Openswan is an implementation of IPsec for Linux. http://www.openswan.org/ + +choice +prompt "IPSec stack to use" +depends ADK_PACKAGE_OPENSWAN +config ADK_COMPILE_OPENSWAN_WITH_NETKEY + prompt "NETKEY - use Linux integrated IPSec Stack" + select ADK_KPACKAGE_KMOD_NET_KEY + select ADK_KPACKAGE_KMOD_INET_XFRM_MODE_TUNNEL + select ADK_KPACKAGE_KMOD_INET_XFRM_MODE_TRANSPORT + select ADK_KPACKAGE_KMOD_INET_ESP + select ADK_KPACKAGE_KMOD_INET_AH + bool + help + +config ADK_COMPILE_OPENSWAN_WITH_KLIPS + prompt "KLIPS - use OpenS/WAN IPSec Stack" + bool + help + +endchoice diff --git a/package/openswan/Makefile b/package/openswan/Makefile index 2fdb07849..3c417135d 100644 --- a/package/openswan/Makefile +++ b/package/openswan/Makefile @@ -4,9 +4,9 @@ include ${TOPDIR}/rules.mk PKG_NAME:= openswan -PKG_VERSION:= 2.6.21 +PKG_VERSION:= 2.6.22 PKG_RELEASE:= 1 -PKG_MD5SUM:= ba9da6c90e0f5fe856767d7510ce371f +PKG_MD5SUM:= 9a30009bade8a1b09fba27680c87cf72 PKG_DESCR:= IPSec software PKG_SECTION:= net PKG_DEPENDS:= ip libgmp @@ -18,42 +18,36 @@ include ${TOPDIR}/mk/package.mk $(eval $(call PKG_template,OPENSWAN,${PKG_NAME},${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) -FLAGS:= ${TCFLAGS} ${TCPPFLAGS} ${TLDFLAGS} - -do-build: - ${MAKE} -C ${WRKBUILD} \ - ${TARGET_CONFIGURE_OPTS} \ - KERNELSRC="${LINUX_DIR}" \ - ARCH="${ARCH}" \ - USERCOMPILE="${FLAGS}" \ - EXTRA_INCLUDE="${TCPPFLAGS}" \ - EXTRA_LIBS="${TLDFLAGS}" \ - IPSECDIR="/usr/lib/ipsec" \ - INC_USRLOCAL="/usr" \ - MODPROBE="insmod" \ - OSDEP="linux" \ - BUILDENV="linux" \ - programs - -do-install: - ${MAKE} -C ${WRKBUILD} \ - ${TARGET_CONFIGURE_OPTS} \ - DESTDIR="${IDIR_OPENSWAN}" \ - KERNELSRC="${LINUX_DIR}" \ - ARCH="${ARCH}" \ - USERCOMPILE="${FLAGS}" \ - IPSECDIR="/usr/lib/ipsec" \ - INC_USRLOCAL="/usr" \ - MODPROBE="insmod" \ - OSDEP="linux" \ - BUILDENV="linux" \ - install - rm -rf ${IDIR_OPENSWAN}/usr/share - rm -rf ${IDIR_OPENSWAN}/usr/man - rm -rf ${IDIR_OPENSWAN}/var - mv ${IDIR_OPENSWAN}/etc/rc.d/init.d/ipsec \ +#ifeq ($(ADK_COMPILE_OPENSWAN_WITH_NETKEY),y) +#XAKE_FLAGS+= USE_KLIPS=false USE_NETKEY=true +#endif + +#ifeq ($(ADK_COMPILE_OPENSWAN_WITH_KLIPS),y) +#XAKE_FLAGS+= USE_KLIPS=true USE_NETKEY=false +#endif + +XAKE_FLAGS+= KERNELSRC="${LINUX_DIR}" \ + IPSECDIR="/usr/lib/ipsec" \ + INC_USRLOCAL="/usr" \ + MODPROBE="insmod" \ + OSDEP="linux" \ + BUILDENV="linux" + +BUILD_STYLE:= auto +INSTALL_STYLE:= auto +ALL_TARGET:= programs + +post-install: + ${INSTALL_DIR} ${IDIR_OPENSWAN}/usr/lib/ipsec + ${INSTALL_DIR} ${IDIR_OPENSWAN}/usr/libexec/ipsec + ${INSTALL_DIR} ${IDIR_OPENSWAN}/etc/ipsec.d + ${INSTALL_DIR} ${IDIR_OPENSWAN}/usr/sbin + ${CP} ${WRKINST}/etc/ipsec.conf ${IDIR_OPENSWAN}/etc/ + ${CP} ${WRKINST}/etc/ipsec.d/* ${IDIR_OPENSWAN}/etc/ipsec.d + ${CP} ${WRKINST}/usr/lib/ipsec/* ${IDIR_OPENSWAN}/usr/lib/ipsec + ${CP} ${WRKINST}/usr/libexec/ipsec/* ${IDIR_OPENSWAN}/usr/libexec/ipsec + ${INSTALL_BIN} ${WRKINST}/usr/sbin/ipsec ${IDIR_OPENSWAN}/usr/sbin + ${INSTALL_BIN} ${WRKINST}/etc/rc.d/init.d/ipsec \ ${IDIR_OPENSWAN}/usr/libexec/ipsec/setup - rm -rf ${IDIR_OPENSWAN}/etc/rc*.d - find ${IDIR_OPENSWAN} -name \*.old -print0 | xargs -0 rm -rf include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/openswan/patches/patch-Makefile_inc b/package/openswan/patches/patch-Makefile_inc index 653528eb9..872f21335 100644 --- a/package/openswan/patches/patch-Makefile_inc +++ b/package/openswan/patches/patch-Makefile_inc @@ -1,5 +1,5 @@ ---- openswan-2.6.21.orig/Makefile.inc 2009-03-30 15:11:28.000000000 +0200 -+++ openswan-2.6.21/Makefile.inc 2009-06-13 14:48:55.000000000 +0200 +--- openswan-2.6.22.orig/Makefile.inc 2009-06-23 04:53:08.000000000 +0200 ++++ openswan-2.6.22/Makefile.inc 2009-07-23 20:09:34.556071786 +0200 @@ -163,7 +163,7 @@ INSTALL=install # how backup names are composed. # Note that the install procedures will never overwrite an existing config @@ -9,3 +9,18 @@ INSTSUIDFLAGS=--mode=u+rxs,g+rx,o+rx --group=root -b --suffix=.old INSTMANFLAGS= INSTCONFFLAGS= +@@ -262,12 +262,12 @@ RH_KERNELSRC?=/lib/modules/2.6.9-1.681_F + # Note you need a locally running bind9 nameserver with lwres{} enabled + # to use this, or have the "lwres" package installed and running. + # This only affects conns that use DNS for keys in lookups. +-USE_LWRES?=false ++USE_LWRES?=true + + # Do a new lookup every time a connection is (re)started. This works better + # on hosts with some dyndns service, since DPD will cause a new dns lookup, + # but it could be a potential security issue if receiving spoofed dns. +-USE_DYNAMICDNS?=true ++USE_DYNAMICDNS?=false + + # Do we want all the configuration files like ipsec.conf and ipsec.secrets + # and any certificates to be in a single directory defined by diff --git a/package/openswan/patches/patch-programs_Makefile_program b/package/openswan/patches/patch-programs_Makefile_program index 74f5c8751..154fd06c2 100644 --- a/package/openswan/patches/patch-programs_Makefile_program +++ b/package/openswan/patches/patch-programs_Makefile_program @@ -1,6 +1,6 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $ ---- openswan-2.6.21.orig/programs/Makefile.program 2009-03-30 15:11:28.000000000 +0200 -+++ openswan-2.6.21/programs/Makefile.program 2009-06-13 14:42:38.000000000 +0200 +--- openswan-2.6.22.orig/programs/Makefile.program 2009-06-23 04:53:08.000000000 +0200 ++++ openswan-2.6.22/programs/Makefile.program 2009-07-23 19:46:18.635264333 +0200 @@ -49,9 +49,9 @@ CFLAGS+=-DFINALCONFFILE=\"${FINALCONFFIL CFLAGS+=-DFINALVARDIR=\"${FINALVARDIR}\" @@ -14,7 +14,7 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $ CFLAGS+= ${WERROR} -@@ -108,67 +108,67 @@ endif +@@ -104,67 +104,67 @@ endif ifneq ($(NOINSTALL),true) doinstall:: $(PROGRAM) $(CONFFILES) $(EXTRA8MAN) $(EXTRA5MAN) $(EXTRA5PROC) $(LIBFILES) $(CONFDFILES) diff --git a/package/openswan/patches/patch-programs_ikeping_ikeping_c b/package/openswan/patches/patch-programs_ikeping_ikeping_c index 5e8bde61b..4be18fcdb 100644 --- a/package/openswan/patches/patch-programs_ikeping_ikeping_c +++ b/package/openswan/patches/patch-programs_ikeping_ikeping_c @@ -1,7 +1,7 @@ $Id: update-patches 24 2008-08-31 14:56:13Z wbx $ ---- openswan-2.6.18.orig/programs/ikeping/ikeping.c 2008-10-06 18:52:49.000000000 +0200 -+++ openswan-2.6.18/programs/ikeping/ikeping.c 2008-10-14 13:09:06.000000000 +0200 -@@ -316,7 +316,7 @@ main(int argc, char **argv) +--- openswan-2.6.22.orig/programs/ikeping/ikeping.c 2009-06-23 04:53:08.000000000 +0200 ++++ openswan-2.6.22/programs/ikeping/ikeping.c 2009-07-23 19:46:18.643265912 +0200 +@@ -319,7 +319,7 @@ main(int argc, char **argv) natt=0; listen_only=0; noDNS=0; diff --git a/target/linux/config/Config.in.ipsec b/target/linux/config/Config.in.ipsec new file mode 100644 index 000000000..998e3a383 --- /dev/null +++ b/target/linux/config/Config.in.ipsec @@ -0,0 +1,52 @@ +menu "IPSec support" + +config ADK_KPACKAGE_KMOD_NET_KEY + prompt "kmod-net-ipsec-netkey............. PF_KEYv2 socket family" + tristate + default n + help + PF_KEYv2 socket family, compatible to KAME ones. + +config ADK_KPACKAGE_KMOD_INET_AH + prompt "kmod-net-ipsec-ah................. IPsec AH support" + tristate + default n + help + Support for IPsec AH. + +config ADK_KPACKAGE_KMOD_INET_ESP + prompt "kmod-net-ipsec-esp................ IPsec ESP support" + tristate + default n + help + Support for IPsec ESP. + +config ADK_KPACKAGE_KMOD_INET_IPCOMP + prompt "kmod-net-ipsec-comp................ IP Payload Compression" + tristate + default n + help + Support for IP Payload Compression Protocol (IPComp) (RFC3173), + typically needed for IPsec. + +config ADK_KPACKAGE_KMOD_INET_XFRM_MODE_TRANSPORT + prompt "kmod-net-ipsec-transport........... IPsec transport mode" + tristate + default n + help + Support for IPsec transport mode. + +config ADK_KPACKAGE_KMOD_INET_XFRM_MODE_TUNNEL + prompt "kmod-net-ipsec-tunnel.............. IPsec tunnel mode" + tristate + default n + help + Support for IPsec tunnel mode. + +config ADK_KPACKAGE_KMOD_INET_XFRM_MODE_BEET + prompt "kmod-net-ipsec-beet................ IPsec BEET mode" + tristate + default n + help + Support for IPsec BEET mode. +endmenu diff --git a/target/linux/config/Config.in.network b/target/linux/config/Config.in.network index 195006c51..255e17738 100644 --- a/target/linux/config/Config.in.network +++ b/target/linux/config/Config.in.network @@ -234,6 +234,7 @@ config ADK_KPACKAGE_KMOD_BONDING information. source target/linux/config/Config.in.sched +source target/linux/config/Config.in.ipsec endmenu -- cgit v1.2.3 From 5e4078831832697218a7bbe94571a985cce7bbc6 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Aug 2009 14:25:12 +0200 Subject: depends on fix --- package/openswan/Config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/openswan/Config.in b/package/openswan/Config.in index 172d02679..543a80f58 100644 --- a/package/openswan/Config.in +++ b/package/openswan/Config.in @@ -11,7 +11,7 @@ config ADK_PACKAGE_OPENSWAN choice prompt "IPSec stack to use" -depends ADK_PACKAGE_OPENSWAN +depends on ADK_PACKAGE_OPENSWAN config ADK_COMPILE_OPENSWAN_WITH_NETKEY prompt "NETKEY - use Linux integrated IPSec Stack" select ADK_KPACKAGE_KMOD_NET_KEY -- cgit v1.2.3 From 48b4e0eac16a23713698ea4cd088cd8c857e4c33 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 12 Aug 2009 21:52:58 +0200 Subject: update gcc, kernel and uclibc Makefile - bring rb532 in shape, make it bootable --- TODO | 3 +- mk/modules.mk | 32 + package/base-files/extra/init | 1 + target/linux/config/Config.in.ipsec | 1 + target/linux/patches/2.6.30.1/natt.patch | 2668 +++ target/linux/patches/2.6.30.4/cygwin-compat.patch | 66 + target/linux/patches/2.6.30.4/freebsd-compat.patch | 11 + target/linux/patches/2.6.30.4/mips-delay-fix.patch | 27 + target/linux/patches/2.6.30.4/mtd-root.patch | 62 + target/linux/patches/2.6.30.4/natt.patch | 2668 +++ target/linux/patches/2.6.30.4/ocf.patch | 23653 +++++++++++++++++++ target/linux/patches/2.6.30.4/swconfig.patch | 1075 + target/linux/patches/2.6.30.4/yaffs2.patch | 15066 ++++++++++++ target/rb532/device.mk | 6 +- toolchain/gcc/Makefile.inc | 2 +- toolchain/uClibc/Makefile | 5 + 16 files changed, 45340 insertions(+), 6 deletions(-) create mode 100644 target/linux/patches/2.6.30.1/natt.patch create mode 100644 target/linux/patches/2.6.30.4/cygwin-compat.patch create mode 100644 target/linux/patches/2.6.30.4/freebsd-compat.patch create mode 100644 target/linux/patches/2.6.30.4/mips-delay-fix.patch create mode 100644 target/linux/patches/2.6.30.4/mtd-root.patch create mode 100644 target/linux/patches/2.6.30.4/natt.patch create mode 100644 target/linux/patches/2.6.30.4/ocf.patch create mode 100644 target/linux/patches/2.6.30.4/swconfig.patch create mode 100644 target/linux/patches/2.6.30.4/yaffs2.patch diff --git a/TODO b/TODO index 86140051d..b9ed1a63f 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,6 @@ - eglibc support - check mips -mno-abicalls - check ac_cv_func_setpgrp_void=no -- kernel 2.6.30 - freebsd build - win cygwin build - netbsd build @@ -16,5 +15,5 @@ - checksum for toolchain packages - network scripts for wireless client / ap - network scripts for pppoe -- publish via trac+git - customise mconf help texts to better fit for OpenADK +- publish via trac+git diff --git a/mk/modules.mk b/mk/modules.mk index 1c02e711f..225daca21 100644 --- a/mk/modules.mk +++ b/mk/modules.mk @@ -205,6 +205,38 @@ $(eval $(call KMOD_template,NET_ACT_PEDIT,net-act-pedit,\ $(MODULES_DIR)/kernel/net/sched/act_pedit \ ,45)) +# +# IPsec +# +$(eval $(call KMOD_template,NET_KEY,net-ipsec-netkey,\ + $(MODULES_DIR)/kernel/net/key/af_key \ +,60)) + +$(eval $(call KMOD_template,INET_AH,net-ipsec-ah,\ + $(MODULES_DIR)/kernel/net/ipv4/ah4 \ +,65)) + +$(eval $(call KMOD_template,INET_ESP,net-ipsec-esp,\ + $(MODULES_DIR)/kernel/net/ipv4/esp4 \ +,65)) + +$(eval $(call KMOD_template,INET_IPCOMP,net-ipsec-comp,\ + $(MODULES_DIR)/kernel/net/ipv4/ipcomp \ + $(MODULES_DIR)/kernel/net/xfrm/xfrm_ipcomp \ +,70)) + +$(eval $(call KMOD_template,INET_XFRM_MODE_TRANSPORT,net-ipsec-transport,\ + $(MODULES_DIR)/kernel/net/ipv4/xfrm4_mode_transport \ +,75)) + +$(eval $(call KMOD_template,INET_XFRM_MODE_TUNNEL,net-ipsec-tunnel,\ + $(MODULES_DIR)/kernel/net/ipv4/xfrm4_mode_tunnel \ +,75)) + +$(eval $(call KMOD_template,INET_XFRM_MODE_BEET,net-ipsec-beet,\ + $(MODULES_DIR)/kernel/net/ipv4/xfrm4_mode_beet \ +,75)) + ## ## Filtering / Firewalling ## diff --git a/package/base-files/extra/init b/package/base-files/extra/init index 65f33e3d6..f8021f286 100755 --- a/package/base-files/extra/init +++ b/package/base-files/extra/init @@ -1,4 +1,5 @@ #!/bin/sh +echo "Starting system" export PATH=/bin:/sbin:/usr/bin:/usr/sbin mount -nt proc proc /proc size=$(awk '/MemTotal:/ { if ($2 > 16000) { print 4096 } else { print 2048 }}' /proc/meminfo) diff --git a/target/linux/config/Config.in.ipsec b/target/linux/config/Config.in.ipsec index 998e3a383..60497bc32 100644 --- a/target/linux/config/Config.in.ipsec +++ b/target/linux/config/Config.in.ipsec @@ -17,6 +17,7 @@ config ADK_KPACKAGE_KMOD_INET_AH config ADK_KPACKAGE_KMOD_INET_ESP prompt "kmod-net-ipsec-esp................ IPsec ESP support" tristate + select ADK_KPACKAGE_KMOD_CRYPTO_AEAD default n help Support for IPsec ESP. diff --git a/target/linux/patches/2.6.30.1/natt.patch b/target/linux/patches/2.6.30.1/natt.patch new file mode 100644 index 000000000..83103a369 --- /dev/null +++ b/target/linux/patches/2.6.30.1/natt.patch @@ -0,0 +1,2668 @@ +diff -Nur linux-2.6.30.1.orig/include/net/xfrmudp.h linux-2.6.30.1/include/net/xfrmudp.h +--- linux-2.6.30.1.orig/include/net/xfrmudp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/include/net/xfrmudp.h 2009-07-24 22:00:56.771280384 +0200 +@@ -0,0 +1,10 @@ ++/* ++ * pointer to function for type that xfrm4_input wants, to permit ++ * decoupling of XFRM from udp.c ++ */ ++#define HAVE_XFRM4_UDP_REGISTER ++ ++typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type); ++extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func ++ , xfrm4_rcv_encap_t *oldfunc); ++extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func); +diff -Nur linux-2.6.30.1.orig/net/ipv4/Kconfig linux-2.6.30.1/net/ipv4/Kconfig +--- linux-2.6.30.1.orig/net/ipv4/Kconfig 2009-07-03 01:52:38.000000000 +0200 ++++ linux-2.6.30.1/net/ipv4/Kconfig 2009-07-24 22:00:56.751278392 +0200 +@@ -379,6 +379,12 @@ + tristate + default n + ++config IPSEC_NAT_TRAVERSAL ++ bool "IPSEC NAT-Traversal (KLIPS compatible)" ++ depends on INET ++ ---help--- ++ Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP. ++ + config INET_XFRM_MODE_TRANSPORT + tristate "IP: IPsec transport mode" + default y +diff -Nur linux-2.6.30.1.orig/net/ipv4/Kconfig.orig linux-2.6.30.1/net/ipv4/Kconfig.orig +--- linux-2.6.30.1.orig/net/ipv4/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/net/ipv4/Kconfig.orig 2009-07-03 01:52:38.000000000 +0200 +@@ -0,0 +1,638 @@ ++# ++# IP configuration ++# ++config IP_MULTICAST ++ bool "IP: multicasting" ++ help ++ This is code for addressing several networked computers at once, ++ enlarging your kernel by about 2 KB. You need multicasting if you ++ intend to participate in the MBONE, a high bandwidth network on top ++ of the Internet which carries audio and video broadcasts. More ++ information about the MBONE is on the WWW at ++ . Information about the multicast ++ capabilities of the various network cards is contained in ++ . For most people, it's ++ safe to say N. ++ ++config IP_ADVANCED_ROUTER ++ bool "IP: advanced router" ++ ---help--- ++ If you intend to run your Linux box mostly as a router, i.e. as a ++ computer that forwards and redistributes network packets, say Y; you ++ will then be presented with several options that allow more precise ++ control about the routing process. ++ ++ The answer to this question won't directly affect the kernel: ++ answering N will just cause the configurator to skip all the ++ questions about advanced routing. ++ ++ Note that your box can only act as a router if you enable IP ++ forwarding in your kernel; you can do that by saying Y to "/proc ++ file system support" and "Sysctl support" below and executing the ++ line ++ ++ echo "1" > /proc/sys/net/ipv4/ip_forward ++ ++ at boot time after the /proc file system has been mounted. ++ ++ If you turn on IP forwarding, you should consider the rp_filter, which ++ automatically rejects incoming packets if the routing table entry ++ for their source address doesn't match the network interface they're ++ arriving on. This has security advantages because it prevents the ++ so-called IP spoofing, however it can pose problems if you use ++ asymmetric routing (packets from you to a host take a different path ++ than packets from that host to you) or if you operate a non-routing ++ host which has several IP addresses on different interfaces. To turn ++ rp_filter on use: ++ ++ echo 1 > /proc/sys/net/ipv4/conf//rp_filter ++ and ++ echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter ++ ++ Note that some distributions enable it in startup scripts. ++ For details about rp_filter strict and loose mode read ++ . ++ ++ If unsure, say N here. ++ ++choice ++ prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)" ++ depends on IP_ADVANCED_ROUTER ++ default ASK_IP_FIB_HASH ++ ++config ASK_IP_FIB_HASH ++ bool "FIB_HASH" ++ ---help--- ++ Current FIB is very proven and good enough for most users. ++ ++config IP_FIB_TRIE ++ bool "FIB_TRIE" ++ ---help--- ++ Use new experimental LC-trie as FIB lookup algorithm. ++ This improves lookup performance if you have a large ++ number of routes. ++ ++ LC-trie is a longest matching prefix lookup algorithm which ++ performs better than FIB_HASH for large routing tables. ++ But, it consumes more memory and is more complex. ++ ++ LC-trie is described in: ++ ++ IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson ++ IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, ++ June 1999 ++ ++ An experimental study of compression methods for dynamic tries ++ Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. ++ http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ ++ ++endchoice ++ ++config IP_FIB_HASH ++ def_bool ASK_IP_FIB_HASH || !IP_ADVANCED_ROUTER ++ ++config IP_FIB_TRIE_STATS ++ bool "FIB TRIE statistics" ++ depends on IP_FIB_TRIE ++ ---help--- ++ Keep track of statistics on structure of FIB TRIE table. ++ Useful for testing and measuring TRIE performance. ++ ++config IP_MULTIPLE_TABLES ++ bool "IP: policy routing" ++ depends on IP_ADVANCED_ROUTER ++ select FIB_RULES ++ ---help--- ++ Normally, a router decides what to do with a received packet based ++ solely on the packet's final destination address. If you say Y here, ++ the Linux router will also be able to take the packet's source ++ address into account. Furthermore, the TOS (Type-Of-Service) field ++ of the packet can be used for routing decisions as well. ++ ++ If you are interested in this, please see the preliminary ++ documentation at ++ and . ++ You will need supporting software from ++ . ++ ++ If unsure, say N. ++ ++config IP_ROUTE_MULTIPATH ++ bool "IP: equal cost multipath" ++ depends on IP_ADVANCED_ROUTER ++ help ++ Normally, the routing tables specify a single action to be taken in ++ a deterministic manner for a given packet. If you say Y here ++ however, it becomes possible to attach several actions to a packet ++ pattern, in effect specifying several alternative paths to travel ++ for those packets. The router considers all these paths to be of ++ equal "cost" and chooses one of them in a non-deterministic fashion ++ if a matching packet arrives. ++ ++config IP_ROUTE_VERBOSE ++ bool "IP: verbose route monitoring" ++ depends on IP_ADVANCED_ROUTER ++ help ++ If you say Y here, which is recommended, then the kernel will print ++ verbose messages regarding the routing, for example warnings about ++ received packets which look strange and could be evidence of an ++ attack or a misconfigured system somewhere. The information is ++ handled by the klogd daemon which is responsible for kernel messages ++ ("man klogd"). ++ ++config IP_PNP ++ bool "IP: kernel level autoconfiguration" ++ help ++ This enables automatic configuration of IP addresses of devices and ++ of the routing table during kernel boot, based on either information ++ supplied on the kernel command line or by BOOTP or RARP protocols. ++ You need to say Y only for diskless machines requiring network ++ access to boot (in which case you want to say Y to "Root file system ++ on NFS" as well), because all other machines configure the network ++ in their startup scripts. ++ ++config IP_PNP_DHCP ++ bool "IP: DHCP support" ++ depends on IP_PNP ++ ---help--- ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the DHCP protocol (a ++ special protocol designed for doing this job), say Y here. In case ++ the boot ROM of your network card was designed for booting Linux and ++ does DHCP itself, providing all necessary information on the kernel ++ command line, you can say N here. ++ ++ If unsure, say Y. Note that if you want to use DHCP, a DHCP server ++ must be operating on your network. Read ++ for details. ++ ++config IP_PNP_BOOTP ++ bool "IP: BOOTP support" ++ depends on IP_PNP ++ ---help--- ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the BOOTP protocol (a ++ special protocol designed for doing this job), say Y here. In case ++ the boot ROM of your network card was designed for booting Linux and ++ does BOOTP itself, providing all necessary information on the kernel ++ command line, you can say N here. If unsure, say Y. Note that if you ++ want to use BOOTP, a BOOTP server must be operating on your network. ++ Read for details. ++ ++config IP_PNP_RARP ++ bool "IP: RARP support" ++ depends on IP_PNP ++ help ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the RARP protocol (an ++ older protocol which is being obsoleted by BOOTP and DHCP), say Y ++ here. Note that if you want to use RARP, a RARP server must be ++ operating on your network. Read ++ for details. ++ ++# not yet ready.. ++# bool ' IP: ARP support' CONFIG_IP_PNP_ARP ++config NET_IPIP ++ tristate "IP: tunneling" ++ select INET_TUNNEL ++ ---help--- ++ Tunneling means encapsulating data of one protocol type within ++ another protocol and sending it over a channel that understands the ++ encapsulating protocol. This particular tunneling driver implements ++ encapsulation of IP within IP, which sounds kind of pointless, but ++ can be useful if you want to make your (or some other) machine ++ appear on a different network than it physically is, or to use ++ mobile-IP facilities (allowing laptops to seamlessly move between ++ networks without changing their IP addresses). ++ ++ Saying Y to this option will produce two modules ( = code which can ++ be inserted in and removed from the running kernel whenever you ++ want). Most people won't need this and can say N. ++ ++config NET_IPGRE ++ tristate "IP: GRE tunnels over IP" ++ help ++ Tunneling means encapsulating data of one protocol type within ++ another protocol and sending it over a channel that understands the ++ encapsulating protocol. This particular tunneling driver implements ++ GRE (Generic Routing Encapsulation) and at this time allows ++ encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure. ++ This driver is useful if the other endpoint is a Cisco router: Cisco ++ likes GRE much better than the other Linux tunneling driver ("IP ++ tunneling" above). In addition, GRE allows multicast redistribution ++ through the tunnel. ++ ++config NET_IPGRE_BROADCAST ++ bool "IP: broadcast GRE over IP" ++ depends on IP_MULTICAST && NET_IPGRE ++ help ++ One application of GRE/IP is to construct a broadcast WAN (Wide Area ++ Network), which looks like a normal Ethernet LAN (Local Area ++ Network), but can be distributed all over the Internet. If you want ++ to do that, say Y here and to "IP multicast routing" below. ++ ++config IP_MROUTE ++ bool "IP: multicast routing" ++ depends on IP_MULTICAST ++ help ++ This is used if you want your machine to act as a router for IP ++ packets that have several destination addresses. It is needed on the ++ MBONE, a high bandwidth network on top of the Internet which carries ++ audio and video broadcasts. In order to do that, you would most ++ likely run the program mrouted. Information about the multicast ++ capabilities of the various network cards is contained in ++ . If you haven't heard ++ about it, you don't need it. ++ ++config IP_PIMSM_V1 ++ bool "IP: PIM-SM version 1 support" ++ depends on IP_MROUTE ++ help ++ Kernel side support for Sparse Mode PIM (Protocol Independent ++ Multicast) version 1. This multicast routing protocol is used widely ++ because Cisco supports it. You need special software to use it ++ (pimd-v1). Please see for more ++ information about PIM. ++ ++ Say Y if you want to use PIM-SM v1. Note that you can say N here if ++ you just want to use Dense Mode PIM. ++ ++config IP_PIMSM_V2 ++ bool "IP: PIM-SM version 2 support" ++ depends on IP_MROUTE ++ help ++ Kernel side support for Sparse Mode PIM version 2. In order to use ++ this, you need an experimental routing daemon supporting it (pimd or ++ gated-5). This routing protocol is not used widely, so say N unless ++ you want to play with it. ++ ++config ARPD ++ bool "IP: ARP daemon support (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ ---help--- ++ Normally, the kernel maintains an internal cache which maps IP ++ addresses to hardware addresses on the local network, so that ++ Ethernet/Token Ring/ etc. frames are sent to the proper address on ++ the physical networking layer. For small networks having a few ++ hundred directly connected hosts or less, keeping this address ++ resolution (ARP) cache inside the kernel works well. However, ++ maintaining an internal ARP cache does not work well for very large ++ switched networks, and will use a lot of kernel memory if TCP/IP ++ connections are made to many machines on the network. ++ ++ If you say Y here, the kernel's internal ARP cache will never grow ++ to more than 256 entries (the oldest entries are expired in a LIFO ++ manner) and communication will be attempted with the user space ARP ++ daemon arpd. Arpd then answers the address resolution request either ++ from its own cache or by asking the net. ++ ++ This code is experimental and also obsolete. If you want to use it, ++ you need to find a version of the daemon arpd on the net somewhere, ++ and you should also say Y to "Kernel/User network link driver", ++ below. If unsure, say N. ++ ++config SYN_COOKIES ++ bool "IP: TCP syncookie support (disabled per default)" ++ ---help--- ++ Normal TCP/IP networking is open to an attack known as "SYN ++ flooding". This denial-of-service attack prevents legitimate remote ++ users from being able to connect to your computer during an ongoing ++ attack and requires very little work from the attacker, who can ++ operate from anywhere on the Internet. ++ ++ SYN cookies provide protection against this type of attack. If you ++ say Y here, the TCP/IP stack will use a cryptographic challenge ++ protocol known as "SYN cookies" to enable legitimate users to ++ continue to connect, even when your machine is under attack. There ++ is no need for the legitimate users to change their TCP/IP software; ++ SYN cookies work transparently to them. For technical information ++ about SYN cookies, check out . ++ ++ If you are SYN flooded, the source address reported by the kernel is ++ likely to have been forged by the attacker; it is only reported as ++ an aid in tracing the packets to their actual source and should not ++ be taken as absolute truth. ++ ++ SYN cookies may prevent correct error reporting on clients when the ++ server is really overloaded. If this happens frequently better turn ++ them off. ++ ++ If you say Y here, note that SYN cookies aren't enabled by default; ++ you can enable them by saying Y to "/proc file system support" and ++ "Sysctl support" below and executing the command ++ ++ echo 1 >/proc/sys/net/ipv4/tcp_syncookies ++ ++ at boot time after the /proc file system has been mounted. ++ ++ If unsure, say N. ++ ++config INET_AH ++ tristate "IP: AH transformation" ++ select XFRM ++ select CRYPTO ++ select CRYPTO_HMAC ++ select CRYPTO_MD5 ++ select CRYPTO_SHA1 ++ ---help--- ++ Support for IPsec AH. ++ ++ If unsure, say Y. ++ ++config INET_ESP ++ tristate "IP: ESP transformation" ++ select XFRM ++ select CRYPTO ++ select CRYPTO_AUTHENC ++ select CRYPTO_HMAC ++ select CRYPTO_MD5 ++ select CRYPTO_CBC ++ select CRYPTO_SHA1 ++ select CRYPTO_DES ++ ---help--- ++ Support for IPsec ESP. ++ ++ If unsure, say Y. ++ ++config INET_IPCOMP ++ tristate "IP: IPComp transformation" ++ select INET_XFRM_TUNNEL ++ select XFRM_IPCOMP ++ ---help--- ++ Support for IP Payload Compression Protocol (IPComp) (RFC3173), ++ typically needed for IPsec. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_TUNNEL ++ tristate ++ select INET_TUNNEL ++ default n ++ ++config INET_TUNNEL ++ tristate ++ default n ++ ++config INET_XFRM_MODE_TRANSPORT ++ tristate "IP: IPsec transport mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec transport mode. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_MODE_TUNNEL ++ tristate "IP: IPsec tunnel mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec tunnel mode. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_MODE_BEET ++ tristate "IP: IPsec BEET mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec BEET mode. ++ ++ If unsure, say Y. ++ ++config INET_LRO ++ bool "Large Receive Offload (ipv4/tcp)" ++ default y ++ ---help--- ++ Support for Large Receive Offload (ipv4/tcp). ++ ++ If unsure, say Y. ++ ++config INET_DIAG ++ tristate "INET: socket monitoring interface" ++ default y ++ ---help--- ++ Support for INET (TCP, DCCP, etc) socket monitoring interface used by ++ native Linux tools such as ss. ss is included in iproute2, currently ++ downloadable at . ++ ++ If unsure, say Y. ++ ++config INET_TCP_DIAG ++ depends on INET_DIAG ++ def_tristate INET_DIAG ++ ++menuconfig TCP_CONG_ADVANCED ++ bool "TCP: advanced congestion control" ++ ---help--- ++ Support for selection of various TCP congestion control ++ modules. ++ ++ Nearly all users can safely say no here, and a safe default ++ selection will be made (CUBIC with new Reno as a fallback). ++ ++ If unsure, say N. ++ ++if TCP_CONG_ADVANCED ++ ++config TCP_CONG_BIC ++ tristate "Binary Increase Congestion (BIC) control" ++ default m ++ ---help--- ++ BIC-TCP is a sender-side only change that ensures a linear RTT ++ fairness under large windows while offering both scalability and ++ bounded TCP-friendliness. The protocol combines two schemes ++ called additive increase and binary search increase. When the ++ congestion window is large, additive increase with a large ++ increment ensures linear RTT fairness as well as good ++ scalability. Under small congestion windows, binary search ++ increase provides TCP friendliness. ++ See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ ++ ++config TCP_CONG_CUBIC ++ tristate "CUBIC TCP" ++ default y ++ ---help--- ++ This is version 2.0 of BIC-TCP which uses a cubic growth function ++ among other techniques. ++ See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf ++ ++config TCP_CONG_WESTWOOD ++ tristate "TCP Westwood+" ++ default m ++ ---help--- ++ TCP Westwood+ is a sender-side only modification of the TCP Reno ++ protocol stack that optimizes the performance of TCP congestion ++ control. It is based on end-to-end bandwidth estimation to set ++ congestion window and slow start threshold after a congestion ++ episode. Using this estimation, TCP Westwood+ adaptively sets a ++ slow start threshold and a congestion window which takes into ++ account the bandwidth used at the time congestion is experienced. ++ TCP Westwood+ significantly increases fairness wrt TCP Reno in ++ wired networks and throughput over wireless links. ++ ++config TCP_CONG_HTCP ++ tristate "H-TCP" ++ default m ++ ---help--- ++ H-TCP is a send-side only modifications of the TCP Reno ++ protocol stack that optimizes the performance of TCP ++ congestion control for high speed network links. It uses a ++ modeswitch to change the alpha and beta parameters of TCP Reno ++ based on network conditions and in a way so as to be fair with ++ other Reno and H-TCP flows. ++ ++config TCP_CONG_HSTCP ++ tristate "High Speed TCP" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ Sally Floyd's High Speed TCP (RFC 3649) congestion control. ++ A modification to TCP's congestion control mechanism for use ++ with large congestion windows. A table indicates how much to ++ increase the congestion window by when an ACK is received. ++ For more detail see http://www.icir.org/floyd/hstcp.html ++ ++config TCP_CONG_HYBLA ++ tristate "TCP-Hybla congestion control algorithm" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP-Hybla is a sender-side only change that eliminates penalization of ++ long-RTT, large-bandwidth connections, like when satellite legs are ++ involved, especially when sharing a common bottleneck with normal ++ terrestrial connections. ++ ++config TCP_CONG_VEGAS ++ tristate "TCP Vegas" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Vegas is a sender-side only change to TCP that anticipates ++ the onset of congestion by estimating the bandwidth. TCP Vegas ++ adjusts the sending rate by modifying the congestion ++ window. TCP Vegas should provide less packet loss, but it is ++ not as aggressive as TCP Reno. ++ ++config TCP_CONG_SCALABLE ++ tristate "Scalable TCP" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ Scalable TCP is a sender-side only change to TCP which uses a ++ MIMD congestion control algorithm which has some nice scaling ++ properties, though is known to have fairness issues. ++ See http://www.deneholme.net/tom/scalable/ ++ ++config TCP_CONG_LP ++ tristate "TCP Low Priority" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Low Priority (TCP-LP), a distributed algorithm whose goal is ++ to utilize only the excess network bandwidth as compared to the ++ ``fair share`` of bandwidth as targeted by TCP. ++ See http://www-ece.rice.edu/networks/TCP-LP/ ++ ++config TCP_CONG_VENO ++ tristate "TCP Veno" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Veno is a sender-side only enhancement of TCP to obtain better ++ throughput over wireless networks. TCP Veno makes use of state ++ distinguishing to circumvent the difficult judgment of the packet loss ++ type. TCP Veno cuts down less congestion window in response to random ++ loss packets. ++ See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf ++ ++config TCP_CONG_YEAH ++ tristate "YeAH TCP" ++ depends on EXPERIMENTAL ++ select TCP_CONG_VEGAS ++ default n ++ ---help--- ++ YeAH-TCP is a sender-side high-speed enabled TCP congestion control ++ algorithm, which uses a mixed loss/delay approach to compute the ++ congestion window. It's design goals target high efficiency, ++ internal, RTT and Reno fairness, resilience to link loss while ++ keeping network elements load as low as possible. ++ ++ For further details look here: ++ http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf ++ ++config TCP_CONG_ILLINOIS ++ tristate "TCP Illinois" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP-Illinois is a sender-side modification of TCP Reno for ++ high speed long delay links. It uses round-trip-time to ++ adjust the alpha and beta parameters to achieve a higher average ++ throughput and maintain fairness. ++ ++ For further details see: ++ http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html ++ ++choice ++ prompt "Default TCP congestion control" ++ default DEFAULT_CUBIC ++ help ++ Select the TCP congestion control that will be used by default ++ for all connections. ++ ++ config DEFAULT_BIC ++ bool "Bic" if TCP_CONG_BIC=y ++ ++ config DEFAULT_CUBIC ++ bool "Cubic" if TCP_CONG_CUBIC=y ++ ++ config DEFAULT_HTCP ++ bool "Htcp" if TCP_CONG_HTCP=y ++ ++ config DEFAULT_VEGAS ++ bool "Vegas" if TCP_CONG_VEGAS=y ++ ++ config DEFAULT_WESTWOOD ++ bool "Westwood" if TCP_CONG_WESTWOOD=y ++ ++ config DEFAULT_RENO ++ bool "Reno" ++ ++endchoice ++ ++endif ++ ++config TCP_CONG_CUBIC ++ tristate ++ depends on !TCP_CONG_ADVANCED ++ default y ++ ++config DEFAULT_TCP_CONG ++ string ++ default "bic" if DEFAULT_BIC ++ default "cubic" if DEFAULT_CUBIC ++ default "htcp" if DEFAULT_HTCP ++ default "vegas" if DEFAULT_VEGAS ++ default "westwood" if DEFAULT_WESTWOOD ++ default "reno" if DEFAULT_RENO ++ default "cubic" ++ ++config TCP_MD5SIG ++ bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ select CRYPTO ++ select CRYPTO_MD5 ++ ---help--- ++ RFC2385 specifies a method of giving MD5 protection to TCP sessions. ++ Its main (only?) use is to protect BGP sessions between core routers ++ on the Internet. ++ ++ If unsure, say N. ++ +diff -Nur linux-2.6.30.1.orig/net/ipv4/udp.c linux-2.6.30.1/net/ipv4/udp.c +--- linux-2.6.30.1.orig/net/ipv4/udp.c 2009-07-03 01:52:38.000000000 +0200 ++++ linux-2.6.30.1/net/ipv4/udp.c 2009-07-24 22:00:56.755270521 +0200 +@@ -104,6 +104,7 @@ + #include + #include + #include ++#include + #include "udp_impl.h" + + struct udp_table udp_table; +@@ -1035,6 +1036,128 @@ + return -1; + } + ++#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++ ++static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL; ++ ++/* ++ * de-encapsulate and pass to the registered xfrm4_rcv_encap_func function. ++ * Most of this code stolen from net/ipv4/xfrm4_input.c ++ * which is attributed to YOSHIFUJI Hideaki @USAGI, and ++ * Derek Atkins ++ */ ++ ++static int xfrm4_udp_encap_rcv_wrapper(struct sock *sk, struct sk_buff *skb) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ struct udphdr *uh; ++ struct iphdr *iph; ++ int iphlen, len; ++ int ret; ++ ++ __u8 *udpdata; ++ __be32 *udpdata32; ++ __u16 encap_type = up->encap_type; ++ ++ /* if this is not encapsulated socket, then just return now */ ++ if (!encap_type && !xfrm4_rcv_encap_func) ++ return 1; ++ ++ /* If this is a paged skb, make sure we pull up ++ * whatever data we need to look at. */ ++ len = skb->len - sizeof(struct udphdr); ++ if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) ++ return 1; ++ ++ /* Now we can get the pointers */ ++ uh = udp_hdr(skb); ++ udpdata = (__u8 *)uh + sizeof(struct udphdr); ++ udpdata32 = (__be32 *)udpdata; ++ ++ switch (encap_type) { ++ default: ++ case UDP_ENCAP_ESPINUDP: ++ /* Check if this is a keepalive packet. If so, eat it. */ ++ if (len == 1 && udpdata[0] == 0xff) { ++ goto drop; ++ } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) { ++ /* ESP Packet without Non-ESP header */ ++ len = sizeof(struct udphdr); ++ } else ++ /* Must be an IKE packet.. pass it through */ ++ return 1; ++ break; ++ case UDP_ENCAP_ESPINUDP_NON_IKE: ++ /* Check if this is a keepalive packet. If so, eat it. */ ++ if (len == 1 && udpdata[0] == 0xff) { ++ goto drop; ++ } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && ++ udpdata32[0] == 0 && udpdata32[1] == 0) { ++ ++ /* ESP Packet with Non-IKE marker */ ++ len = sizeof(struct udphdr) + 2 * sizeof(u32); ++ } else ++ /* Must be an IKE packet.. pass it through */ ++ return 1; ++ break; ++ } ++ ++ /* At this point we are sure that this is an ESPinUDP packet, ++ * so we need to remove 'len' bytes from the packet (the UDP ++ * header and optional ESP marker bytes) and then modify the ++ * protocol to ESP, and then call into the transform receiver. ++ */ ++ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) ++ goto drop; ++ ++ /* Now we can update and verify the packet length... */ ++ iph = ip_hdr(skb); ++ iphlen = iph->ihl << 2; ++ iph->tot_len = htons(ntohs(iph->tot_len) - len); ++ if (skb->len < iphlen + len) { ++ /* packet is too small!?! */ ++ goto drop; ++ } ++ ++ /* pull the data buffer up to the ESP header and set the ++ * transport header to point to ESP. Keep UDP on the stack ++ * for later. ++ */ ++ __skb_pull(skb, len); ++ skb_reset_transport_header(skb); ++ ++ /* modify the protocol (it's ESP!) */ ++ iph->protocol = IPPROTO_ESP; ++ ++ /* process ESP */ ++ ret = (*xfrm4_rcv_encap_func)(skb, encap_type); ++ return ret; ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func, ++ xfrm4_rcv_encap_t *oldfunc) ++{ ++ if (oldfunc != NULL) ++ *oldfunc = xfrm4_rcv_encap_func; ++ xfrm4_rcv_encap_func = func; ++ return 0; ++} ++ ++int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func) ++{ ++ if (xfrm4_rcv_encap_func != func) ++ return -1; ++ ++ xfrm4_rcv_encap_func = NULL; ++ return 0; ++} ++ ++#endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */ ++ + /* returns: + * -1: error + * 0: success +@@ -1377,6 +1500,11 @@ + case 0: + case UDP_ENCAP_ESPINUDP: + case UDP_ENCAP_ESPINUDP_NON_IKE: ++#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++ if (xfrm4_rcv_encap_func) ++ up->encap_rcv = xfrm4_udp_encap_rcv_wrapper; ++ else ++#endif + up->encap_rcv = xfrm4_udp_encap_rcv; + /* FALLTHROUGH */ + case UDP_ENCAP_L2TPINUDP: +@@ -1828,3 +1956,9 @@ + EXPORT_SYMBOL(udp_proc_register); + EXPORT_SYMBOL(udp_proc_unregister); + #endif ++ ++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++EXPORT_SYMBOL(udp4_register_esp_rcvencap); ++EXPORT_SYMBOL(udp4_unregister_esp_rcvencap); ++#endif ++ +diff -Nur linux-2.6.30.1.orig/net/ipv4/udp.c.orig linux-2.6.30.1/net/ipv4/udp.c.orig +--- linux-2.6.30.1.orig/net/ipv4/udp.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/net/ipv4/udp.c.orig 2009-07-03 01:52:38.000000000 +0200 +@@ -0,0 +1,1830 @@ ++/* ++ * INET An implementation of the TCP/IP protocol suite for the LINUX ++ * operating system. INET is implemented using the BSD Socket ++ * interface as the means of communication with the user level. ++ * ++ * The User Datagram Protocol (UDP). ++ * ++ * Authors: Ross Biro ++ * Fred N. van Kempen, ++ * Arnt Gulbrandsen, ++ * Alan Cox, ++ * Hirokazu Takahashi, ++ * ++ * Fixes: ++ * Alan Cox : verify_area() calls ++ * Alan Cox : stopped close while in use off icmp ++ * messages. Not a fix but a botch that ++ * for udp at least is 'valid'. ++ * Alan Cox : Fixed icmp handling properly ++ * Alan Cox : Correct error for oversized datagrams ++ * Alan Cox : Tidied select() semantics. ++ * Alan Cox : udp_err() fixed properly, also now ++ * select and read wake correctly on errors ++ * Alan Cox : udp_send verify_area moved to avoid mem leak ++ * Alan Cox : UDP can count its memory ++ * Alan Cox : send to an unknown connection causes ++ * an ECONNREFUSED off the icmp, but ++ * does NOT close. ++ * Alan Cox : Switched to new sk_buff handlers. No more backlog! ++ * Alan Cox : Using generic datagram code. Even smaller and the PEEK ++ * bug no longer crashes it. ++ * Fred Van Kempen : Net2e support for sk->broadcast. ++ * Alan Cox : Uses skb_free_datagram ++ * Alan Cox : Added get/set sockopt support. ++ * Alan Cox : Broadcasting without option set returns EACCES. ++ * Alan Cox : No wakeup calls. Instead we now use the callbacks. ++ * Alan Cox : Use ip_tos and ip_ttl ++ * Alan Cox : SNMP Mibs ++ * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. ++ * Matt Dillon : UDP length checks. ++ * Alan Cox : Smarter af_inet used properly. ++ * Alan Cox : Use new kernel side addressing. ++ * Alan Cox : Incorrect return on truncated datagram receive. ++ * Arnt Gulbrandsen : New udp_send and stuff ++ * Alan Cox : Cache last socket ++ * Alan Cox : Route cache ++ * Jon Peatfield : Minor efficiency fix to sendto(). ++ * Mike Shaver : RFC1122 checks. ++ * Alan Cox : Nonblocking error fix. ++ * Willy Konynenberg : Transparent proxying support. ++ * Mike McLagan : Routing by source ++ * David S. Miller : New socket lookup architecture. ++ * Last socket cache retained as it ++ * does have a high hit rate. ++ * Olaf Kirch : Don't linearise iovec on sendmsg. ++ * Andi Kleen : Some cleanups, cache destination entry ++ * for connect. ++ * Vitaly E. Lavrov : Transparent proxy revived after year coma. ++ * Melvin Smith : Check msg_name not msg_namelen in sendto(), ++ * return ENOTCONN for unconnected sockets (POSIX) ++ * Janos Farkas : don't deliver multi/broadcasts to a different ++ * bound-to-device socket ++ * Hirokazu Takahashi : HW checksumming for outgoing UDP ++ * datagrams. ++ * Hirokazu Takahashi : sendfile() on UDP works now. ++ * Arnaldo C. Melo : convert /proc/net/udp to seq_file ++ * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which ++ * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind ++ * a single port at the same time. ++ * Derek Atkins : Add Encapulation Support ++ * James Chapman : Add L2TP encapsulation type. ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "udp_impl.h" ++ ++struct udp_table udp_table; ++EXPORT_SYMBOL(udp_table); ++ ++int sysctl_udp_mem[3] __read_mostly; ++int sysctl_udp_rmem_min __read_mostly; ++int sysctl_udp_wmem_min __read_mostly; ++ ++EXPORT_SYMBOL(sysctl_udp_mem); ++EXPORT_SYMBOL(sysctl_udp_rmem_min); ++EXPORT_SYMBOL(sysctl_udp_wmem_min); ++ ++atomic_t udp_memory_allocated; ++EXPORT_SYMBOL(udp_memory_allocated); ++ ++#define PORTS_PER_CHAIN (65536 / UDP_HTABLE_SIZE) ++ ++static int udp_lib_lport_inuse(struct net *net, __u16 num, ++ const struct udp_hslot *hslot, ++ unsigned long *bitmap, ++ struct sock *sk, ++ int (*saddr_comp)(const struct sock *sk1, ++ const struct sock *sk2)) ++{ ++ struct sock *sk2; ++ struct hlist_nulls_node *node; ++ ++ sk_nulls_for_each(sk2, node, &hslot->head) ++ if (net_eq(sock_net(sk2), net) && ++ sk2 != sk && ++ (bitmap || sk2->sk_hash == num) && ++ (!sk2->sk_reuse || !sk->sk_reuse) && ++ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ++ || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && ++ (*saddr_comp)(sk, sk2)) { ++ if (bitmap) ++ __set_bit(sk2->sk_hash / UDP_HTABLE_SIZE, ++ bitmap); ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 ++ * ++ * @sk: socket struct in question ++ * @snum: port number to look up ++ * @saddr_comp: AF-dependent comparison of bound local IP addresses ++ */ ++int udp_lib_get_port(struct sock *sk, unsigned short snum, ++ int (*saddr_comp)(const struct sock *sk1, ++ const struct sock *sk2 ) ) ++{ ++ struct udp_hslot *hslot; ++ struct udp_table *udptable = sk->sk_prot->h.udp_table; ++ int error = 1; ++ struct net *net = sock_net(sk); ++ ++ if (!snum) { ++ int low, high, remaining; ++ unsigned rand; ++ unsigned short first, last; ++ DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN); ++ ++ inet_get_local_port_range(&low, &high); ++ remaining = (high - low) + 1; ++ ++ rand = net_random(); ++ first = (((u64)rand * remaining) >> 32) + low; ++ /* ++ * force rand to be an odd multiple of UDP_HTABLE_SIZE ++ */ ++ rand = (rand | 1) * UDP_HTABLE_SIZE; ++ for (last = first + UDP_HTABLE_SIZE; first != last; first++) { ++ hslot = &udptable->hash[udp_hashfn(net, first)]; ++ bitmap_zero(bitmap, PORTS_PER_CHAIN); ++ spin_lock_bh(&hslot->lock); ++ udp_lib_lport_inuse(net, snum, hslot, bitmap, sk, ++ saddr_comp); ++ ++ snum = first; ++ /* ++ * Iterate on all possible values of snum for this hash. ++ * Using steps of an odd multiple of UDP_HTABLE_SIZE ++ * give us randomization and full range coverage. ++ */ ++ do { ++ if (low <= snum && snum <= high && ++ !test_bit(snum / UDP_HTABLE_SIZE, bitmap)) ++ goto found; ++ snum += rand; ++ } while (snum != first); ++ spin_unlock_bh(&hslot->lock); ++ } ++ goto fail; ++ } else { ++ hslot = &udptable->hash[udp_hashfn(net, snum)]; ++ spin_lock_bh(&hslot->lock); ++ if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp)) ++ goto fail_unlock; ++ } ++found: ++ inet_sk(sk)->num = snum; ++ sk->sk_hash = snum; ++ if (sk_unhashed(sk)) { ++ sk_nulls_add_node_rcu(sk, &hslot->head); ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); ++ } ++ error = 0; ++fail_unlock: ++ spin_unlock_bh(&hslot->lock); ++fail: ++ return error; ++} ++ ++static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) ++{ ++ struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); ++ ++ return ( !ipv6_only_sock(sk2) && ++ (!inet1->rcv_saddr || !inet2->rcv_saddr || ++ inet1->rcv_saddr == inet2->rcv_saddr )); ++} ++ ++int udp_v4_get_port(struct sock *sk, unsigned short snum) ++{ ++ return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); ++} ++ ++static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, ++ unsigned short hnum, ++ __be16 sport, __be32 daddr, __be16 dport, int dif) ++{ ++ int score = -1; ++ ++ if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && ++ !ipv6_only_sock(sk)) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ score = (sk->sk_family == PF_INET ? 1 : 0); ++ if (inet->rcv_saddr) { ++ if (inet->rcv_saddr != daddr) ++ return -1; ++ score += 2; ++ } ++ if (inet->daddr) { ++ if (inet->daddr != saddr) ++ return -1; ++ score += 2; ++ } ++ if (inet->dport) { ++ if (inet->dport != sport) ++ return -1; ++ score += 2; ++ } ++ if (sk->sk_bound_dev_if) { ++ if (sk->sk_bound_dev_if != dif) ++ return -1; ++ score += 2; ++ } ++ } ++ return score; ++} ++ ++/* UDP is nearly always wildcards out the wazoo, it makes no sense to try ++ * harder than this. -DaveM ++ */ ++static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, ++ __be16 sport, __be32 daddr, __be16 dport, ++ int dif, struct udp_table *udptable) ++{ ++ struct sock *sk, *result; ++ struct hlist_nulls_node *node; ++ unsigned short hnum = ntohs(dport); ++ unsigned int hash = udp_hashfn(net, hnum); ++ struct udp_hslot *hslot = &udptable->hash[hash]; ++ int score, badness; ++ ++ rcu_read_lock(); ++begin: ++ result = NULL; ++ badness = -1; ++ sk_nulls_for_each_rcu(sk, node, &hslot->head) { ++ score = compute_score(sk, net, saddr, hnum, sport, ++ daddr, dport, dif); ++ if (score > badness) { ++ result = sk; ++ badness = score; ++ } ++ } ++ /* ++ * if the nulls value we got at the end of this lookup is ++ * not the expected one, we must restart lookup. ++ * We probably met an item that was moved to another chain. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ ++ if (result) { ++ if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) ++ result = NULL; ++ else if (unlikely(compute_score(result, net, saddr, hnum, sport, ++ daddr, dport, dif) < badness)) { ++ sock_put(result); ++ goto begin; ++ } ++ } ++ rcu_read_unlock(); ++ return result; ++} ++ ++static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, ++ __be16 sport, __be16 dport, ++ struct udp_table *udptable) ++{ ++ struct sock *sk; ++ const struct iphdr *iph = ip_hdr(skb); ++ ++ if (unlikely(sk = skb_steal_sock(skb))) ++ return sk; ++ else ++ return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport, ++ iph->daddr, dport, inet_iif(skb), ++ udptable); ++} ++ ++struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, ++ __be32 daddr, __be16 dport, int dif) ++{ ++ return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); ++} ++EXPORT_SYMBOL_GPL(udp4_lib_lookup); ++ ++static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, ++ __be16 loc_port, __be32 loc_addr, ++ __be16 rmt_port, __be32 rmt_addr, ++ int dif) ++{ ++ struct hlist_nulls_node *node; ++ struct sock *s = sk; ++ unsigned short hnum = ntohs(loc_port); ++ ++ sk_nulls_for_each_from(s, node) { ++ struct inet_sock *inet = inet_sk(s); ++ ++ if (!net_eq(sock_net(s), net) || ++ s->sk_hash != hnum || ++ (inet->daddr && inet->daddr != rmt_addr) || ++ (inet->dport != rmt_port && inet->dport) || ++ (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || ++ ipv6_only_sock(s) || ++ (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) ++ continue; ++ if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) ++ continue; ++ goto found; ++ } ++ s = NULL; ++found: ++ return s; ++} ++ ++/* ++ * This routine is called by the ICMP module when it gets some ++ * sort of error condition. If err < 0 then the socket should ++ * be closed and the error returned to the user. If err > 0 ++ * it's just the icmp type << 8 | icmp code. ++ * Header points to the ip header of the error packet. We move ++ * on past this. Then (as it used to claim before adjustment) ++ * header points to the first 8 bytes of the udp header. We need ++ * to find the appropriate port. ++ */ ++ ++void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) ++{ ++ struct inet_sock *inet; ++ struct iphdr *iph = (struct iphdr*)skb->data; ++ struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); ++ const int type = icmp_hdr(skb)->type; ++ const int code = icmp_hdr(skb)->code; ++ struct sock *sk; ++ int harderr; ++ int err; ++ struct net *net = dev_net(skb->dev); ++ ++ sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, ++ iph->saddr, uh->source, skb->dev->ifindex, udptable); ++ if (sk == NULL) { ++ ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); ++ return; /* No socket for error */ ++ } ++ ++ err = 0; ++ harderr = 0; ++ inet = inet_sk(sk); ++ ++ switch (type) { ++ default: ++ case ICMP_TIME_EXCEEDED: ++ err = EHOSTUNREACH; ++ break; ++ case ICMP_SOURCE_QUENCH: ++ goto out; ++ case ICMP_PARAMETERPROB: ++ err = EPROTO; ++ harderr = 1; ++ break; ++ case ICMP_DEST_UNREACH: ++ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ ++ if (inet->pmtudisc != IP_PMTUDISC_DONT) { ++ err = EMSGSIZE; ++ harderr = 1; ++ break; ++ } ++ goto out; ++ } ++ err = EHOSTUNREACH; ++ if (code <= NR_ICMP_UNREACH) { ++ harderr = icmp_err_convert[code].fatal; ++ err = icmp_err_convert[code].errno; ++ } ++ break; ++ } ++ ++ /* ++ * RFC1122: OK. Passes ICMP errors back to application, as per ++ * 4.1.3.3. ++ */ ++ if (!inet->recverr) { ++ if (!harderr || sk->sk_state != TCP_ESTABLISHED) ++ goto out; ++ } else { ++ ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); ++ } ++ sk->sk_err = err; ++ sk->sk_error_report(sk); ++out: ++ sock_put(sk); ++} ++ ++void udp_err(struct sk_buff *skb, u32 info) ++{ ++ __udp4_lib_err(skb, info, &udp_table); ++} ++ ++/* ++ * Throw away all pending data and cancel the corking. Socket is locked. ++ */ ++void udp_flush_pending_frames(struct sock *sk) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ ++ if (up->pending) { ++ up->len = 0; ++ up->pending = 0; ++ ip_flush_pending_frames(sk); ++ } ++} ++EXPORT_SYMBOL(udp_flush_pending_frames); ++ ++/** ++ * udp4_hwcsum_outgoing - handle outgoing HW checksumming ++ * @sk: socket we are sending on ++ * @skb: sk_buff containing the filled-in UDP header ++ * (checksum field must be zeroed out) ++ */ ++static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ++ __be32 src, __be32 dst, int len ) ++{ ++ unsigned int offset; ++ struct udphdr *uh = udp_hdr(skb); ++ __wsum csum = 0; ++ ++ if (skb_queue_len(&sk->sk_write_queue) == 1) { ++ /* ++ * Only one fragment on the socket. ++ */ ++ skb->csum_start = skb_transport_header(skb) - skb->head; ++ skb->csum_offset = offsetof(struct udphdr, check); ++ uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); ++ } else { ++ /* ++ * HW-checksum won't work as there are two or more ++ * fragments on the socket so that all csums of sk_buffs ++ * should be together ++ */ ++ offset = skb_transport_offset(skb); ++ skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ skb_queue_walk(&sk->sk_write_queue, skb) { ++ csum = csum_add(csum, skb->csum); ++ } ++ ++ uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); ++ if (uh->check == 0) ++ uh->check = CSUM_MANGLED_0; ++ } ++} ++ ++/* ++ * Push out all pending data as one UDP datagram. Socket is locked. ++ */ ++static int udp_push_pending_frames(struct sock *sk) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ struct inet_sock *inet = inet_sk(sk); ++ struct flowi *fl = &inet->cork.fl; ++ struct sk_buff *skb; ++ struct udphdr *uh; ++ int err = 0; ++ int is_udplite = IS_UDPLITE(sk); ++ __wsum csum = 0; ++ ++ /* Grab the skbuff where UDP header space exists. */ ++ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) ++ goto out; ++ ++ /* ++ * Create a UDP header ++ */ ++ uh = udp_hdr(skb); ++ uh->source = fl->fl_ip_sport; ++ uh->dest = fl->fl_ip_dport; ++ uh->len = htons(up->len); ++ uh->check = 0; ++ ++ if (is_udplite) /* UDP-Lite */ ++ csum = udplite_csum_outgoing(sk, skb); ++ ++ else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ goto send; ++ ++ } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ ++ ++ udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); ++ goto send; ++ ++ } else /* `normal' UDP */ ++ csum = udp_csum_outgoing(sk, skb); ++ ++ /* add protocol-dependent pseudo-header */ ++ uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, ++ sk->sk_protocol, csum ); ++ if (uh->check == 0) ++ uh->check = CSUM_MANGLED_0; ++ ++send: ++ err = ip_push_pending_frames(sk); ++out: ++ up->len = 0; ++ up->pending = 0; ++ if (!err) ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_OUTDATAGRAMS, is_udplite); ++ return err; ++} ++ ++int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ++ size_t len) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct udp_sock *up = udp_sk(sk); ++ int ulen = len; ++ struct ipcm_cookie ipc; ++ struct rtable *rt = NULL; ++ int free = 0; ++ int connected = 0; ++ __be32 daddr, faddr, saddr; ++ __be16 dport; ++ u8 tos; ++ int err, is_udplite = IS_UDPLITE(sk); ++ int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; ++ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); ++ ++ if (len > 0xFFFF) ++ return -EMSGSIZE; ++ ++ /* ++ * Check the flags. ++ */ ++ ++ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ ++ return -EOPNOTSUPP; ++ ++ ipc.opt = NULL; ++ ipc.shtx.flags = 0; ++ ++ if (up->pending) { ++ /* ++ * There are pending frames. ++ * The socket lock must be held while it's corked. ++ */ ++ lock_sock(sk); ++ if (likely(up->pending)) { ++ if (unlikely(up->pending != AF_INET)) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ goto do_append_data; ++ } ++ release_sock(sk); ++ } ++ ulen += sizeof(struct udphdr); ++ ++ /* ++ * Get and verify the address. ++ */ ++ if (msg->msg_name) { ++ struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; ++ if (msg->msg_namelen < sizeof(*usin)) ++ return -EINVAL; ++ if (usin->sin_family != AF_INET) { ++ if (usin->sin_family != AF_UNSPEC) ++ return -EAFNOSUPPORT; ++ } ++ ++ daddr = usin->sin_addr.s_addr; ++ dport = usin->sin_port; ++ if (dport == 0) ++ return -EINVAL; ++ } else { ++ if (sk->sk_state != TCP_ESTABLISHED) ++ return -EDESTADDRREQ; ++ daddr = inet->daddr; ++ dport = inet->dport; ++ /* Open fast path for connected socket. ++ Route will not be used, if at least one option is set. ++ */ ++ connected = 1; ++ } ++ ipc.addr = inet->saddr; ++ ++ ipc.oif = sk->sk_bound_dev_if; ++ err = sock_tx_timestamp(msg, sk, &ipc.shtx); ++ if (err) ++ return err; ++ if (msg->msg_controllen) { ++ err = ip_cmsg_send(sock_net(sk), msg, &ipc); ++ if (err) ++ return err; ++ if (ipc.opt) ++ free = 1; ++ connected = 0; ++ } ++ if (!ipc.opt) ++ ipc.opt = inet->opt; ++ ++ saddr = ipc.addr; ++ ipc.addr = faddr = daddr; ++ ++ if (ipc.opt && ipc.opt->srr) { ++ if (!daddr) ++ return -EINVAL; ++ faddr = ipc.opt->faddr; ++ connected = 0; ++ } ++ tos = RT_TOS(inet->tos); ++ if (sock_flag(sk, SOCK_LOCALROUTE) || ++ (msg->msg_flags & MSG_DONTROUTE) || ++ (ipc.opt && ipc.opt->is_strictroute)) { ++ tos |= RTO_ONLINK; ++ connected = 0; ++ } ++ ++ if (ipv4_is_multicast(daddr)) { ++ if (!ipc.oif) ++ ipc.oif = inet->mc_index; ++ if (!saddr) ++ saddr = inet->mc_addr; ++ connected = 0; ++ } ++ ++ if (connected) ++ rt = (struct rtable*)sk_dst_check(sk, 0); ++ ++ if (rt == NULL) { ++ struct flowi fl = { .oif = ipc.oif, ++ .nl_u = { .ip4_u = ++ { .daddr = faddr, ++ .saddr = saddr, ++ .tos = tos } }, ++ .proto = sk->sk_protocol, ++ .flags = inet_sk_flowi_flags(sk), ++ .uli_u = { .ports = ++ { .sport = inet->sport, ++ .dport = dport } } }; ++ struct net *net = sock_net(sk); ++ ++ security_sk_classify_flow(sk, &fl); ++ err = ip_route_output_flow(net, &rt, &fl, sk, 1); ++ if (err) { ++ if (err == -ENETUNREACH) ++ IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); ++ goto out; ++ } ++ ++ err = -EACCES; ++ if ((rt->rt_flags & RTCF_BROADCAST) && ++ !sock_flag(sk, SOCK_BROADCAST)) ++ goto out; ++ if (connected) ++ sk_dst_set(sk, dst_clone(&rt->u.dst)); ++ } ++ ++ if (msg->msg_flags&MSG_CONFIRM) ++ goto do_confirm; ++back_from_confirm: ++ ++ saddr = rt->rt_src; ++ if (!ipc.addr) ++ daddr = ipc.addr = rt->rt_dst; ++ ++ lock_sock(sk); ++ if (unlikely(up->pending)) { ++ /* The socket is already corked while preparing it. */ ++ /* ... which is an evident application bug. --ANK */ ++ release_sock(sk); ++ ++ LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); ++ err = -EINVAL; ++ goto out; ++ } ++ /* ++ * Now cork the socket to pend data. ++ */ ++ inet->cork.fl.fl4_dst = daddr; ++ inet->cork.fl.fl_ip_dport = dport; ++ inet->cork.fl.fl4_src = saddr; ++ inet->cork.fl.fl_ip_sport = inet->sport; ++ up->pending = AF_INET; ++ ++do_append_data: ++ up->len += ulen; ++ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; ++ err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, ++ sizeof(struct udphdr), &ipc, &rt, ++ corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); ++ if (err) ++ udp_flush_pending_frames(sk); ++ else if (!corkreq) ++ err = udp_push_pending_frames(sk); ++ else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) ++ up->pending = 0; ++ release_sock(sk); ++ ++out: ++ ip_rt_put(rt); ++ if (free) ++ kfree(ipc.opt); ++ if (!err) ++ return len; ++ /* ++ * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting ++ * ENOBUFS might not be good (it's not tunable per se), but otherwise ++ * we don't have a good statistic (IpOutDiscards but it can be too many ++ * things). We could add another new stat but at least for now that ++ * seems like overkill. ++ */ ++ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_SNDBUFERRORS, is_udplite); ++ } ++ return err; ++ ++do_confirm: ++ dst_confirm(&rt->u.dst); ++ if (!(msg->msg_flags&MSG_PROBE) || len) ++ goto back_from_confirm; ++ err = 0; ++ goto out; ++} ++ ++int udp_sendpage(struct sock *sk, struct page *page, int offset, ++ size_t size, int flags) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int ret; ++ ++ if (!up->pending) { ++ struct msghdr msg = { .msg_flags = flags|MSG_MORE }; ++ ++ /* Call udp_sendmsg to specify destination address which ++ * sendpage interface can't pass. ++ * This will succeed only when the socket is connected. ++ */ ++ ret = udp_sendmsg(NULL, sk, &msg, 0); ++ if (ret < 0) ++ return ret; ++ } ++ ++ lock_sock(sk); ++ ++ if (unlikely(!up->pending)) { ++ release_sock(sk); ++ ++ LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); ++ return -EINVAL; ++ } ++ ++ ret = ip_append_page(sk, page, offset, size, flags); ++ if (ret == -EOPNOTSUPP) { ++ release_sock(sk); ++ return sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ } ++ if (ret < 0) { ++ udp_flush_pending_frames(sk); ++ goto out; ++ } ++ ++ up->len += size; ++ if (!(up->corkflag || (flags&MSG_MORE))) ++ ret = udp_push_pending_frames(sk); ++ if (!ret) ++ ret = size; ++out: ++ release_sock(sk); ++ return ret; ++} ++ ++/* ++ * IOCTL requests applicable to the UDP protocol ++ */ ++ ++int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case SIOCOUTQ: ++ { ++ int amount = atomic_read(&sk->sk_wmem_alloc); ++ return put_user(amount, (int __user *)arg); ++ } ++ ++ case SIOCINQ: ++ { ++ struct sk_buff *skb; ++ unsigned long amount; ++ ++ amount = 0; ++ spin_lock_bh(&sk->sk_receive_queue.lock); ++ skb = skb_peek(&sk->sk_receive_queue); ++ if (skb != NULL) { ++ /* ++ * We will only return the amount ++ * of this packet since that is all ++ * that will be read. ++ */ ++ amount = skb->len - sizeof(struct udphdr); ++ } ++ spin_unlock_bh(&sk->sk_receive_queue.lock); ++ return put_user(amount, (int __user *)arg); ++ } ++ ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This should be easy, if there is something there we ++ * return it, otherwise we block. ++ */ ++ ++int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ++ size_t len, int noblock, int flags, int *addr_len) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; ++ struct sk_buff *skb; ++ unsigned int ulen, copied; ++ int peeked; ++ int err; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ /* ++ * Check any passed addresses ++ */ ++ if (addr_len) ++ *addr_len=sizeof(*sin); ++ ++ if (flags & MSG_ERRQUEUE) ++ return ip_recv_error(sk, msg, len); ++ ++try_again: ++ skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), ++ &peeked, &err); ++ if (!skb) ++ goto out; ++ ++ ulen = skb->len - sizeof(struct udphdr); ++ copied = len; ++ if (copied > ulen) ++ copied = ulen; ++ else if (copied < ulen) ++ msg->msg_flags |= MSG_TRUNC; ++ ++ /* ++ * If checksum is needed at all, try to do it while copying the ++ * data. If the data is truncated, or if we only want a partial ++ * coverage checksum (UDP-Lite), do it before the copy. ++ */ ++ ++ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { ++ if (udp_lib_checksum_complete(skb)) ++ goto csum_copy_err; ++ } ++ ++ if (skb_csum_unnecessary(skb)) ++ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), ++ msg->msg_iov, copied ); ++ else { ++ err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); ++ ++ if (err == -EINVAL) ++ goto csum_copy_err; ++ } ++ ++ if (err) ++ goto out_free; ++ ++ if (!peeked) ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_INDATAGRAMS, is_udplite); ++ ++ sock_recv_timestamp(msg, sk, skb); ++ ++ /* Copy the address. */ ++ if (sin) ++ { ++ sin->sin_family = AF_INET; ++ sin->sin_port = udp_hdr(skb)->source; ++ sin->sin_addr.s_addr = ip_hdr(skb)->saddr; ++ memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ } ++ if (inet->cmsg_flags) ++ ip_cmsg_recv(msg, skb); ++ ++ err = copied; ++ if (flags & MSG_TRUNC) ++ err = ulen; ++ ++out_free: ++ lock_sock(sk); ++ skb_free_datagram(sk, skb); ++ release_sock(sk); ++out: ++ return err; ++ ++csum_copy_err: ++ lock_sock(sk); ++ if (!skb_kill_datagram(sk, skb, flags)) ++ UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ release_sock(sk); ++ ++ if (noblock) ++ return -EAGAIN; ++ goto try_again; ++} ++ ++ ++int udp_disconnect(struct sock *sk, int flags) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ /* ++ * 1003.1g - break association. ++ */ ++ ++ sk->sk_state = TCP_CLOSE; ++ inet->daddr = 0; ++ inet->dport = 0; ++ sk->sk_bound_dev_if = 0; ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); ++ ++ if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { ++ sk->sk_prot->unhash(sk); ++ inet->sport = 0; ++ } ++ sk_dst_reset(sk); ++ return 0; ++} ++ ++void udp_lib_unhash(struct sock *sk) ++{ ++ if (sk_hashed(sk)) { ++ struct udp_table *udptable = sk->sk_prot->h.udp_table; ++ unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash); ++ struct udp_hslot *hslot = &udptable->hash[hash]; ++ ++ spin_lock_bh(&hslot->lock); ++ if (sk_nulls_del_node_init_rcu(sk)) { ++ inet_sk(sk)->num = 0; ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); ++ } ++ spin_unlock_bh(&hslot->lock); ++ } ++} ++EXPORT_SYMBOL(udp_lib_unhash); ++ ++static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ int is_udplite = IS_UDPLITE(sk); ++ int rc; ++ ++ if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { ++ /* Note that an ENOMEM error is charged twice */ ++ if (rc == -ENOMEM) { ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, ++ is_udplite); ++ atomic_inc(&sk->sk_drops); ++ } ++ goto drop; ++ } ++ ++ return 0; ++ ++drop: ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ kfree_skb(skb); ++ return -1; ++} ++ ++/* returns: ++ * -1: error ++ * 0: success ++ * >0: "udp encap" protocol resubmission ++ * ++ * Note that in the success and error cases, the skb is assumed to ++ * have either been requeued or freed. ++ */ ++int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int rc; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ /* ++ * Charge it to the socket, dropping if the queue is full. ++ */ ++ if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) ++ goto drop; ++ nf_reset(skb); ++ ++ if (up->encap_type) { ++ /* ++ * This is an encapsulation socket so pass the skb to ++ * the socket's udp_encap_rcv() hook. Otherwise, just ++ * fall through and pass this up the UDP socket. ++ * up->encap_rcv() returns the following value: ++ * =0 if skb was successfully passed to the encap ++ * handler or was discarded by it. ++ * >0 if skb should be passed on to UDP. ++ * <0 if skb should be resubmitted as proto -N ++ */ ++ ++ /* if we're overly short, let UDP handle it */ ++ if (skb->len > sizeof(struct udphdr) && ++ up->encap_rcv != NULL) { ++ int ret; ++ ++ ret = (*up->encap_rcv)(sk, skb); ++ if (ret <= 0) { ++ UDP_INC_STATS_BH(sock_net(sk), ++ UDP_MIB_INDATAGRAMS, ++ is_udplite); ++ return -ret; ++ } ++ } ++ ++ /* FALLTHROUGH -- it's a UDP Packet */ ++ } ++ ++ /* ++ * UDP-Lite specific tests, ignored on UDP sockets ++ */ ++ if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { ++ ++ /* ++ * MIB statistics other than incrementing the error count are ++ * disabled for the following two types of errors: these depend ++ * on the application settings, not on the functioning of the ++ * protocol stack as such. ++ * ++ * RFC 3828 here recommends (sec 3.3): "There should also be a ++ * way ... to ... at least let the receiving application block ++ * delivery of packets with coverage values less than a value ++ * provided by the application." ++ */ ++ if (up->pcrlen == 0) { /* full coverage was set */ ++ LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " ++ "%d while full coverage %d requested\n", ++ UDP_SKB_CB(skb)->cscov, skb->len); ++ goto drop; ++ } ++ /* The next case involves violating the min. coverage requested ++ * by the receiver. This is subtle: if receiver wants x and x is ++ * greater than the buffersize/MTU then receiver will complain ++ * that it wants x while sender emits packets of smaller size y. ++ * Therefore the above ...()->partial_cov statement is essential. ++ */ ++ if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { ++ LIMIT_NETDEBUG(KERN_WARNING ++ "UDPLITE: coverage %d too small, need min %d\n", ++ UDP_SKB_CB(skb)->cscov, up->pcrlen); ++ goto drop; ++ } ++ } ++ ++ if (sk->sk_filter) { ++ if (udp_lib_checksum_complete(skb)) ++ goto drop; ++ } ++ ++ rc = 0; ++ ++ bh_lock_sock(sk); ++ if (!sock_owned_by_user(sk)) ++ rc = __udp_queue_rcv_skb(sk, skb); ++ else ++ sk_add_backlog(sk, skb); ++ bh_unlock_sock(sk); ++ ++ return rc; ++ ++drop: ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ kfree_skb(skb); ++ return -1; ++} ++ ++/* ++ * Multicasts and broadcasts go to each listener. ++ * ++ * Note: called only from the BH handler context, ++ * so we don't need to lock the hashes. ++ */ ++static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, ++ struct udphdr *uh, ++ __be32 saddr, __be32 daddr, ++ struct udp_table *udptable) ++{ ++ struct sock *sk; ++ struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; ++ int dif; ++ ++ spin_lock(&hslot->lock); ++ sk = sk_nulls_head(&hslot->head); ++ dif = skb->dev->ifindex; ++ sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); ++ if (sk) { ++ struct sock *sknext = NULL; ++ ++ do { ++ struct sk_buff *skb1 = skb; ++ ++ sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, ++ daddr, uh->source, saddr, ++ dif); ++ if (sknext) ++ skb1 = skb_clone(skb, GFP_ATOMIC); ++ ++ if (skb1) { ++ int ret = udp_queue_rcv_skb(sk, skb1); ++ if (ret > 0) ++ /* we should probably re-process instead ++ * of dropping packets here. */ ++ kfree_skb(skb1); ++ } ++ sk = sknext; ++ } while (sknext); ++ } else ++ consume_skb(skb); ++ spin_unlock(&hslot->lock); ++ return 0; ++} ++ ++/* Initialize UDP checksum. If exited with zero value (success), ++ * CHECKSUM_UNNECESSARY means, that no more checks are required. ++ * Otherwise, csum completion requires chacksumming packet body, ++ * including udp header and folding it to skb->csum. ++ */ ++static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, ++ int proto) ++{ ++ const struct iphdr *iph; ++ int err; ++ ++ UDP_SKB_CB(skb)->partial_cov = 0; ++ UDP_SKB_CB(skb)->cscov = skb->len; ++ ++ if (proto == IPPROTO_UDPLITE) { ++ err = udplite_checksum_init(skb, uh); ++ if (err) ++ return err; ++ } ++ ++ iph = ip_hdr(skb); ++ if (uh->check == 0) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else if (skb->ip_summed == CHECKSUM_COMPLETE) { ++ if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, ++ proto, skb->csum)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } ++ if (!skb_csum_unnecessary(skb)) ++ skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, ++ skb->len, proto, 0); ++ /* Probably, we should checksum udp header (it should be in cache ++ * in any case) and data in tiny packets (< rx copybreak). ++ */ ++ ++ return 0; ++} ++ ++/* ++ * All we need to do is get the socket, and then do a checksum. ++ */ ++ ++int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, ++ int proto) ++{ ++ struct sock *sk; ++ struct udphdr *uh; ++ unsigned short ulen; ++ struct rtable *rt = (struct rtable*)skb->dst; ++ __be32 saddr, daddr; ++ struct net *net = dev_net(skb->dev); ++ ++ /* ++ * Validate the packet. ++ */ ++ if (!pskb_may_pull(skb, sizeof(struct udphdr))) ++ goto drop; /* No space for header. */ ++ ++ uh = udp_hdr(skb); ++ ulen = ntohs(uh->len); ++ if (ulen > skb->len) ++ goto short_packet; ++ ++ if (proto == IPPROTO_UDP) { ++ /* UDP validates ulen. */ ++ if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) ++ goto short_packet; ++ uh = udp_hdr(skb); ++ } ++ ++ if (udp4_csum_init(skb, uh, proto)) ++ goto csum_error; ++ ++ saddr = ip_hdr(skb)->saddr; ++ daddr = ip_hdr(skb)->daddr; ++ ++ if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) ++ return __udp4_lib_mcast_deliver(net, skb, uh, ++ saddr, daddr, udptable); ++ ++ sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); ++ ++ if (sk != NULL) { ++ int ret = udp_queue_rcv_skb(sk, skb); ++ sock_put(sk); ++ ++ /* a return value > 0 means to resubmit the input, but ++ * it wants the return to be -protocol, or 0 ++ */ ++ if (ret > 0) ++ return -ret; ++ return 0; ++ } ++ ++ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) ++ goto drop; ++ nf_reset(skb); ++ ++ /* No socket. Drop packet silently, if checksum is wrong */ ++ if (udp_lib_checksum_complete(skb)) ++ goto csum_error; ++ ++ UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); ++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); ++ ++ /* ++ * Hmm. We got an UDP packet to a port to which we ++ * don't wanna listen. Ignore it. ++ */ ++ kfree_skb(skb); ++ return 0; ++ ++short_packet: ++ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", ++ proto == IPPROTO_UDPLITE ? "-Lite" : "", ++ &saddr, ++ ntohs(uh->source), ++ ulen, ++ skb->len, ++ &daddr, ++ ntohs(uh->dest)); ++ goto drop; ++ ++csum_error: ++ /* ++ * RFC1122: OK. Discards the bad packet silently (as far as ++ * the network is concerned, anyway) as per 4.1.3.4 (MUST). ++ */ ++ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", ++ proto == IPPROTO_UDPLITE ? "-Lite" : "", ++ &saddr, ++ ntohs(uh->source), ++ &daddr, ++ ntohs(uh->dest), ++ ulen); ++drop: ++ UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); ++ kfree_skb(skb); ++ return 0; ++} ++ ++int udp_rcv(struct sk_buff *skb) ++{ ++ return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP); ++} ++ ++void udp_destroy_sock(struct sock *sk) ++{ ++ lock_sock(sk); ++ udp_flush_pending_frames(sk); ++ release_sock(sk); ++} ++ ++/* ++ * Socket option code for UDP ++ */ ++int udp_lib_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen, ++ int (*push_pending_frames)(struct sock *)) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int val; ++ int err = 0; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ if (optlencorkflag = 1; ++ } else { ++ up->corkflag = 0; ++ lock_sock(sk); ++ (*push_pending_frames)(sk); ++ release_sock(sk); ++ } ++ break; ++ ++ case UDP_ENCAP: ++ switch (val) { ++ case 0: ++ case UDP_ENCAP_ESPINUDP: ++ case UDP_ENCAP_ESPINUDP_NON_IKE: ++ up->encap_rcv = xfrm4_udp_encap_rcv; ++ /* FALLTHROUGH */ ++ case UDP_ENCAP_L2TPINUDP: ++ up->encap_type = val; ++ break; ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ break; ++ ++ /* ++ * UDP-Lite's partial checksum coverage (RFC 3828). ++ */ ++ /* The sender sets actual checksum coverage length via this option. ++ * The case coverage > packet length is handled by send module. */ ++ case UDPLITE_SEND_CSCOV: ++ if (!is_udplite) /* Disable the option on UDP sockets */ ++ return -ENOPROTOOPT; ++ if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ ++ val = 8; ++ else if (val > USHORT_MAX) ++ val = USHORT_MAX; ++ up->pcslen = val; ++ up->pcflag |= UDPLITE_SEND_CC; ++ break; ++ ++ /* The receiver specifies a minimum checksum coverage value. To make ++ * sense, this should be set to at least 8 (as done below). If zero is ++ * used, this again means full checksum coverage. */ ++ case UDPLITE_RECV_CSCOV: ++ if (!is_udplite) /* Disable the option on UDP sockets */ ++ return -ENOPROTOOPT; ++ if (val != 0 && val < 8) /* Avoid silly minimal values. */ ++ val = 8; ++ else if (val > USHORT_MAX) ++ val = USHORT_MAX; ++ up->pcrlen = val; ++ up->pcflag |= UDPLITE_RECV_CC; ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ return err; ++} ++ ++int udp_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_setsockopt(sk, level, optname, optval, optlen, ++ udp_push_pending_frames); ++ return ip_setsockopt(sk, level, optname, optval, optlen); ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_udp_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_setsockopt(sk, level, optname, optval, optlen, ++ udp_push_pending_frames); ++ return compat_ip_setsockopt(sk, level, optname, optval, optlen); ++} ++#endif ++ ++int udp_lib_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int val, len; ++ ++ if (get_user(len,optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(int)); ++ ++ if (len < 0) ++ return -EINVAL; ++ ++ switch (optname) { ++ case UDP_CORK: ++ val = up->corkflag; ++ break; ++ ++ case UDP_ENCAP: ++ val = up->encap_type; ++ break; ++ ++ /* The following two cannot be changed on UDP sockets, the return is ++ * always 0 (which corresponds to the full checksum coverage of UDP). */ ++ case UDPLITE_SEND_CSCOV: ++ val = up->pcslen; ++ break; ++ ++ case UDPLITE_RECV_CSCOV: ++ val = up->pcrlen; ++ break; ++ ++ default: ++ return -ENOPROTOOPT; ++ } ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ if (copy_to_user(optval, &val,len)) ++ return -EFAULT; ++ return 0; ++} ++ ++int udp_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_getsockopt(sk, level, optname, optval, optlen); ++ return ip_getsockopt(sk, level, optname, optval, optlen); ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_udp_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_getsockopt(sk, level, optname, optval, optlen); ++ return compat_ip_getsockopt(sk, level, optname, optval, optlen); ++} ++#endif ++/** ++ * udp_poll - wait for a UDP event. ++ * @file - file struct ++ * @sock - socket ++ * @wait - poll table ++ * ++ * This is same as datagram poll, except for the special case of ++ * blocking sockets. If application is using a blocking fd ++ * and a packet with checksum error is in the queue; ++ * then it could get return from select indicating data available ++ * but then block when reading it. Add special case code ++ * to work around these arguably broken applications. ++ */ ++unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) ++{ ++ unsigned int mask = datagram_poll(file, sock, wait); ++ struct sock *sk = sock->sk; ++ int is_lite = IS_UDPLITE(sk); ++ ++ /* Check for false positives due to checksum errors */ ++ if ( (mask & POLLRDNORM) && ++ !(file->f_flags & O_NONBLOCK) && ++ !(sk->sk_shutdown & RCV_SHUTDOWN)){ ++ struct sk_buff_head *rcvq = &sk->sk_receive_queue; ++ struct sk_buff *skb; ++ ++ spin_lock_bh(&rcvq->lock); ++ while ((skb = skb_peek(rcvq)) != NULL && ++ udp_lib_checksum_complete(skb)) { ++ UDP_INC_STATS_BH(sock_net(sk), ++ UDP_MIB_INERRORS, is_lite); ++ __skb_unlink(skb, rcvq); ++ kfree_skb(skb); ++ } ++ spin_unlock_bh(&rcvq->lock); ++ ++ /* nothing to see, move along */ ++ if (skb == NULL) ++ mask &= ~(POLLIN | POLLRDNORM); ++ } ++ ++ return mask; ++ ++} ++ ++struct proto udp_prot = { ++ .name = "UDP", ++ .owner = THIS_MODULE, ++ .close = udp_lib_close, ++ .connect = ip4_datagram_connect, ++ .disconnect = udp_disconnect, ++ .ioctl = udp_ioctl, ++ .destroy = udp_destroy_sock, ++ .setsockopt = udp_setsockopt, ++ .getsockopt = udp_getsockopt, ++ .sendmsg = udp_sendmsg, ++ .recvmsg = udp_recvmsg, ++ .sendpage = udp_sendpage, ++ .backlog_rcv = __udp_queue_rcv_skb, ++ .hash = udp_lib_hash, ++ .unhash = udp_lib_unhash, ++ .get_port = udp_v4_get_port, ++ .memory_allocated = &udp_memory_allocated, ++ .sysctl_mem = sysctl_udp_mem, ++ .sysctl_wmem = &sysctl_udp_wmem_min, ++ .sysctl_rmem = &sysctl_udp_rmem_min, ++ .obj_size = sizeof(struct udp_sock), ++ .slab_flags = SLAB_DESTROY_BY_RCU, ++ .h.udp_table = &udp_table, ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_udp_setsockopt, ++ .compat_getsockopt = compat_udp_getsockopt, ++#endif ++}; ++ ++/* ------------------------------------------------------------------------ */ ++#ifdef CONFIG_PROC_FS ++ ++static struct sock *udp_get_first(struct seq_file *seq, int start) ++{ ++ struct sock *sk; ++ struct udp_iter_state *state = seq->private; ++ struct net *net = seq_file_net(seq); ++ ++ for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { ++ struct hlist_nulls_node *node; ++ struct udp_hslot *hslot = &state->udp_table->hash[state->bucket]; ++ spin_lock_bh(&hslot->lock); ++ sk_nulls_for_each(sk, node, &hslot->head) { ++ if (!net_eq(sock_net(sk), net)) ++ continue; ++ if (sk->sk_family == state->family) ++ goto found; ++ } ++ spin_unlock_bh(&hslot->lock); ++ } ++ sk = NULL; ++found: ++ return sk; ++} ++ ++static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) ++{ ++ struct udp_iter_state *state = seq->private; ++ struct net *net = seq_file_net(seq); ++ ++ do { ++ sk = sk_nulls_next(sk); ++ } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); ++ ++ if (!sk) { ++ if (state->bucket < UDP_HTABLE_SIZE) ++ spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); ++ return udp_get_first(seq, state->bucket + 1); ++ } ++ return sk; ++} ++ ++static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) ++{ ++ struct sock *sk = udp_get_first(seq, 0); ++ ++ if (sk) ++ while (pos && (sk = udp_get_next(seq, sk)) != NULL) ++ --pos; ++ return pos ? NULL : sk; ++} ++ ++static void *udp_seq_start(struct seq_file *seq, loff_t *pos) ++{ ++ struct udp_iter_state *state = seq->private; ++ state->bucket = UDP_HTABLE_SIZE; ++ ++ return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN; ++} ++ ++static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++{ ++ struct sock *sk; ++ ++ if (v == SEQ_START_TOKEN) ++ sk = udp_get_idx(seq, 0); ++ else ++ sk = udp_get_next(seq, v); ++ ++ ++*pos; ++ return sk; ++} ++ ++static void udp_seq_stop(struct seq_file *seq, void *v) ++{ ++ struct udp_iter_state *state = seq->private; ++ ++ if (state->bucket < UDP_HTABLE_SIZE) ++ spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); ++} ++ ++static int udp_seq_open(struct inode *inode, struct file *file) ++{ ++ struct udp_seq_afinfo *afinfo = PDE(inode)->data; ++ struct udp_iter_state *s; ++ int err; ++ ++ err = seq_open_net(inode, file, &afinfo->seq_ops, ++ sizeof(struct udp_iter_state)); ++ if (err < 0) ++ return err; ++ ++ s = ((struct seq_file *)file->private_data)->private; ++ s->family = afinfo->family; ++ s->udp_table = afinfo->udp_table; ++ return err; ++} ++ ++/* ------------------------------------------------------------------------ */ ++int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) ++{ ++ struct proc_dir_entry *p; ++ int rc = 0; ++ ++ afinfo->seq_fops.open = udp_seq_open; ++ afinfo->seq_fops.read = seq_read; ++ afinfo->seq_fops.llseek = seq_lseek; ++ afinfo->seq_fops.release = seq_release_net; ++ ++ afinfo->seq_ops.start = udp_seq_start; ++ afinfo->seq_ops.next = udp_seq_next; ++ afinfo->seq_ops.stop = udp_seq_stop; ++ ++ p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, ++ &afinfo->seq_fops, afinfo); ++ if (!p) ++ rc = -ENOMEM; ++ return rc; ++} ++ ++void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) ++{ ++ proc_net_remove(net, afinfo->name); ++} ++ ++/* ------------------------------------------------------------------------ */ ++static void udp4_format_sock(struct sock *sp, struct seq_file *f, ++ int bucket, int *len) ++{ ++ struct inet_sock *inet = inet_sk(sp); ++ __be32 dest = inet->daddr; ++ __be32 src = inet->rcv_saddr; ++ __u16 destp = ntohs(inet->dport); ++ __u16 srcp = ntohs(inet->sport); ++ ++ seq_printf(f, "%4d: %08X:%04X %08X:%04X" ++ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", ++ bucket, src, srcp, dest, destp, sp->sk_state, ++ atomic_read(&sp->sk_wmem_alloc), ++ atomic_read(&sp->sk_rmem_alloc), ++ 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), ++ atomic_read(&sp->sk_refcnt), sp, ++ atomic_read(&sp->sk_drops), len); ++} ++ ++int udp4_seq_show(struct seq_file *seq, void *v) ++{ ++ if (v == SEQ_START_TOKEN) ++ seq_printf(seq, "%-127s\n", ++ " sl local_address rem_address st tx_queue " ++ "rx_queue tr tm->when retrnsmt uid timeout " ++ "inode ref pointer drops"); ++ else { ++ struct udp_iter_state *state = seq->private; ++ int len; ++ ++ udp4_format_sock(v, seq, state->bucket, &len); ++ seq_printf(seq, "%*s\n", 127 - len ,""); ++ } ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++static struct udp_seq_afinfo udp4_seq_afinfo = { ++ .name = "udp", ++ .family = AF_INET, ++ .udp_table = &udp_table, ++ .seq_fops = { ++ .owner = THIS_MODULE, ++ }, ++ .seq_ops = { ++ .show = udp4_seq_show, ++ }, ++}; ++ ++static int udp4_proc_init_net(struct net *net) ++{ ++ return udp_proc_register(net, &udp4_seq_afinfo); ++} ++ ++static void udp4_proc_exit_net(struct net *net) ++{ ++ udp_proc_unregister(net, &udp4_seq_afinfo); ++} ++ ++static struct pernet_operations udp4_net_ops = { ++ .init = udp4_proc_init_net, ++ .exit = udp4_proc_exit_net, ++}; ++ ++int __init udp4_proc_init(void) ++{ ++ return register_pernet_subsys(&udp4_net_ops); ++} ++ ++void udp4_proc_exit(void) ++{ ++ unregister_pernet_subsys(&udp4_net_ops); ++} ++#endif /* CONFIG_PROC_FS */ ++ ++void __init udp_table_init(struct udp_table *table) ++{ ++ int i; ++ ++ for (i = 0; i < UDP_HTABLE_SIZE; i++) { ++ INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); ++ spin_lock_init(&table->hash[i].lock); ++ } ++} ++ ++void __init udp_init(void) ++{ ++ unsigned long nr_pages, limit; ++ ++ udp_table_init(&udp_table); ++ /* Set the pressure threshold up by the same strategy of TCP. It is a ++ * fraction of global memory that is up to 1/2 at 256 MB, decreasing ++ * toward zero with the amount of memory, with a floor of 128 pages. ++ */ ++ nr_pages = totalram_pages - totalhigh_pages; ++ limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); ++ limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); ++ limit = max(limit, 128UL); ++ sysctl_udp_mem[0] = limit / 4 * 3; ++ sysctl_udp_mem[1] = limit; ++ sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2; ++ ++ sysctl_udp_rmem_min = SK_MEM_QUANTUM; ++ sysctl_udp_wmem_min = SK_MEM_QUANTUM; ++} ++ ++EXPORT_SYMBOL(udp_disconnect); ++EXPORT_SYMBOL(udp_ioctl); ++EXPORT_SYMBOL(udp_prot); ++EXPORT_SYMBOL(udp_sendmsg); ++EXPORT_SYMBOL(udp_lib_getsockopt); ++EXPORT_SYMBOL(udp_lib_setsockopt); ++EXPORT_SYMBOL(udp_poll); ++EXPORT_SYMBOL(udp_lib_get_port); ++ ++#ifdef CONFIG_PROC_FS ++EXPORT_SYMBOL(udp_proc_register); ++EXPORT_SYMBOL(udp_proc_unregister); ++#endif diff --git a/target/linux/patches/2.6.30.4/cygwin-compat.patch b/target/linux/patches/2.6.30.4/cygwin-compat.patch new file mode 100644 index 000000000..8d087dddf --- /dev/null +++ b/target/linux/patches/2.6.30.4/cygwin-compat.patch @@ -0,0 +1,66 @@ +diff -Nur linux-2.6.30.orig/scripts/mod/file2alias.c linux-2.6.30/scripts/mod/file2alias.c +--- linux-2.6.30.orig/scripts/mod/file2alias.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/scripts/mod/file2alias.c 2009-06-11 09:17:10.000000000 +0200 +@@ -29,7 +29,11 @@ + + #include + ++#ifdef __CYGWIN__ ++typedef __uint32_t __u32; ++#else + typedef uint32_t __u32; ++#endif + typedef uint16_t __u16; + typedef unsigned char __u8; + +diff -Nur linux-2.6.30.orig/scripts/mod/modpost.h linux-2.6.30/scripts/mod/modpost.h +--- linux-2.6.30.orig/scripts/mod/modpost.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/scripts/mod/modpost.h 2009-06-11 09:17:10.000000000 +0200 +@@ -9,6 +9,11 @@ + #include + #include + ++#ifdef __CYGWIN__ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++#endif ++ + #include "elfconfig.h" + + #if KERNEL_ELFCLASS == ELFCLASS32 +@@ -19,13 +24,17 @@ + #define Elf_Addr Elf32_Addr + #define Elf_Sword Elf64_Sword + #define Elf_Section Elf32_Half ++#ifndef __CYGWIN__ + #define ELF_ST_BIND ELF32_ST_BIND + #define ELF_ST_TYPE ELF32_ST_TYPE ++#endif + + #define Elf_Rel Elf32_Rel + #define Elf_Rela Elf32_Rela ++#ifndef __CYGWIN__ + #define ELF_R_SYM ELF32_R_SYM + #define ELF_R_TYPE ELF32_R_TYPE ++#endif + #else + + #define Elf_Ehdr Elf64_Ehdr +@@ -43,6 +52,17 @@ + #define ELF_R_TYPE ELF64_R_TYPE + #endif + ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++ + /* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ + typedef struct + { diff --git a/target/linux/patches/2.6.30.4/freebsd-compat.patch b/target/linux/patches/2.6.30.4/freebsd-compat.patch new file mode 100644 index 000000000..051fdc63e --- /dev/null +++ b/target/linux/patches/2.6.30.4/freebsd-compat.patch @@ -0,0 +1,11 @@ +diff -Nur linux-2.6.30.orig/arch/x86/boot/tools/build.c linux-2.6.30/arch/x86/boot/tools/build.c +--- linux-2.6.30.orig/arch/x86/boot/tools/build.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/arch/x86/boot/tools/build.c 2009-06-11 09:18:50.000000000 +0200 +@@ -29,7 +29,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/target/linux/patches/2.6.30.4/mips-delay-fix.patch b/target/linux/patches/2.6.30.4/mips-delay-fix.patch new file mode 100644 index 000000000..128ed54ec --- /dev/null +++ b/target/linux/patches/2.6.30.4/mips-delay-fix.patch @@ -0,0 +1,27 @@ +From: Atsushi Nemoto +Subject: [PATCH] fix __ndelay build error and add 'ull' suffix for 32-bit kernel + +Signed-off-by: Atsushi Nemoto +--- + arch/mips/lib/delay.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/mips/lib/delay.c ++++ b/arch/mips/lib/delay.c +@@ -43,7 +43,7 @@ void __udelay(unsigned long us) + { + unsigned int lpj = current_cpu_data.udelay_val; + +- __delay((us * 0x000010c7 * HZ * lpj) >> 32); ++ __delay((us * 0x000010c7ull * HZ * lpj) >> 32); + } + EXPORT_SYMBOL(__udelay); + +@@ -51,6 +51,6 @@ void __ndelay(unsigned long ns) + { + unsigned int lpj = current_cpu_data.udelay_val; + +- __delay((us * 0x00000005 * HZ * lpj) >> 32); ++ __delay((ns * 0x00000005ull * HZ * lpj) >> 32); + } + EXPORT_SYMBOL(__ndelay); diff --git a/target/linux/patches/2.6.30.4/mtd-root.patch b/target/linux/patches/2.6.30.4/mtd-root.patch new file mode 100644 index 000000000..3576848be --- /dev/null +++ b/target/linux/patches/2.6.30.4/mtd-root.patch @@ -0,0 +1,62 @@ +diff -Nur linux-2.6.29.1.orig/drivers/mtd/Kconfig linux-2.6.29.1/drivers/mtd/Kconfig +--- linux-2.6.29.1.orig/drivers/mtd/Kconfig 2009-04-02 22:55:27.000000000 +0200 ++++ linux-2.6.29.1/drivers/mtd/Kconfig 2009-05-02 19:24:14.444062164 +0200 +@@ -53,6 +53,11 @@ + should normally be compiled as kernel modules. The modules perform + various checks and verifications when loaded. + ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ depends on MTD_PARTITIONS ++ default y ++ + config MTD_REDBOOT_PARTS + tristate "RedBoot partition table parsing" + depends on MTD_PARTITIONS +diff -Nur linux-2.6.29.1.orig/drivers/mtd/mtdpart.c linux-2.6.29.1/drivers/mtd/mtdpart.c +--- linux-2.6.29.1.orig/drivers/mtd/mtdpart.c 2009-04-02 22:55:27.000000000 +0200 ++++ linux-2.6.29.1/drivers/mtd/mtdpart.c 2009-05-02 19:26:39.038093851 +0200 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -37,7 +38,7 @@ + * the pointer to that structure with this macro. + */ + #define PART(x) ((struct mtd_part *)(x)) +- ++#define IS_PART(mtd) (mtd->read == part_read) + + /* + * MTD methods which simply translate the effective address and pass through +@@ -502,14 +503,23 @@ + { + struct mtd_part *slave; + uint64_t cur_offset = 0; +- int i; ++ int i, j, ret; + + printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); + +- for (i = 0; i < nbparts; i++) { +- slave = add_one_partition(master, parts + i, i, cur_offset); ++ for (i = 0, j = 0; i < nbparts; i++) { ++ slave = add_one_partition(master, parts + i, j++, cur_offset); + if (!slave) + return -ENOMEM; ++ if (!strcmp(parts[i].name, "rootfs") && slave->registered) { ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (ROOT_DEV == 0) { ++ printk(KERN_NOTICE "mtd: partition \"rootfs\" " ++ "set to be root filesystem\n"); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index); ++ } ++#endif ++ } + cur_offset = slave->offset + slave->mtd.size; + } + diff --git a/target/linux/patches/2.6.30.4/natt.patch b/target/linux/patches/2.6.30.4/natt.patch new file mode 100644 index 000000000..83103a369 --- /dev/null +++ b/target/linux/patches/2.6.30.4/natt.patch @@ -0,0 +1,2668 @@ +diff -Nur linux-2.6.30.1.orig/include/net/xfrmudp.h linux-2.6.30.1/include/net/xfrmudp.h +--- linux-2.6.30.1.orig/include/net/xfrmudp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/include/net/xfrmudp.h 2009-07-24 22:00:56.771280384 +0200 +@@ -0,0 +1,10 @@ ++/* ++ * pointer to function for type that xfrm4_input wants, to permit ++ * decoupling of XFRM from udp.c ++ */ ++#define HAVE_XFRM4_UDP_REGISTER ++ ++typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type); ++extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func ++ , xfrm4_rcv_encap_t *oldfunc); ++extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func); +diff -Nur linux-2.6.30.1.orig/net/ipv4/Kconfig linux-2.6.30.1/net/ipv4/Kconfig +--- linux-2.6.30.1.orig/net/ipv4/Kconfig 2009-07-03 01:52:38.000000000 +0200 ++++ linux-2.6.30.1/net/ipv4/Kconfig 2009-07-24 22:00:56.751278392 +0200 +@@ -379,6 +379,12 @@ + tristate + default n + ++config IPSEC_NAT_TRAVERSAL ++ bool "IPSEC NAT-Traversal (KLIPS compatible)" ++ depends on INET ++ ---help--- ++ Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP. ++ + config INET_XFRM_MODE_TRANSPORT + tristate "IP: IPsec transport mode" + default y +diff -Nur linux-2.6.30.1.orig/net/ipv4/Kconfig.orig linux-2.6.30.1/net/ipv4/Kconfig.orig +--- linux-2.6.30.1.orig/net/ipv4/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/net/ipv4/Kconfig.orig 2009-07-03 01:52:38.000000000 +0200 +@@ -0,0 +1,638 @@ ++# ++# IP configuration ++# ++config IP_MULTICAST ++ bool "IP: multicasting" ++ help ++ This is code for addressing several networked computers at once, ++ enlarging your kernel by about 2 KB. You need multicasting if you ++ intend to participate in the MBONE, a high bandwidth network on top ++ of the Internet which carries audio and video broadcasts. More ++ information about the MBONE is on the WWW at ++ . Information about the multicast ++ capabilities of the various network cards is contained in ++ . For most people, it's ++ safe to say N. ++ ++config IP_ADVANCED_ROUTER ++ bool "IP: advanced router" ++ ---help--- ++ If you intend to run your Linux box mostly as a router, i.e. as a ++ computer that forwards and redistributes network packets, say Y; you ++ will then be presented with several options that allow more precise ++ control about the routing process. ++ ++ The answer to this question won't directly affect the kernel: ++ answering N will just cause the configurator to skip all the ++ questions about advanced routing. ++ ++ Note that your box can only act as a router if you enable IP ++ forwarding in your kernel; you can do that by saying Y to "/proc ++ file system support" and "Sysctl support" below and executing the ++ line ++ ++ echo "1" > /proc/sys/net/ipv4/ip_forward ++ ++ at boot time after the /proc file system has been mounted. ++ ++ If you turn on IP forwarding, you should consider the rp_filter, which ++ automatically rejects incoming packets if the routing table entry ++ for their source address doesn't match the network interface they're ++ arriving on. This has security advantages because it prevents the ++ so-called IP spoofing, however it can pose problems if you use ++ asymmetric routing (packets from you to a host take a different path ++ than packets from that host to you) or if you operate a non-routing ++ host which has several IP addresses on different interfaces. To turn ++ rp_filter on use: ++ ++ echo 1 > /proc/sys/net/ipv4/conf//rp_filter ++ and ++ echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter ++ ++ Note that some distributions enable it in startup scripts. ++ For details about rp_filter strict and loose mode read ++ . ++ ++ If unsure, say N here. ++ ++choice ++ prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)" ++ depends on IP_ADVANCED_ROUTER ++ default ASK_IP_FIB_HASH ++ ++config ASK_IP_FIB_HASH ++ bool "FIB_HASH" ++ ---help--- ++ Current FIB is very proven and good enough for most users. ++ ++config IP_FIB_TRIE ++ bool "FIB_TRIE" ++ ---help--- ++ Use new experimental LC-trie as FIB lookup algorithm. ++ This improves lookup performance if you have a large ++ number of routes. ++ ++ LC-trie is a longest matching prefix lookup algorithm which ++ performs better than FIB_HASH for large routing tables. ++ But, it consumes more memory and is more complex. ++ ++ LC-trie is described in: ++ ++ IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson ++ IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, ++ June 1999 ++ ++ An experimental study of compression methods for dynamic tries ++ Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. ++ http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ ++ ++endchoice ++ ++config IP_FIB_HASH ++ def_bool ASK_IP_FIB_HASH || !IP_ADVANCED_ROUTER ++ ++config IP_FIB_TRIE_STATS ++ bool "FIB TRIE statistics" ++ depends on IP_FIB_TRIE ++ ---help--- ++ Keep track of statistics on structure of FIB TRIE table. ++ Useful for testing and measuring TRIE performance. ++ ++config IP_MULTIPLE_TABLES ++ bool "IP: policy routing" ++ depends on IP_ADVANCED_ROUTER ++ select FIB_RULES ++ ---help--- ++ Normally, a router decides what to do with a received packet based ++ solely on the packet's final destination address. If you say Y here, ++ the Linux router will also be able to take the packet's source ++ address into account. Furthermore, the TOS (Type-Of-Service) field ++ of the packet can be used for routing decisions as well. ++ ++ If you are interested in this, please see the preliminary ++ documentation at ++ and . ++ You will need supporting software from ++ . ++ ++ If unsure, say N. ++ ++config IP_ROUTE_MULTIPATH ++ bool "IP: equal cost multipath" ++ depends on IP_ADVANCED_ROUTER ++ help ++ Normally, the routing tables specify a single action to be taken in ++ a deterministic manner for a given packet. If you say Y here ++ however, it becomes possible to attach several actions to a packet ++ pattern, in effect specifying several alternative paths to travel ++ for those packets. The router considers all these paths to be of ++ equal "cost" and chooses one of them in a non-deterministic fashion ++ if a matching packet arrives. ++ ++config IP_ROUTE_VERBOSE ++ bool "IP: verbose route monitoring" ++ depends on IP_ADVANCED_ROUTER ++ help ++ If you say Y here, which is recommended, then the kernel will print ++ verbose messages regarding the routing, for example warnings about ++ received packets which look strange and could be evidence of an ++ attack or a misconfigured system somewhere. The information is ++ handled by the klogd daemon which is responsible for kernel messages ++ ("man klogd"). ++ ++config IP_PNP ++ bool "IP: kernel level autoconfiguration" ++ help ++ This enables automatic configuration of IP addresses of devices and ++ of the routing table during kernel boot, based on either information ++ supplied on the kernel command line or by BOOTP or RARP protocols. ++ You need to say Y only for diskless machines requiring network ++ access to boot (in which case you want to say Y to "Root file system ++ on NFS" as well), because all other machines configure the network ++ in their startup scripts. ++ ++config IP_PNP_DHCP ++ bool "IP: DHCP support" ++ depends on IP_PNP ++ ---help--- ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the DHCP protocol (a ++ special protocol designed for doing this job), say Y here. In case ++ the boot ROM of your network card was designed for booting Linux and ++ does DHCP itself, providing all necessary information on the kernel ++ command line, you can say N here. ++ ++ If unsure, say Y. Note that if you want to use DHCP, a DHCP server ++ must be operating on your network. Read ++ for details. ++ ++config IP_PNP_BOOTP ++ bool "IP: BOOTP support" ++ depends on IP_PNP ++ ---help--- ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the BOOTP protocol (a ++ special protocol designed for doing this job), say Y here. In case ++ the boot ROM of your network card was designed for booting Linux and ++ does BOOTP itself, providing all necessary information on the kernel ++ command line, you can say N here. If unsure, say Y. Note that if you ++ want to use BOOTP, a BOOTP server must be operating on your network. ++ Read for details. ++ ++config IP_PNP_RARP ++ bool "IP: RARP support" ++ depends on IP_PNP ++ help ++ If you want your Linux box to mount its whole root file system (the ++ one containing the directory /) from some other computer over the ++ net via NFS and you want the IP address of your computer to be ++ discovered automatically at boot time using the RARP protocol (an ++ older protocol which is being obsoleted by BOOTP and DHCP), say Y ++ here. Note that if you want to use RARP, a RARP server must be ++ operating on your network. Read ++ for details. ++ ++# not yet ready.. ++# bool ' IP: ARP support' CONFIG_IP_PNP_ARP ++config NET_IPIP ++ tristate "IP: tunneling" ++ select INET_TUNNEL ++ ---help--- ++ Tunneling means encapsulating data of one protocol type within ++ another protocol and sending it over a channel that understands the ++ encapsulating protocol. This particular tunneling driver implements ++ encapsulation of IP within IP, which sounds kind of pointless, but ++ can be useful if you want to make your (or some other) machine ++ appear on a different network than it physically is, or to use ++ mobile-IP facilities (allowing laptops to seamlessly move between ++ networks without changing their IP addresses). ++ ++ Saying Y to this option will produce two modules ( = code which can ++ be inserted in and removed from the running kernel whenever you ++ want). Most people won't need this and can say N. ++ ++config NET_IPGRE ++ tristate "IP: GRE tunnels over IP" ++ help ++ Tunneling means encapsulating data of one protocol type within ++ another protocol and sending it over a channel that understands the ++ encapsulating protocol. This particular tunneling driver implements ++ GRE (Generic Routing Encapsulation) and at this time allows ++ encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure. ++ This driver is useful if the other endpoint is a Cisco router: Cisco ++ likes GRE much better than the other Linux tunneling driver ("IP ++ tunneling" above). In addition, GRE allows multicast redistribution ++ through the tunnel. ++ ++config NET_IPGRE_BROADCAST ++ bool "IP: broadcast GRE over IP" ++ depends on IP_MULTICAST && NET_IPGRE ++ help ++ One application of GRE/IP is to construct a broadcast WAN (Wide Area ++ Network), which looks like a normal Ethernet LAN (Local Area ++ Network), but can be distributed all over the Internet. If you want ++ to do that, say Y here and to "IP multicast routing" below. ++ ++config IP_MROUTE ++ bool "IP: multicast routing" ++ depends on IP_MULTICAST ++ help ++ This is used if you want your machine to act as a router for IP ++ packets that have several destination addresses. It is needed on the ++ MBONE, a high bandwidth network on top of the Internet which carries ++ audio and video broadcasts. In order to do that, you would most ++ likely run the program mrouted. Information about the multicast ++ capabilities of the various network cards is contained in ++ . If you haven't heard ++ about it, you don't need it. ++ ++config IP_PIMSM_V1 ++ bool "IP: PIM-SM version 1 support" ++ depends on IP_MROUTE ++ help ++ Kernel side support for Sparse Mode PIM (Protocol Independent ++ Multicast) version 1. This multicast routing protocol is used widely ++ because Cisco supports it. You need special software to use it ++ (pimd-v1). Please see for more ++ information about PIM. ++ ++ Say Y if you want to use PIM-SM v1. Note that you can say N here if ++ you just want to use Dense Mode PIM. ++ ++config IP_PIMSM_V2 ++ bool "IP: PIM-SM version 2 support" ++ depends on IP_MROUTE ++ help ++ Kernel side support for Sparse Mode PIM version 2. In order to use ++ this, you need an experimental routing daemon supporting it (pimd or ++ gated-5). This routing protocol is not used widely, so say N unless ++ you want to play with it. ++ ++config ARPD ++ bool "IP: ARP daemon support (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ ---help--- ++ Normally, the kernel maintains an internal cache which maps IP ++ addresses to hardware addresses on the local network, so that ++ Ethernet/Token Ring/ etc. frames are sent to the proper address on ++ the physical networking layer. For small networks having a few ++ hundred directly connected hosts or less, keeping this address ++ resolution (ARP) cache inside the kernel works well. However, ++ maintaining an internal ARP cache does not work well for very large ++ switched networks, and will use a lot of kernel memory if TCP/IP ++ connections are made to many machines on the network. ++ ++ If you say Y here, the kernel's internal ARP cache will never grow ++ to more than 256 entries (the oldest entries are expired in a LIFO ++ manner) and communication will be attempted with the user space ARP ++ daemon arpd. Arpd then answers the address resolution request either ++ from its own cache or by asking the net. ++ ++ This code is experimental and also obsolete. If you want to use it, ++ you need to find a version of the daemon arpd on the net somewhere, ++ and you should also say Y to "Kernel/User network link driver", ++ below. If unsure, say N. ++ ++config SYN_COOKIES ++ bool "IP: TCP syncookie support (disabled per default)" ++ ---help--- ++ Normal TCP/IP networking is open to an attack known as "SYN ++ flooding". This denial-of-service attack prevents legitimate remote ++ users from being able to connect to your computer during an ongoing ++ attack and requires very little work from the attacker, who can ++ operate from anywhere on the Internet. ++ ++ SYN cookies provide protection against this type of attack. If you ++ say Y here, the TCP/IP stack will use a cryptographic challenge ++ protocol known as "SYN cookies" to enable legitimate users to ++ continue to connect, even when your machine is under attack. There ++ is no need for the legitimate users to change their TCP/IP software; ++ SYN cookies work transparently to them. For technical information ++ about SYN cookies, check out . ++ ++ If you are SYN flooded, the source address reported by the kernel is ++ likely to have been forged by the attacker; it is only reported as ++ an aid in tracing the packets to their actual source and should not ++ be taken as absolute truth. ++ ++ SYN cookies may prevent correct error reporting on clients when the ++ server is really overloaded. If this happens frequently better turn ++ them off. ++ ++ If you say Y here, note that SYN cookies aren't enabled by default; ++ you can enable them by saying Y to "/proc file system support" and ++ "Sysctl support" below and executing the command ++ ++ echo 1 >/proc/sys/net/ipv4/tcp_syncookies ++ ++ at boot time after the /proc file system has been mounted. ++ ++ If unsure, say N. ++ ++config INET_AH ++ tristate "IP: AH transformation" ++ select XFRM ++ select CRYPTO ++ select CRYPTO_HMAC ++ select CRYPTO_MD5 ++ select CRYPTO_SHA1 ++ ---help--- ++ Support for IPsec AH. ++ ++ If unsure, say Y. ++ ++config INET_ESP ++ tristate "IP: ESP transformation" ++ select XFRM ++ select CRYPTO ++ select CRYPTO_AUTHENC ++ select CRYPTO_HMAC ++ select CRYPTO_MD5 ++ select CRYPTO_CBC ++ select CRYPTO_SHA1 ++ select CRYPTO_DES ++ ---help--- ++ Support for IPsec ESP. ++ ++ If unsure, say Y. ++ ++config INET_IPCOMP ++ tristate "IP: IPComp transformation" ++ select INET_XFRM_TUNNEL ++ select XFRM_IPCOMP ++ ---help--- ++ Support for IP Payload Compression Protocol (IPComp) (RFC3173), ++ typically needed for IPsec. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_TUNNEL ++ tristate ++ select INET_TUNNEL ++ default n ++ ++config INET_TUNNEL ++ tristate ++ default n ++ ++config INET_XFRM_MODE_TRANSPORT ++ tristate "IP: IPsec transport mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec transport mode. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_MODE_TUNNEL ++ tristate "IP: IPsec tunnel mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec tunnel mode. ++ ++ If unsure, say Y. ++ ++config INET_XFRM_MODE_BEET ++ tristate "IP: IPsec BEET mode" ++ default y ++ select XFRM ++ ---help--- ++ Support for IPsec BEET mode. ++ ++ If unsure, say Y. ++ ++config INET_LRO ++ bool "Large Receive Offload (ipv4/tcp)" ++ default y ++ ---help--- ++ Support for Large Receive Offload (ipv4/tcp). ++ ++ If unsure, say Y. ++ ++config INET_DIAG ++ tristate "INET: socket monitoring interface" ++ default y ++ ---help--- ++ Support for INET (TCP, DCCP, etc) socket monitoring interface used by ++ native Linux tools such as ss. ss is included in iproute2, currently ++ downloadable at . ++ ++ If unsure, say Y. ++ ++config INET_TCP_DIAG ++ depends on INET_DIAG ++ def_tristate INET_DIAG ++ ++menuconfig TCP_CONG_ADVANCED ++ bool "TCP: advanced congestion control" ++ ---help--- ++ Support for selection of various TCP congestion control ++ modules. ++ ++ Nearly all users can safely say no here, and a safe default ++ selection will be made (CUBIC with new Reno as a fallback). ++ ++ If unsure, say N. ++ ++if TCP_CONG_ADVANCED ++ ++config TCP_CONG_BIC ++ tristate "Binary Increase Congestion (BIC) control" ++ default m ++ ---help--- ++ BIC-TCP is a sender-side only change that ensures a linear RTT ++ fairness under large windows while offering both scalability and ++ bounded TCP-friendliness. The protocol combines two schemes ++ called additive increase and binary search increase. When the ++ congestion window is large, additive increase with a large ++ increment ensures linear RTT fairness as well as good ++ scalability. Under small congestion windows, binary search ++ increase provides TCP friendliness. ++ See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ ++ ++config TCP_CONG_CUBIC ++ tristate "CUBIC TCP" ++ default y ++ ---help--- ++ This is version 2.0 of BIC-TCP which uses a cubic growth function ++ among other techniques. ++ See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf ++ ++config TCP_CONG_WESTWOOD ++ tristate "TCP Westwood+" ++ default m ++ ---help--- ++ TCP Westwood+ is a sender-side only modification of the TCP Reno ++ protocol stack that optimizes the performance of TCP congestion ++ control. It is based on end-to-end bandwidth estimation to set ++ congestion window and slow start threshold after a congestion ++ episode. Using this estimation, TCP Westwood+ adaptively sets a ++ slow start threshold and a congestion window which takes into ++ account the bandwidth used at the time congestion is experienced. ++ TCP Westwood+ significantly increases fairness wrt TCP Reno in ++ wired networks and throughput over wireless links. ++ ++config TCP_CONG_HTCP ++ tristate "H-TCP" ++ default m ++ ---help--- ++ H-TCP is a send-side only modifications of the TCP Reno ++ protocol stack that optimizes the performance of TCP ++ congestion control for high speed network links. It uses a ++ modeswitch to change the alpha and beta parameters of TCP Reno ++ based on network conditions and in a way so as to be fair with ++ other Reno and H-TCP flows. ++ ++config TCP_CONG_HSTCP ++ tristate "High Speed TCP" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ Sally Floyd's High Speed TCP (RFC 3649) congestion control. ++ A modification to TCP's congestion control mechanism for use ++ with large congestion windows. A table indicates how much to ++ increase the congestion window by when an ACK is received. ++ For more detail see http://www.icir.org/floyd/hstcp.html ++ ++config TCP_CONG_HYBLA ++ tristate "TCP-Hybla congestion control algorithm" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP-Hybla is a sender-side only change that eliminates penalization of ++ long-RTT, large-bandwidth connections, like when satellite legs are ++ involved, especially when sharing a common bottleneck with normal ++ terrestrial connections. ++ ++config TCP_CONG_VEGAS ++ tristate "TCP Vegas" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Vegas is a sender-side only change to TCP that anticipates ++ the onset of congestion by estimating the bandwidth. TCP Vegas ++ adjusts the sending rate by modifying the congestion ++ window. TCP Vegas should provide less packet loss, but it is ++ not as aggressive as TCP Reno. ++ ++config TCP_CONG_SCALABLE ++ tristate "Scalable TCP" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ Scalable TCP is a sender-side only change to TCP which uses a ++ MIMD congestion control algorithm which has some nice scaling ++ properties, though is known to have fairness issues. ++ See http://www.deneholme.net/tom/scalable/ ++ ++config TCP_CONG_LP ++ tristate "TCP Low Priority" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Low Priority (TCP-LP), a distributed algorithm whose goal is ++ to utilize only the excess network bandwidth as compared to the ++ ``fair share`` of bandwidth as targeted by TCP. ++ See http://www-ece.rice.edu/networks/TCP-LP/ ++ ++config TCP_CONG_VENO ++ tristate "TCP Veno" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP Veno is a sender-side only enhancement of TCP to obtain better ++ throughput over wireless networks. TCP Veno makes use of state ++ distinguishing to circumvent the difficult judgment of the packet loss ++ type. TCP Veno cuts down less congestion window in response to random ++ loss packets. ++ See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf ++ ++config TCP_CONG_YEAH ++ tristate "YeAH TCP" ++ depends on EXPERIMENTAL ++ select TCP_CONG_VEGAS ++ default n ++ ---help--- ++ YeAH-TCP is a sender-side high-speed enabled TCP congestion control ++ algorithm, which uses a mixed loss/delay approach to compute the ++ congestion window. It's design goals target high efficiency, ++ internal, RTT and Reno fairness, resilience to link loss while ++ keeping network elements load as low as possible. ++ ++ For further details look here: ++ http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf ++ ++config TCP_CONG_ILLINOIS ++ tristate "TCP Illinois" ++ depends on EXPERIMENTAL ++ default n ++ ---help--- ++ TCP-Illinois is a sender-side modification of TCP Reno for ++ high speed long delay links. It uses round-trip-time to ++ adjust the alpha and beta parameters to achieve a higher average ++ throughput and maintain fairness. ++ ++ For further details see: ++ http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html ++ ++choice ++ prompt "Default TCP congestion control" ++ default DEFAULT_CUBIC ++ help ++ Select the TCP congestion control that will be used by default ++ for all connections. ++ ++ config DEFAULT_BIC ++ bool "Bic" if TCP_CONG_BIC=y ++ ++ config DEFAULT_CUBIC ++ bool "Cubic" if TCP_CONG_CUBIC=y ++ ++ config DEFAULT_HTCP ++ bool "Htcp" if TCP_CONG_HTCP=y ++ ++ config DEFAULT_VEGAS ++ bool "Vegas" if TCP_CONG_VEGAS=y ++ ++ config DEFAULT_WESTWOOD ++ bool "Westwood" if TCP_CONG_WESTWOOD=y ++ ++ config DEFAULT_RENO ++ bool "Reno" ++ ++endchoice ++ ++endif ++ ++config TCP_CONG_CUBIC ++ tristate ++ depends on !TCP_CONG_ADVANCED ++ default y ++ ++config DEFAULT_TCP_CONG ++ string ++ default "bic" if DEFAULT_BIC ++ default "cubic" if DEFAULT_CUBIC ++ default "htcp" if DEFAULT_HTCP ++ default "vegas" if DEFAULT_VEGAS ++ default "westwood" if DEFAULT_WESTWOOD ++ default "reno" if DEFAULT_RENO ++ default "cubic" ++ ++config TCP_MD5SIG ++ bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ select CRYPTO ++ select CRYPTO_MD5 ++ ---help--- ++ RFC2385 specifies a method of giving MD5 protection to TCP sessions. ++ Its main (only?) use is to protect BGP sessions between core routers ++ on the Internet. ++ ++ If unsure, say N. ++ +diff -Nur linux-2.6.30.1.orig/net/ipv4/udp.c linux-2.6.30.1/net/ipv4/udp.c +--- linux-2.6.30.1.orig/net/ipv4/udp.c 2009-07-03 01:52:38.000000000 +0200 ++++ linux-2.6.30.1/net/ipv4/udp.c 2009-07-24 22:00:56.755270521 +0200 +@@ -104,6 +104,7 @@ + #include + #include + #include ++#include + #include "udp_impl.h" + + struct udp_table udp_table; +@@ -1035,6 +1036,128 @@ + return -1; + } + ++#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++ ++static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL; ++ ++/* ++ * de-encapsulate and pass to the registered xfrm4_rcv_encap_func function. ++ * Most of this code stolen from net/ipv4/xfrm4_input.c ++ * which is attributed to YOSHIFUJI Hideaki @USAGI, and ++ * Derek Atkins ++ */ ++ ++static int xfrm4_udp_encap_rcv_wrapper(struct sock *sk, struct sk_buff *skb) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ struct udphdr *uh; ++ struct iphdr *iph; ++ int iphlen, len; ++ int ret; ++ ++ __u8 *udpdata; ++ __be32 *udpdata32; ++ __u16 encap_type = up->encap_type; ++ ++ /* if this is not encapsulated socket, then just return now */ ++ if (!encap_type && !xfrm4_rcv_encap_func) ++ return 1; ++ ++ /* If this is a paged skb, make sure we pull up ++ * whatever data we need to look at. */ ++ len = skb->len - sizeof(struct udphdr); ++ if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) ++ return 1; ++ ++ /* Now we can get the pointers */ ++ uh = udp_hdr(skb); ++ udpdata = (__u8 *)uh + sizeof(struct udphdr); ++ udpdata32 = (__be32 *)udpdata; ++ ++ switch (encap_type) { ++ default: ++ case UDP_ENCAP_ESPINUDP: ++ /* Check if this is a keepalive packet. If so, eat it. */ ++ if (len == 1 && udpdata[0] == 0xff) { ++ goto drop; ++ } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) { ++ /* ESP Packet without Non-ESP header */ ++ len = sizeof(struct udphdr); ++ } else ++ /* Must be an IKE packet.. pass it through */ ++ return 1; ++ break; ++ case UDP_ENCAP_ESPINUDP_NON_IKE: ++ /* Check if this is a keepalive packet. If so, eat it. */ ++ if (len == 1 && udpdata[0] == 0xff) { ++ goto drop; ++ } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && ++ udpdata32[0] == 0 && udpdata32[1] == 0) { ++ ++ /* ESP Packet with Non-IKE marker */ ++ len = sizeof(struct udphdr) + 2 * sizeof(u32); ++ } else ++ /* Must be an IKE packet.. pass it through */ ++ return 1; ++ break; ++ } ++ ++ /* At this point we are sure that this is an ESPinUDP packet, ++ * so we need to remove 'len' bytes from the packet (the UDP ++ * header and optional ESP marker bytes) and then modify the ++ * protocol to ESP, and then call into the transform receiver. ++ */ ++ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) ++ goto drop; ++ ++ /* Now we can update and verify the packet length... */ ++ iph = ip_hdr(skb); ++ iphlen = iph->ihl << 2; ++ iph->tot_len = htons(ntohs(iph->tot_len) - len); ++ if (skb->len < iphlen + len) { ++ /* packet is too small!?! */ ++ goto drop; ++ } ++ ++ /* pull the data buffer up to the ESP header and set the ++ * transport header to point to ESP. Keep UDP on the stack ++ * for later. ++ */ ++ __skb_pull(skb, len); ++ skb_reset_transport_header(skb); ++ ++ /* modify the protocol (it's ESP!) */ ++ iph->protocol = IPPROTO_ESP; ++ ++ /* process ESP */ ++ ret = (*xfrm4_rcv_encap_func)(skb, encap_type); ++ return ret; ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func, ++ xfrm4_rcv_encap_t *oldfunc) ++{ ++ if (oldfunc != NULL) ++ *oldfunc = xfrm4_rcv_encap_func; ++ xfrm4_rcv_encap_func = func; ++ return 0; ++} ++ ++int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func) ++{ ++ if (xfrm4_rcv_encap_func != func) ++ return -1; ++ ++ xfrm4_rcv_encap_func = NULL; ++ return 0; ++} ++ ++#endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */ ++ + /* returns: + * -1: error + * 0: success +@@ -1377,6 +1500,11 @@ + case 0: + case UDP_ENCAP_ESPINUDP: + case UDP_ENCAP_ESPINUDP_NON_IKE: ++#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++ if (xfrm4_rcv_encap_func) ++ up->encap_rcv = xfrm4_udp_encap_rcv_wrapper; ++ else ++#endif + up->encap_rcv = xfrm4_udp_encap_rcv; + /* FALLTHROUGH */ + case UDP_ENCAP_L2TPINUDP: +@@ -1828,3 +1956,9 @@ + EXPORT_SYMBOL(udp_proc_register); + EXPORT_SYMBOL(udp_proc_unregister); + #endif ++ ++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) ++EXPORT_SYMBOL(udp4_register_esp_rcvencap); ++EXPORT_SYMBOL(udp4_unregister_esp_rcvencap); ++#endif ++ +diff -Nur linux-2.6.30.1.orig/net/ipv4/udp.c.orig linux-2.6.30.1/net/ipv4/udp.c.orig +--- linux-2.6.30.1.orig/net/ipv4/udp.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30.1/net/ipv4/udp.c.orig 2009-07-03 01:52:38.000000000 +0200 +@@ -0,0 +1,1830 @@ ++/* ++ * INET An implementation of the TCP/IP protocol suite for the LINUX ++ * operating system. INET is implemented using the BSD Socket ++ * interface as the means of communication with the user level. ++ * ++ * The User Datagram Protocol (UDP). ++ * ++ * Authors: Ross Biro ++ * Fred N. van Kempen, ++ * Arnt Gulbrandsen, ++ * Alan Cox, ++ * Hirokazu Takahashi, ++ * ++ * Fixes: ++ * Alan Cox : verify_area() calls ++ * Alan Cox : stopped close while in use off icmp ++ * messages. Not a fix but a botch that ++ * for udp at least is 'valid'. ++ * Alan Cox : Fixed icmp handling properly ++ * Alan Cox : Correct error for oversized datagrams ++ * Alan Cox : Tidied select() semantics. ++ * Alan Cox : udp_err() fixed properly, also now ++ * select and read wake correctly on errors ++ * Alan Cox : udp_send verify_area moved to avoid mem leak ++ * Alan Cox : UDP can count its memory ++ * Alan Cox : send to an unknown connection causes ++ * an ECONNREFUSED off the icmp, but ++ * does NOT close. ++ * Alan Cox : Switched to new sk_buff handlers. No more backlog! ++ * Alan Cox : Using generic datagram code. Even smaller and the PEEK ++ * bug no longer crashes it. ++ * Fred Van Kempen : Net2e support for sk->broadcast. ++ * Alan Cox : Uses skb_free_datagram ++ * Alan Cox : Added get/set sockopt support. ++ * Alan Cox : Broadcasting without option set returns EACCES. ++ * Alan Cox : No wakeup calls. Instead we now use the callbacks. ++ * Alan Cox : Use ip_tos and ip_ttl ++ * Alan Cox : SNMP Mibs ++ * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. ++ * Matt Dillon : UDP length checks. ++ * Alan Cox : Smarter af_inet used properly. ++ * Alan Cox : Use new kernel side addressing. ++ * Alan Cox : Incorrect return on truncated datagram receive. ++ * Arnt Gulbrandsen : New udp_send and stuff ++ * Alan Cox : Cache last socket ++ * Alan Cox : Route cache ++ * Jon Peatfield : Minor efficiency fix to sendto(). ++ * Mike Shaver : RFC1122 checks. ++ * Alan Cox : Nonblocking error fix. ++ * Willy Konynenberg : Transparent proxying support. ++ * Mike McLagan : Routing by source ++ * David S. Miller : New socket lookup architecture. ++ * Last socket cache retained as it ++ * does have a high hit rate. ++ * Olaf Kirch : Don't linearise iovec on sendmsg. ++ * Andi Kleen : Some cleanups, cache destination entry ++ * for connect. ++ * Vitaly E. Lavrov : Transparent proxy revived after year coma. ++ * Melvin Smith : Check msg_name not msg_namelen in sendto(), ++ * return ENOTCONN for unconnected sockets (POSIX) ++ * Janos Farkas : don't deliver multi/broadcasts to a different ++ * bound-to-device socket ++ * Hirokazu Takahashi : HW checksumming for outgoing UDP ++ * datagrams. ++ * Hirokazu Takahashi : sendfile() on UDP works now. ++ * Arnaldo C. Melo : convert /proc/net/udp to seq_file ++ * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which ++ * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind ++ * a single port at the same time. ++ * Derek Atkins : Add Encapulation Support ++ * James Chapman : Add L2TP encapsulation type. ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "udp_impl.h" ++ ++struct udp_table udp_table; ++EXPORT_SYMBOL(udp_table); ++ ++int sysctl_udp_mem[3] __read_mostly; ++int sysctl_udp_rmem_min __read_mostly; ++int sysctl_udp_wmem_min __read_mostly; ++ ++EXPORT_SYMBOL(sysctl_udp_mem); ++EXPORT_SYMBOL(sysctl_udp_rmem_min); ++EXPORT_SYMBOL(sysctl_udp_wmem_min); ++ ++atomic_t udp_memory_allocated; ++EXPORT_SYMBOL(udp_memory_allocated); ++ ++#define PORTS_PER_CHAIN (65536 / UDP_HTABLE_SIZE) ++ ++static int udp_lib_lport_inuse(struct net *net, __u16 num, ++ const struct udp_hslot *hslot, ++ unsigned long *bitmap, ++ struct sock *sk, ++ int (*saddr_comp)(const struct sock *sk1, ++ const struct sock *sk2)) ++{ ++ struct sock *sk2; ++ struct hlist_nulls_node *node; ++ ++ sk_nulls_for_each(sk2, node, &hslot->head) ++ if (net_eq(sock_net(sk2), net) && ++ sk2 != sk && ++ (bitmap || sk2->sk_hash == num) && ++ (!sk2->sk_reuse || !sk->sk_reuse) && ++ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ++ || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && ++ (*saddr_comp)(sk, sk2)) { ++ if (bitmap) ++ __set_bit(sk2->sk_hash / UDP_HTABLE_SIZE, ++ bitmap); ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 ++ * ++ * @sk: socket struct in question ++ * @snum: port number to look up ++ * @saddr_comp: AF-dependent comparison of bound local IP addresses ++ */ ++int udp_lib_get_port(struct sock *sk, unsigned short snum, ++ int (*saddr_comp)(const struct sock *sk1, ++ const struct sock *sk2 ) ) ++{ ++ struct udp_hslot *hslot; ++ struct udp_table *udptable = sk->sk_prot->h.udp_table; ++ int error = 1; ++ struct net *net = sock_net(sk); ++ ++ if (!snum) { ++ int low, high, remaining; ++ unsigned rand; ++ unsigned short first, last; ++ DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN); ++ ++ inet_get_local_port_range(&low, &high); ++ remaining = (high - low) + 1; ++ ++ rand = net_random(); ++ first = (((u64)rand * remaining) >> 32) + low; ++ /* ++ * force rand to be an odd multiple of UDP_HTABLE_SIZE ++ */ ++ rand = (rand | 1) * UDP_HTABLE_SIZE; ++ for (last = first + UDP_HTABLE_SIZE; first != last; first++) { ++ hslot = &udptable->hash[udp_hashfn(net, first)]; ++ bitmap_zero(bitmap, PORTS_PER_CHAIN); ++ spin_lock_bh(&hslot->lock); ++ udp_lib_lport_inuse(net, snum, hslot, bitmap, sk, ++ saddr_comp); ++ ++ snum = first; ++ /* ++ * Iterate on all possible values of snum for this hash. ++ * Using steps of an odd multiple of UDP_HTABLE_SIZE ++ * give us randomization and full range coverage. ++ */ ++ do { ++ if (low <= snum && snum <= high && ++ !test_bit(snum / UDP_HTABLE_SIZE, bitmap)) ++ goto found; ++ snum += rand; ++ } while (snum != first); ++ spin_unlock_bh(&hslot->lock); ++ } ++ goto fail; ++ } else { ++ hslot = &udptable->hash[udp_hashfn(net, snum)]; ++ spin_lock_bh(&hslot->lock); ++ if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp)) ++ goto fail_unlock; ++ } ++found: ++ inet_sk(sk)->num = snum; ++ sk->sk_hash = snum; ++ if (sk_unhashed(sk)) { ++ sk_nulls_add_node_rcu(sk, &hslot->head); ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); ++ } ++ error = 0; ++fail_unlock: ++ spin_unlock_bh(&hslot->lock); ++fail: ++ return error; ++} ++ ++static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) ++{ ++ struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); ++ ++ return ( !ipv6_only_sock(sk2) && ++ (!inet1->rcv_saddr || !inet2->rcv_saddr || ++ inet1->rcv_saddr == inet2->rcv_saddr )); ++} ++ ++int udp_v4_get_port(struct sock *sk, unsigned short snum) ++{ ++ return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); ++} ++ ++static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, ++ unsigned short hnum, ++ __be16 sport, __be32 daddr, __be16 dport, int dif) ++{ ++ int score = -1; ++ ++ if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && ++ !ipv6_only_sock(sk)) { ++ struct inet_sock *inet = inet_sk(sk); ++ ++ score = (sk->sk_family == PF_INET ? 1 : 0); ++ if (inet->rcv_saddr) { ++ if (inet->rcv_saddr != daddr) ++ return -1; ++ score += 2; ++ } ++ if (inet->daddr) { ++ if (inet->daddr != saddr) ++ return -1; ++ score += 2; ++ } ++ if (inet->dport) { ++ if (inet->dport != sport) ++ return -1; ++ score += 2; ++ } ++ if (sk->sk_bound_dev_if) { ++ if (sk->sk_bound_dev_if != dif) ++ return -1; ++ score += 2; ++ } ++ } ++ return score; ++} ++ ++/* UDP is nearly always wildcards out the wazoo, it makes no sense to try ++ * harder than this. -DaveM ++ */ ++static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, ++ __be16 sport, __be32 daddr, __be16 dport, ++ int dif, struct udp_table *udptable) ++{ ++ struct sock *sk, *result; ++ struct hlist_nulls_node *node; ++ unsigned short hnum = ntohs(dport); ++ unsigned int hash = udp_hashfn(net, hnum); ++ struct udp_hslot *hslot = &udptable->hash[hash]; ++ int score, badness; ++ ++ rcu_read_lock(); ++begin: ++ result = NULL; ++ badness = -1; ++ sk_nulls_for_each_rcu(sk, node, &hslot->head) { ++ score = compute_score(sk, net, saddr, hnum, sport, ++ daddr, dport, dif); ++ if (score > badness) { ++ result = sk; ++ badness = score; ++ } ++ } ++ /* ++ * if the nulls value we got at the end of this lookup is ++ * not the expected one, we must restart lookup. ++ * We probably met an item that was moved to another chain. ++ */ ++ if (get_nulls_value(node) != hash) ++ goto begin; ++ ++ if (result) { ++ if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) ++ result = NULL; ++ else if (unlikely(compute_score(result, net, saddr, hnum, sport, ++ daddr, dport, dif) < badness)) { ++ sock_put(result); ++ goto begin; ++ } ++ } ++ rcu_read_unlock(); ++ return result; ++} ++ ++static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, ++ __be16 sport, __be16 dport, ++ struct udp_table *udptable) ++{ ++ struct sock *sk; ++ const struct iphdr *iph = ip_hdr(skb); ++ ++ if (unlikely(sk = skb_steal_sock(skb))) ++ return sk; ++ else ++ return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport, ++ iph->daddr, dport, inet_iif(skb), ++ udptable); ++} ++ ++struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, ++ __be32 daddr, __be16 dport, int dif) ++{ ++ return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); ++} ++EXPORT_SYMBOL_GPL(udp4_lib_lookup); ++ ++static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, ++ __be16 loc_port, __be32 loc_addr, ++ __be16 rmt_port, __be32 rmt_addr, ++ int dif) ++{ ++ struct hlist_nulls_node *node; ++ struct sock *s = sk; ++ unsigned short hnum = ntohs(loc_port); ++ ++ sk_nulls_for_each_from(s, node) { ++ struct inet_sock *inet = inet_sk(s); ++ ++ if (!net_eq(sock_net(s), net) || ++ s->sk_hash != hnum || ++ (inet->daddr && inet->daddr != rmt_addr) || ++ (inet->dport != rmt_port && inet->dport) || ++ (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || ++ ipv6_only_sock(s) || ++ (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) ++ continue; ++ if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) ++ continue; ++ goto found; ++ } ++ s = NULL; ++found: ++ return s; ++} ++ ++/* ++ * This routine is called by the ICMP module when it gets some ++ * sort of error condition. If err < 0 then the socket should ++ * be closed and the error returned to the user. If err > 0 ++ * it's just the icmp type << 8 | icmp code. ++ * Header points to the ip header of the error packet. We move ++ * on past this. Then (as it used to claim before adjustment) ++ * header points to the first 8 bytes of the udp header. We need ++ * to find the appropriate port. ++ */ ++ ++void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) ++{ ++ struct inet_sock *inet; ++ struct iphdr *iph = (struct iphdr*)skb->data; ++ struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); ++ const int type = icmp_hdr(skb)->type; ++ const int code = icmp_hdr(skb)->code; ++ struct sock *sk; ++ int harderr; ++ int err; ++ struct net *net = dev_net(skb->dev); ++ ++ sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, ++ iph->saddr, uh->source, skb->dev->ifindex, udptable); ++ if (sk == NULL) { ++ ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); ++ return; /* No socket for error */ ++ } ++ ++ err = 0; ++ harderr = 0; ++ inet = inet_sk(sk); ++ ++ switch (type) { ++ default: ++ case ICMP_TIME_EXCEEDED: ++ err = EHOSTUNREACH; ++ break; ++ case ICMP_SOURCE_QUENCH: ++ goto out; ++ case ICMP_PARAMETERPROB: ++ err = EPROTO; ++ harderr = 1; ++ break; ++ case ICMP_DEST_UNREACH: ++ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ ++ if (inet->pmtudisc != IP_PMTUDISC_DONT) { ++ err = EMSGSIZE; ++ harderr = 1; ++ break; ++ } ++ goto out; ++ } ++ err = EHOSTUNREACH; ++ if (code <= NR_ICMP_UNREACH) { ++ harderr = icmp_err_convert[code].fatal; ++ err = icmp_err_convert[code].errno; ++ } ++ break; ++ } ++ ++ /* ++ * RFC1122: OK. Passes ICMP errors back to application, as per ++ * 4.1.3.3. ++ */ ++ if (!inet->recverr) { ++ if (!harderr || sk->sk_state != TCP_ESTABLISHED) ++ goto out; ++ } else { ++ ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); ++ } ++ sk->sk_err = err; ++ sk->sk_error_report(sk); ++out: ++ sock_put(sk); ++} ++ ++void udp_err(struct sk_buff *skb, u32 info) ++{ ++ __udp4_lib_err(skb, info, &udp_table); ++} ++ ++/* ++ * Throw away all pending data and cancel the corking. Socket is locked. ++ */ ++void udp_flush_pending_frames(struct sock *sk) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ ++ if (up->pending) { ++ up->len = 0; ++ up->pending = 0; ++ ip_flush_pending_frames(sk); ++ } ++} ++EXPORT_SYMBOL(udp_flush_pending_frames); ++ ++/** ++ * udp4_hwcsum_outgoing - handle outgoing HW checksumming ++ * @sk: socket we are sending on ++ * @skb: sk_buff containing the filled-in UDP header ++ * (checksum field must be zeroed out) ++ */ ++static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ++ __be32 src, __be32 dst, int len ) ++{ ++ unsigned int offset; ++ struct udphdr *uh = udp_hdr(skb); ++ __wsum csum = 0; ++ ++ if (skb_queue_len(&sk->sk_write_queue) == 1) { ++ /* ++ * Only one fragment on the socket. ++ */ ++ skb->csum_start = skb_transport_header(skb) - skb->head; ++ skb->csum_offset = offsetof(struct udphdr, check); ++ uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); ++ } else { ++ /* ++ * HW-checksum won't work as there are two or more ++ * fragments on the socket so that all csums of sk_buffs ++ * should be together ++ */ ++ offset = skb_transport_offset(skb); ++ skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ skb_queue_walk(&sk->sk_write_queue, skb) { ++ csum = csum_add(csum, skb->csum); ++ } ++ ++ uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); ++ if (uh->check == 0) ++ uh->check = CSUM_MANGLED_0; ++ } ++} ++ ++/* ++ * Push out all pending data as one UDP datagram. Socket is locked. ++ */ ++static int udp_push_pending_frames(struct sock *sk) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ struct inet_sock *inet = inet_sk(sk); ++ struct flowi *fl = &inet->cork.fl; ++ struct sk_buff *skb; ++ struct udphdr *uh; ++ int err = 0; ++ int is_udplite = IS_UDPLITE(sk); ++ __wsum csum = 0; ++ ++ /* Grab the skbuff where UDP header space exists. */ ++ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) ++ goto out; ++ ++ /* ++ * Create a UDP header ++ */ ++ uh = udp_hdr(skb); ++ uh->source = fl->fl_ip_sport; ++ uh->dest = fl->fl_ip_dport; ++ uh->len = htons(up->len); ++ uh->check = 0; ++ ++ if (is_udplite) /* UDP-Lite */ ++ csum = udplite_csum_outgoing(sk, skb); ++ ++ else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ goto send; ++ ++ } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ ++ ++ udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); ++ goto send; ++ ++ } else /* `normal' UDP */ ++ csum = udp_csum_outgoing(sk, skb); ++ ++ /* add protocol-dependent pseudo-header */ ++ uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, ++ sk->sk_protocol, csum ); ++ if (uh->check == 0) ++ uh->check = CSUM_MANGLED_0; ++ ++send: ++ err = ip_push_pending_frames(sk); ++out: ++ up->len = 0; ++ up->pending = 0; ++ if (!err) ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_OUTDATAGRAMS, is_udplite); ++ return err; ++} ++ ++int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ++ size_t len) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct udp_sock *up = udp_sk(sk); ++ int ulen = len; ++ struct ipcm_cookie ipc; ++ struct rtable *rt = NULL; ++ int free = 0; ++ int connected = 0; ++ __be32 daddr, faddr, saddr; ++ __be16 dport; ++ u8 tos; ++ int err, is_udplite = IS_UDPLITE(sk); ++ int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; ++ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); ++ ++ if (len > 0xFFFF) ++ return -EMSGSIZE; ++ ++ /* ++ * Check the flags. ++ */ ++ ++ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ ++ return -EOPNOTSUPP; ++ ++ ipc.opt = NULL; ++ ipc.shtx.flags = 0; ++ ++ if (up->pending) { ++ /* ++ * There are pending frames. ++ * The socket lock must be held while it's corked. ++ */ ++ lock_sock(sk); ++ if (likely(up->pending)) { ++ if (unlikely(up->pending != AF_INET)) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ goto do_append_data; ++ } ++ release_sock(sk); ++ } ++ ulen += sizeof(struct udphdr); ++ ++ /* ++ * Get and verify the address. ++ */ ++ if (msg->msg_name) { ++ struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; ++ if (msg->msg_namelen < sizeof(*usin)) ++ return -EINVAL; ++ if (usin->sin_family != AF_INET) { ++ if (usin->sin_family != AF_UNSPEC) ++ return -EAFNOSUPPORT; ++ } ++ ++ daddr = usin->sin_addr.s_addr; ++ dport = usin->sin_port; ++ if (dport == 0) ++ return -EINVAL; ++ } else { ++ if (sk->sk_state != TCP_ESTABLISHED) ++ return -EDESTADDRREQ; ++ daddr = inet->daddr; ++ dport = inet->dport; ++ /* Open fast path for connected socket. ++ Route will not be used, if at least one option is set. ++ */ ++ connected = 1; ++ } ++ ipc.addr = inet->saddr; ++ ++ ipc.oif = sk->sk_bound_dev_if; ++ err = sock_tx_timestamp(msg, sk, &ipc.shtx); ++ if (err) ++ return err; ++ if (msg->msg_controllen) { ++ err = ip_cmsg_send(sock_net(sk), msg, &ipc); ++ if (err) ++ return err; ++ if (ipc.opt) ++ free = 1; ++ connected = 0; ++ } ++ if (!ipc.opt) ++ ipc.opt = inet->opt; ++ ++ saddr = ipc.addr; ++ ipc.addr = faddr = daddr; ++ ++ if (ipc.opt && ipc.opt->srr) { ++ if (!daddr) ++ return -EINVAL; ++ faddr = ipc.opt->faddr; ++ connected = 0; ++ } ++ tos = RT_TOS(inet->tos); ++ if (sock_flag(sk, SOCK_LOCALROUTE) || ++ (msg->msg_flags & MSG_DONTROUTE) || ++ (ipc.opt && ipc.opt->is_strictroute)) { ++ tos |= RTO_ONLINK; ++ connected = 0; ++ } ++ ++ if (ipv4_is_multicast(daddr)) { ++ if (!ipc.oif) ++ ipc.oif = inet->mc_index; ++ if (!saddr) ++ saddr = inet->mc_addr; ++ connected = 0; ++ } ++ ++ if (connected) ++ rt = (struct rtable*)sk_dst_check(sk, 0); ++ ++ if (rt == NULL) { ++ struct flowi fl = { .oif = ipc.oif, ++ .nl_u = { .ip4_u = ++ { .daddr = faddr, ++ .saddr = saddr, ++ .tos = tos } }, ++ .proto = sk->sk_protocol, ++ .flags = inet_sk_flowi_flags(sk), ++ .uli_u = { .ports = ++ { .sport = inet->sport, ++ .dport = dport } } }; ++ struct net *net = sock_net(sk); ++ ++ security_sk_classify_flow(sk, &fl); ++ err = ip_route_output_flow(net, &rt, &fl, sk, 1); ++ if (err) { ++ if (err == -ENETUNREACH) ++ IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); ++ goto out; ++ } ++ ++ err = -EACCES; ++ if ((rt->rt_flags & RTCF_BROADCAST) && ++ !sock_flag(sk, SOCK_BROADCAST)) ++ goto out; ++ if (connected) ++ sk_dst_set(sk, dst_clone(&rt->u.dst)); ++ } ++ ++ if (msg->msg_flags&MSG_CONFIRM) ++ goto do_confirm; ++back_from_confirm: ++ ++ saddr = rt->rt_src; ++ if (!ipc.addr) ++ daddr = ipc.addr = rt->rt_dst; ++ ++ lock_sock(sk); ++ if (unlikely(up->pending)) { ++ /* The socket is already corked while preparing it. */ ++ /* ... which is an evident application bug. --ANK */ ++ release_sock(sk); ++ ++ LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); ++ err = -EINVAL; ++ goto out; ++ } ++ /* ++ * Now cork the socket to pend data. ++ */ ++ inet->cork.fl.fl4_dst = daddr; ++ inet->cork.fl.fl_ip_dport = dport; ++ inet->cork.fl.fl4_src = saddr; ++ inet->cork.fl.fl_ip_sport = inet->sport; ++ up->pending = AF_INET; ++ ++do_append_data: ++ up->len += ulen; ++ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; ++ err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, ++ sizeof(struct udphdr), &ipc, &rt, ++ corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); ++ if (err) ++ udp_flush_pending_frames(sk); ++ else if (!corkreq) ++ err = udp_push_pending_frames(sk); ++ else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) ++ up->pending = 0; ++ release_sock(sk); ++ ++out: ++ ip_rt_put(rt); ++ if (free) ++ kfree(ipc.opt); ++ if (!err) ++ return len; ++ /* ++ * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting ++ * ENOBUFS might not be good (it's not tunable per se), but otherwise ++ * we don't have a good statistic (IpOutDiscards but it can be too many ++ * things). We could add another new stat but at least for now that ++ * seems like overkill. ++ */ ++ if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_SNDBUFERRORS, is_udplite); ++ } ++ return err; ++ ++do_confirm: ++ dst_confirm(&rt->u.dst); ++ if (!(msg->msg_flags&MSG_PROBE) || len) ++ goto back_from_confirm; ++ err = 0; ++ goto out; ++} ++ ++int udp_sendpage(struct sock *sk, struct page *page, int offset, ++ size_t size, int flags) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int ret; ++ ++ if (!up->pending) { ++ struct msghdr msg = { .msg_flags = flags|MSG_MORE }; ++ ++ /* Call udp_sendmsg to specify destination address which ++ * sendpage interface can't pass. ++ * This will succeed only when the socket is connected. ++ */ ++ ret = udp_sendmsg(NULL, sk, &msg, 0); ++ if (ret < 0) ++ return ret; ++ } ++ ++ lock_sock(sk); ++ ++ if (unlikely(!up->pending)) { ++ release_sock(sk); ++ ++ LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); ++ return -EINVAL; ++ } ++ ++ ret = ip_append_page(sk, page, offset, size, flags); ++ if (ret == -EOPNOTSUPP) { ++ release_sock(sk); ++ return sock_no_sendpage(sk->sk_socket, page, offset, ++ size, flags); ++ } ++ if (ret < 0) { ++ udp_flush_pending_frames(sk); ++ goto out; ++ } ++ ++ up->len += size; ++ if (!(up->corkflag || (flags&MSG_MORE))) ++ ret = udp_push_pending_frames(sk); ++ if (!ret) ++ ret = size; ++out: ++ release_sock(sk); ++ return ret; ++} ++ ++/* ++ * IOCTL requests applicable to the UDP protocol ++ */ ++ ++int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case SIOCOUTQ: ++ { ++ int amount = atomic_read(&sk->sk_wmem_alloc); ++ return put_user(amount, (int __user *)arg); ++ } ++ ++ case SIOCINQ: ++ { ++ struct sk_buff *skb; ++ unsigned long amount; ++ ++ amount = 0; ++ spin_lock_bh(&sk->sk_receive_queue.lock); ++ skb = skb_peek(&sk->sk_receive_queue); ++ if (skb != NULL) { ++ /* ++ * We will only return the amount ++ * of this packet since that is all ++ * that will be read. ++ */ ++ amount = skb->len - sizeof(struct udphdr); ++ } ++ spin_unlock_bh(&sk->sk_receive_queue.lock); ++ return put_user(amount, (int __user *)arg); ++ } ++ ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This should be easy, if there is something there we ++ * return it, otherwise we block. ++ */ ++ ++int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ++ size_t len, int noblock, int flags, int *addr_len) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; ++ struct sk_buff *skb; ++ unsigned int ulen, copied; ++ int peeked; ++ int err; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ /* ++ * Check any passed addresses ++ */ ++ if (addr_len) ++ *addr_len=sizeof(*sin); ++ ++ if (flags & MSG_ERRQUEUE) ++ return ip_recv_error(sk, msg, len); ++ ++try_again: ++ skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), ++ &peeked, &err); ++ if (!skb) ++ goto out; ++ ++ ulen = skb->len - sizeof(struct udphdr); ++ copied = len; ++ if (copied > ulen) ++ copied = ulen; ++ else if (copied < ulen) ++ msg->msg_flags |= MSG_TRUNC; ++ ++ /* ++ * If checksum is needed at all, try to do it while copying the ++ * data. If the data is truncated, or if we only want a partial ++ * coverage checksum (UDP-Lite), do it before the copy. ++ */ ++ ++ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { ++ if (udp_lib_checksum_complete(skb)) ++ goto csum_copy_err; ++ } ++ ++ if (skb_csum_unnecessary(skb)) ++ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), ++ msg->msg_iov, copied ); ++ else { ++ err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); ++ ++ if (err == -EINVAL) ++ goto csum_copy_err; ++ } ++ ++ if (err) ++ goto out_free; ++ ++ if (!peeked) ++ UDP_INC_STATS_USER(sock_net(sk), ++ UDP_MIB_INDATAGRAMS, is_udplite); ++ ++ sock_recv_timestamp(msg, sk, skb); ++ ++ /* Copy the address. */ ++ if (sin) ++ { ++ sin->sin_family = AF_INET; ++ sin->sin_port = udp_hdr(skb)->source; ++ sin->sin_addr.s_addr = ip_hdr(skb)->saddr; ++ memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); ++ } ++ if (inet->cmsg_flags) ++ ip_cmsg_recv(msg, skb); ++ ++ err = copied; ++ if (flags & MSG_TRUNC) ++ err = ulen; ++ ++out_free: ++ lock_sock(sk); ++ skb_free_datagram(sk, skb); ++ release_sock(sk); ++out: ++ return err; ++ ++csum_copy_err: ++ lock_sock(sk); ++ if (!skb_kill_datagram(sk, skb, flags)) ++ UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ release_sock(sk); ++ ++ if (noblock) ++ return -EAGAIN; ++ goto try_again; ++} ++ ++ ++int udp_disconnect(struct sock *sk, int flags) ++{ ++ struct inet_sock *inet = inet_sk(sk); ++ /* ++ * 1003.1g - break association. ++ */ ++ ++ sk->sk_state = TCP_CLOSE; ++ inet->daddr = 0; ++ inet->dport = 0; ++ sk->sk_bound_dev_if = 0; ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); ++ ++ if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { ++ sk->sk_prot->unhash(sk); ++ inet->sport = 0; ++ } ++ sk_dst_reset(sk); ++ return 0; ++} ++ ++void udp_lib_unhash(struct sock *sk) ++{ ++ if (sk_hashed(sk)) { ++ struct udp_table *udptable = sk->sk_prot->h.udp_table; ++ unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash); ++ struct udp_hslot *hslot = &udptable->hash[hash]; ++ ++ spin_lock_bh(&hslot->lock); ++ if (sk_nulls_del_node_init_rcu(sk)) { ++ inet_sk(sk)->num = 0; ++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); ++ } ++ spin_unlock_bh(&hslot->lock); ++ } ++} ++EXPORT_SYMBOL(udp_lib_unhash); ++ ++static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) ++{ ++ int is_udplite = IS_UDPLITE(sk); ++ int rc; ++ ++ if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { ++ /* Note that an ENOMEM error is charged twice */ ++ if (rc == -ENOMEM) { ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, ++ is_udplite); ++ atomic_inc(&sk->sk_drops); ++ } ++ goto drop; ++ } ++ ++ return 0; ++ ++drop: ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ kfree_skb(skb); ++ return -1; ++} ++ ++/* returns: ++ * -1: error ++ * 0: success ++ * >0: "udp encap" protocol resubmission ++ * ++ * Note that in the success and error cases, the skb is assumed to ++ * have either been requeued or freed. ++ */ ++int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int rc; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ /* ++ * Charge it to the socket, dropping if the queue is full. ++ */ ++ if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) ++ goto drop; ++ nf_reset(skb); ++ ++ if (up->encap_type) { ++ /* ++ * This is an encapsulation socket so pass the skb to ++ * the socket's udp_encap_rcv() hook. Otherwise, just ++ * fall through and pass this up the UDP socket. ++ * up->encap_rcv() returns the following value: ++ * =0 if skb was successfully passed to the encap ++ * handler or was discarded by it. ++ * >0 if skb should be passed on to UDP. ++ * <0 if skb should be resubmitted as proto -N ++ */ ++ ++ /* if we're overly short, let UDP handle it */ ++ if (skb->len > sizeof(struct udphdr) && ++ up->encap_rcv != NULL) { ++ int ret; ++ ++ ret = (*up->encap_rcv)(sk, skb); ++ if (ret <= 0) { ++ UDP_INC_STATS_BH(sock_net(sk), ++ UDP_MIB_INDATAGRAMS, ++ is_udplite); ++ return -ret; ++ } ++ } ++ ++ /* FALLTHROUGH -- it's a UDP Packet */ ++ } ++ ++ /* ++ * UDP-Lite specific tests, ignored on UDP sockets ++ */ ++ if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { ++ ++ /* ++ * MIB statistics other than incrementing the error count are ++ * disabled for the following two types of errors: these depend ++ * on the application settings, not on the functioning of the ++ * protocol stack as such. ++ * ++ * RFC 3828 here recommends (sec 3.3): "There should also be a ++ * way ... to ... at least let the receiving application block ++ * delivery of packets with coverage values less than a value ++ * provided by the application." ++ */ ++ if (up->pcrlen == 0) { /* full coverage was set */ ++ LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " ++ "%d while full coverage %d requested\n", ++ UDP_SKB_CB(skb)->cscov, skb->len); ++ goto drop; ++ } ++ /* The next case involves violating the min. coverage requested ++ * by the receiver. This is subtle: if receiver wants x and x is ++ * greater than the buffersize/MTU then receiver will complain ++ * that it wants x while sender emits packets of smaller size y. ++ * Therefore the above ...()->partial_cov statement is essential. ++ */ ++ if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { ++ LIMIT_NETDEBUG(KERN_WARNING ++ "UDPLITE: coverage %d too small, need min %d\n", ++ UDP_SKB_CB(skb)->cscov, up->pcrlen); ++ goto drop; ++ } ++ } ++ ++ if (sk->sk_filter) { ++ if (udp_lib_checksum_complete(skb)) ++ goto drop; ++ } ++ ++ rc = 0; ++ ++ bh_lock_sock(sk); ++ if (!sock_owned_by_user(sk)) ++ rc = __udp_queue_rcv_skb(sk, skb); ++ else ++ sk_add_backlog(sk, skb); ++ bh_unlock_sock(sk); ++ ++ return rc; ++ ++drop: ++ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); ++ kfree_skb(skb); ++ return -1; ++} ++ ++/* ++ * Multicasts and broadcasts go to each listener. ++ * ++ * Note: called only from the BH handler context, ++ * so we don't need to lock the hashes. ++ */ ++static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, ++ struct udphdr *uh, ++ __be32 saddr, __be32 daddr, ++ struct udp_table *udptable) ++{ ++ struct sock *sk; ++ struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; ++ int dif; ++ ++ spin_lock(&hslot->lock); ++ sk = sk_nulls_head(&hslot->head); ++ dif = skb->dev->ifindex; ++ sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); ++ if (sk) { ++ struct sock *sknext = NULL; ++ ++ do { ++ struct sk_buff *skb1 = skb; ++ ++ sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, ++ daddr, uh->source, saddr, ++ dif); ++ if (sknext) ++ skb1 = skb_clone(skb, GFP_ATOMIC); ++ ++ if (skb1) { ++ int ret = udp_queue_rcv_skb(sk, skb1); ++ if (ret > 0) ++ /* we should probably re-process instead ++ * of dropping packets here. */ ++ kfree_skb(skb1); ++ } ++ sk = sknext; ++ } while (sknext); ++ } else ++ consume_skb(skb); ++ spin_unlock(&hslot->lock); ++ return 0; ++} ++ ++/* Initialize UDP checksum. If exited with zero value (success), ++ * CHECKSUM_UNNECESSARY means, that no more checks are required. ++ * Otherwise, csum completion requires chacksumming packet body, ++ * including udp header and folding it to skb->csum. ++ */ ++static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, ++ int proto) ++{ ++ const struct iphdr *iph; ++ int err; ++ ++ UDP_SKB_CB(skb)->partial_cov = 0; ++ UDP_SKB_CB(skb)->cscov = skb->len; ++ ++ if (proto == IPPROTO_UDPLITE) { ++ err = udplite_checksum_init(skb, uh); ++ if (err) ++ return err; ++ } ++ ++ iph = ip_hdr(skb); ++ if (uh->check == 0) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else if (skb->ip_summed == CHECKSUM_COMPLETE) { ++ if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, ++ proto, skb->csum)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } ++ if (!skb_csum_unnecessary(skb)) ++ skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, ++ skb->len, proto, 0); ++ /* Probably, we should checksum udp header (it should be in cache ++ * in any case) and data in tiny packets (< rx copybreak). ++ */ ++ ++ return 0; ++} ++ ++/* ++ * All we need to do is get the socket, and then do a checksum. ++ */ ++ ++int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, ++ int proto) ++{ ++ struct sock *sk; ++ struct udphdr *uh; ++ unsigned short ulen; ++ struct rtable *rt = (struct rtable*)skb->dst; ++ __be32 saddr, daddr; ++ struct net *net = dev_net(skb->dev); ++ ++ /* ++ * Validate the packet. ++ */ ++ if (!pskb_may_pull(skb, sizeof(struct udphdr))) ++ goto drop; /* No space for header. */ ++ ++ uh = udp_hdr(skb); ++ ulen = ntohs(uh->len); ++ if (ulen > skb->len) ++ goto short_packet; ++ ++ if (proto == IPPROTO_UDP) { ++ /* UDP validates ulen. */ ++ if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) ++ goto short_packet; ++ uh = udp_hdr(skb); ++ } ++ ++ if (udp4_csum_init(skb, uh, proto)) ++ goto csum_error; ++ ++ saddr = ip_hdr(skb)->saddr; ++ daddr = ip_hdr(skb)->daddr; ++ ++ if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) ++ return __udp4_lib_mcast_deliver(net, skb, uh, ++ saddr, daddr, udptable); ++ ++ sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); ++ ++ if (sk != NULL) { ++ int ret = udp_queue_rcv_skb(sk, skb); ++ sock_put(sk); ++ ++ /* a return value > 0 means to resubmit the input, but ++ * it wants the return to be -protocol, or 0 ++ */ ++ if (ret > 0) ++ return -ret; ++ return 0; ++ } ++ ++ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) ++ goto drop; ++ nf_reset(skb); ++ ++ /* No socket. Drop packet silently, if checksum is wrong */ ++ if (udp_lib_checksum_complete(skb)) ++ goto csum_error; ++ ++ UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); ++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); ++ ++ /* ++ * Hmm. We got an UDP packet to a port to which we ++ * don't wanna listen. Ignore it. ++ */ ++ kfree_skb(skb); ++ return 0; ++ ++short_packet: ++ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", ++ proto == IPPROTO_UDPLITE ? "-Lite" : "", ++ &saddr, ++ ntohs(uh->source), ++ ulen, ++ skb->len, ++ &daddr, ++ ntohs(uh->dest)); ++ goto drop; ++ ++csum_error: ++ /* ++ * RFC1122: OK. Discards the bad packet silently (as far as ++ * the network is concerned, anyway) as per 4.1.3.4 (MUST). ++ */ ++ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", ++ proto == IPPROTO_UDPLITE ? "-Lite" : "", ++ &saddr, ++ ntohs(uh->source), ++ &daddr, ++ ntohs(uh->dest), ++ ulen); ++drop: ++ UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); ++ kfree_skb(skb); ++ return 0; ++} ++ ++int udp_rcv(struct sk_buff *skb) ++{ ++ return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP); ++} ++ ++void udp_destroy_sock(struct sock *sk) ++{ ++ lock_sock(sk); ++ udp_flush_pending_frames(sk); ++ release_sock(sk); ++} ++ ++/* ++ * Socket option code for UDP ++ */ ++int udp_lib_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen, ++ int (*push_pending_frames)(struct sock *)) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int val; ++ int err = 0; ++ int is_udplite = IS_UDPLITE(sk); ++ ++ if (optlencorkflag = 1; ++ } else { ++ up->corkflag = 0; ++ lock_sock(sk); ++ (*push_pending_frames)(sk); ++ release_sock(sk); ++ } ++ break; ++ ++ case UDP_ENCAP: ++ switch (val) { ++ case 0: ++ case UDP_ENCAP_ESPINUDP: ++ case UDP_ENCAP_ESPINUDP_NON_IKE: ++ up->encap_rcv = xfrm4_udp_encap_rcv; ++ /* FALLTHROUGH */ ++ case UDP_ENCAP_L2TPINUDP: ++ up->encap_type = val; ++ break; ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ break; ++ ++ /* ++ * UDP-Lite's partial checksum coverage (RFC 3828). ++ */ ++ /* The sender sets actual checksum coverage length via this option. ++ * The case coverage > packet length is handled by send module. */ ++ case UDPLITE_SEND_CSCOV: ++ if (!is_udplite) /* Disable the option on UDP sockets */ ++ return -ENOPROTOOPT; ++ if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ ++ val = 8; ++ else if (val > USHORT_MAX) ++ val = USHORT_MAX; ++ up->pcslen = val; ++ up->pcflag |= UDPLITE_SEND_CC; ++ break; ++ ++ /* The receiver specifies a minimum checksum coverage value. To make ++ * sense, this should be set to at least 8 (as done below). If zero is ++ * used, this again means full checksum coverage. */ ++ case UDPLITE_RECV_CSCOV: ++ if (!is_udplite) /* Disable the option on UDP sockets */ ++ return -ENOPROTOOPT; ++ if (val != 0 && val < 8) /* Avoid silly minimal values. */ ++ val = 8; ++ else if (val > USHORT_MAX) ++ val = USHORT_MAX; ++ up->pcrlen = val; ++ up->pcflag |= UDPLITE_RECV_CC; ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ return err; ++} ++ ++int udp_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_setsockopt(sk, level, optname, optval, optlen, ++ udp_push_pending_frames); ++ return ip_setsockopt(sk, level, optname, optval, optlen); ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_udp_setsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_setsockopt(sk, level, optname, optval, optlen, ++ udp_push_pending_frames); ++ return compat_ip_setsockopt(sk, level, optname, optval, optlen); ++} ++#endif ++ ++int udp_lib_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ struct udp_sock *up = udp_sk(sk); ++ int val, len; ++ ++ if (get_user(len,optlen)) ++ return -EFAULT; ++ ++ len = min_t(unsigned int, len, sizeof(int)); ++ ++ if (len < 0) ++ return -EINVAL; ++ ++ switch (optname) { ++ case UDP_CORK: ++ val = up->corkflag; ++ break; ++ ++ case UDP_ENCAP: ++ val = up->encap_type; ++ break; ++ ++ /* The following two cannot be changed on UDP sockets, the return is ++ * always 0 (which corresponds to the full checksum coverage of UDP). */ ++ case UDPLITE_SEND_CSCOV: ++ val = up->pcslen; ++ break; ++ ++ case UDPLITE_RECV_CSCOV: ++ val = up->pcrlen; ++ break; ++ ++ default: ++ return -ENOPROTOOPT; ++ } ++ ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ if (copy_to_user(optval, &val,len)) ++ return -EFAULT; ++ return 0; ++} ++ ++int udp_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_getsockopt(sk, level, optname, optval, optlen); ++ return ip_getsockopt(sk, level, optname, optval, optlen); ++} ++ ++#ifdef CONFIG_COMPAT ++int compat_udp_getsockopt(struct sock *sk, int level, int optname, ++ char __user *optval, int __user *optlen) ++{ ++ if (level == SOL_UDP || level == SOL_UDPLITE) ++ return udp_lib_getsockopt(sk, level, optname, optval, optlen); ++ return compat_ip_getsockopt(sk, level, optname, optval, optlen); ++} ++#endif ++/** ++ * udp_poll - wait for a UDP event. ++ * @file - file struct ++ * @sock - socket ++ * @wait - poll table ++ * ++ * This is same as datagram poll, except for the special case of ++ * blocking sockets. If application is using a blocking fd ++ * and a packet with checksum error is in the queue; ++ * then it could get return from select indicating data available ++ * but then block when reading it. Add special case code ++ * to work around these arguably broken applications. ++ */ ++unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) ++{ ++ unsigned int mask = datagram_poll(file, sock, wait); ++ struct sock *sk = sock->sk; ++ int is_lite = IS_UDPLITE(sk); ++ ++ /* Check for false positives due to checksum errors */ ++ if ( (mask & POLLRDNORM) && ++ !(file->f_flags & O_NONBLOCK) && ++ !(sk->sk_shutdown & RCV_SHUTDOWN)){ ++ struct sk_buff_head *rcvq = &sk->sk_receive_queue; ++ struct sk_buff *skb; ++ ++ spin_lock_bh(&rcvq->lock); ++ while ((skb = skb_peek(rcvq)) != NULL && ++ udp_lib_checksum_complete(skb)) { ++ UDP_INC_STATS_BH(sock_net(sk), ++ UDP_MIB_INERRORS, is_lite); ++ __skb_unlink(skb, rcvq); ++ kfree_skb(skb); ++ } ++ spin_unlock_bh(&rcvq->lock); ++ ++ /* nothing to see, move along */ ++ if (skb == NULL) ++ mask &= ~(POLLIN | POLLRDNORM); ++ } ++ ++ return mask; ++ ++} ++ ++struct proto udp_prot = { ++ .name = "UDP", ++ .owner = THIS_MODULE, ++ .close = udp_lib_close, ++ .connect = ip4_datagram_connect, ++ .disconnect = udp_disconnect, ++ .ioctl = udp_ioctl, ++ .destroy = udp_destroy_sock, ++ .setsockopt = udp_setsockopt, ++ .getsockopt = udp_getsockopt, ++ .sendmsg = udp_sendmsg, ++ .recvmsg = udp_recvmsg, ++ .sendpage = udp_sendpage, ++ .backlog_rcv = __udp_queue_rcv_skb, ++ .hash = udp_lib_hash, ++ .unhash = udp_lib_unhash, ++ .get_port = udp_v4_get_port, ++ .memory_allocated = &udp_memory_allocated, ++ .sysctl_mem = sysctl_udp_mem, ++ .sysctl_wmem = &sysctl_udp_wmem_min, ++ .sysctl_rmem = &sysctl_udp_rmem_min, ++ .obj_size = sizeof(struct udp_sock), ++ .slab_flags = SLAB_DESTROY_BY_RCU, ++ .h.udp_table = &udp_table, ++#ifdef CONFIG_COMPAT ++ .compat_setsockopt = compat_udp_setsockopt, ++ .compat_getsockopt = compat_udp_getsockopt, ++#endif ++}; ++ ++/* ------------------------------------------------------------------------ */ ++#ifdef CONFIG_PROC_FS ++ ++static struct sock *udp_get_first(struct seq_file *seq, int start) ++{ ++ struct sock *sk; ++ struct udp_iter_state *state = seq->private; ++ struct net *net = seq_file_net(seq); ++ ++ for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { ++ struct hlist_nulls_node *node; ++ struct udp_hslot *hslot = &state->udp_table->hash[state->bucket]; ++ spin_lock_bh(&hslot->lock); ++ sk_nulls_for_each(sk, node, &hslot->head) { ++ if (!net_eq(sock_net(sk), net)) ++ continue; ++ if (sk->sk_family == state->family) ++ goto found; ++ } ++ spin_unlock_bh(&hslot->lock); ++ } ++ sk = NULL; ++found: ++ return sk; ++} ++ ++static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) ++{ ++ struct udp_iter_state *state = seq->private; ++ struct net *net = seq_file_net(seq); ++ ++ do { ++ sk = sk_nulls_next(sk); ++ } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); ++ ++ if (!sk) { ++ if (state->bucket < UDP_HTABLE_SIZE) ++ spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); ++ return udp_get_first(seq, state->bucket + 1); ++ } ++ return sk; ++} ++ ++static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) ++{ ++ struct sock *sk = udp_get_first(seq, 0); ++ ++ if (sk) ++ while (pos && (sk = udp_get_next(seq, sk)) != NULL) ++ --pos; ++ return pos ? NULL : sk; ++} ++ ++static void *udp_seq_start(struct seq_file *seq, loff_t *pos) ++{ ++ struct udp_iter_state *state = seq->private; ++ state->bucket = UDP_HTABLE_SIZE; ++ ++ return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN; ++} ++ ++static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++{ ++ struct sock *sk; ++ ++ if (v == SEQ_START_TOKEN) ++ sk = udp_get_idx(seq, 0); ++ else ++ sk = udp_get_next(seq, v); ++ ++ ++*pos; ++ return sk; ++} ++ ++static void udp_seq_stop(struct seq_file *seq, void *v) ++{ ++ struct udp_iter_state *state = seq->private; ++ ++ if (state->bucket < UDP_HTABLE_SIZE) ++ spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); ++} ++ ++static int udp_seq_open(struct inode *inode, struct file *file) ++{ ++ struct udp_seq_afinfo *afinfo = PDE(inode)->data; ++ struct udp_iter_state *s; ++ int err; ++ ++ err = seq_open_net(inode, file, &afinfo->seq_ops, ++ sizeof(struct udp_iter_state)); ++ if (err < 0) ++ return err; ++ ++ s = ((struct seq_file *)file->private_data)->private; ++ s->family = afinfo->family; ++ s->udp_table = afinfo->udp_table; ++ return err; ++} ++ ++/* ------------------------------------------------------------------------ */ ++int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) ++{ ++ struct proc_dir_entry *p; ++ int rc = 0; ++ ++ afinfo->seq_fops.open = udp_seq_open; ++ afinfo->seq_fops.read = seq_read; ++ afinfo->seq_fops.llseek = seq_lseek; ++ afinfo->seq_fops.release = seq_release_net; ++ ++ afinfo->seq_ops.start = udp_seq_start; ++ afinfo->seq_ops.next = udp_seq_next; ++ afinfo->seq_ops.stop = udp_seq_stop; ++ ++ p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, ++ &afinfo->seq_fops, afinfo); ++ if (!p) ++ rc = -ENOMEM; ++ return rc; ++} ++ ++void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) ++{ ++ proc_net_remove(net, afinfo->name); ++} ++ ++/* ------------------------------------------------------------------------ */ ++static void udp4_format_sock(struct sock *sp, struct seq_file *f, ++ int bucket, int *len) ++{ ++ struct inet_sock *inet = inet_sk(sp); ++ __be32 dest = inet->daddr; ++ __be32 src = inet->rcv_saddr; ++ __u16 destp = ntohs(inet->dport); ++ __u16 srcp = ntohs(inet->sport); ++ ++ seq_printf(f, "%4d: %08X:%04X %08X:%04X" ++ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", ++ bucket, src, srcp, dest, destp, sp->sk_state, ++ atomic_read(&sp->sk_wmem_alloc), ++ atomic_read(&sp->sk_rmem_alloc), ++ 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), ++ atomic_read(&sp->sk_refcnt), sp, ++ atomic_read(&sp->sk_drops), len); ++} ++ ++int udp4_seq_show(struct seq_file *seq, void *v) ++{ ++ if (v == SEQ_START_TOKEN) ++ seq_printf(seq, "%-127s\n", ++ " sl local_address rem_address st tx_queue " ++ "rx_queue tr tm->when retrnsmt uid timeout " ++ "inode ref pointer drops"); ++ else { ++ struct udp_iter_state *state = seq->private; ++ int len; ++ ++ udp4_format_sock(v, seq, state->bucket, &len); ++ seq_printf(seq, "%*s\n", 127 - len ,""); ++ } ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------ */ ++static struct udp_seq_afinfo udp4_seq_afinfo = { ++ .name = "udp", ++ .family = AF_INET, ++ .udp_table = &udp_table, ++ .seq_fops = { ++ .owner = THIS_MODULE, ++ }, ++ .seq_ops = { ++ .show = udp4_seq_show, ++ }, ++}; ++ ++static int udp4_proc_init_net(struct net *net) ++{ ++ return udp_proc_register(net, &udp4_seq_afinfo); ++} ++ ++static void udp4_proc_exit_net(struct net *net) ++{ ++ udp_proc_unregister(net, &udp4_seq_afinfo); ++} ++ ++static struct pernet_operations udp4_net_ops = { ++ .init = udp4_proc_init_net, ++ .exit = udp4_proc_exit_net, ++}; ++ ++int __init udp4_proc_init(void) ++{ ++ return register_pernet_subsys(&udp4_net_ops); ++} ++ ++void udp4_proc_exit(void) ++{ ++ unregister_pernet_subsys(&udp4_net_ops); ++} ++#endif /* CONFIG_PROC_FS */ ++ ++void __init udp_table_init(struct udp_table *table) ++{ ++ int i; ++ ++ for (i = 0; i < UDP_HTABLE_SIZE; i++) { ++ INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); ++ spin_lock_init(&table->hash[i].lock); ++ } ++} ++ ++void __init udp_init(void) ++{ ++ unsigned long nr_pages, limit; ++ ++ udp_table_init(&udp_table); ++ /* Set the pressure threshold up by the same strategy of TCP. It is a ++ * fraction of global memory that is up to 1/2 at 256 MB, decreasing ++ * toward zero with the amount of memory, with a floor of 128 pages. ++ */ ++ nr_pages = totalram_pages - totalhigh_pages; ++ limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); ++ limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); ++ limit = max(limit, 128UL); ++ sysctl_udp_mem[0] = limit / 4 * 3; ++ sysctl_udp_mem[1] = limit; ++ sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2; ++ ++ sysctl_udp_rmem_min = SK_MEM_QUANTUM; ++ sysctl_udp_wmem_min = SK_MEM_QUANTUM; ++} ++ ++EXPORT_SYMBOL(udp_disconnect); ++EXPORT_SYMBOL(udp_ioctl); ++EXPORT_SYMBOL(udp_prot); ++EXPORT_SYMBOL(udp_sendmsg); ++EXPORT_SYMBOL(udp_lib_getsockopt); ++EXPORT_SYMBOL(udp_lib_setsockopt); ++EXPORT_SYMBOL(udp_poll); ++EXPORT_SYMBOL(udp_lib_get_port); ++ ++#ifdef CONFIG_PROC_FS ++EXPORT_SYMBOL(udp_proc_register); ++EXPORT_SYMBOL(udp_proc_unregister); ++#endif diff --git a/target/linux/patches/2.6.30.4/ocf.patch b/target/linux/patches/2.6.30.4/ocf.patch new file mode 100644 index 000000000..64c5eeb0f --- /dev/null +++ b/target/linux/patches/2.6.30.4/ocf.patch @@ -0,0 +1,23653 @@ +diff -Nur linux-2.6.30.orig/crypto/Kconfig linux-2.6.30/crypto/Kconfig +--- linux-2.6.30.orig/crypto/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/crypto/Kconfig 2009-06-11 10:55:27.000000000 +0200 +@@ -781,3 +781,5 @@ + source "drivers/crypto/Kconfig" + + endif # if CRYPTO ++ ++source "crypto/ocf/Kconfig" +diff -Nur linux-2.6.30.orig/crypto/Makefile linux-2.6.30/crypto/Makefile +--- linux-2.6.30.orig/crypto/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/crypto/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -84,6 +84,8 @@ + obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o + obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + ++obj-$(CONFIG_OCF_OCF) += ocf/ ++ + # + # generic algorithms and the async_tx api + # +diff -Nur linux-2.6.30.orig/crypto/ocf/Config.in linux-2.6.30/crypto/ocf/Config.in +--- linux-2.6.30.orig/crypto/ocf/Config.in 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Config.in 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,34 @@ ++############################################################################# ++ ++mainmenu_option next_comment ++comment 'OCF Configuration' ++tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF ++dep_mbool ' enable fips RNG checks (fips check on RNG data before use)' \ ++ CONFIG_OCF_FIPS $CONFIG_OCF_OCF ++dep_mbool ' enable harvesting entropy for /dev/random' \ ++ CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF ++dep_tristate ' cryptodev (user space support)' \ ++ CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF ++dep_tristate ' cryptosoft (software crypto engine)' \ ++ CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF ++dep_tristate ' safenet (HW crypto engine)' \ ++ CONFIG_OCF_SAFE $CONFIG_OCF_OCF ++dep_tristate ' IXP4xx (HW crypto engine)' \ ++ CONFIG_OCF_IXP4XX $CONFIG_OCF_OCF ++dep_mbool ' Enable IXP4xx HW to perform SHA1 and MD5 hashing (very slow)' \ ++ CONFIG_OCF_IXP4XX_SHA1_MD5 $CONFIG_OCF_IXP4XX ++dep_tristate ' hifn (HW crypto engine)' \ ++ CONFIG_OCF_HIFN $CONFIG_OCF_OCF ++dep_tristate ' talitos (HW crypto engine)' \ ++ CONFIG_OCF_TALITOS $CONFIG_OCF_OCF ++dep_tristate ' pasemi (HW crypto engine)' \ ++ CONFIG_OCF_PASEMI $CONFIG_OCF_OCF ++dep_tristate ' ep80579 (HW crypto engine)' \ ++ CONFIG_OCF_EP80579 $CONFIG_OCF_OCF ++dep_tristate ' ocfnull (does no crypto)' \ ++ CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF ++dep_tristate ' ocf-bench (HW crypto in-kernel benchmark)' \ ++ CONFIG_OCF_BENCH $CONFIG_OCF_OCF ++endmenu ++ ++############################################################################# +diff -Nur linux-2.6.30.orig/crypto/ocf/criov.c linux-2.6.30/crypto/ocf/criov.c +--- linux-2.6.30.orig/crypto/ocf/criov.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/criov.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,215 @@ ++/* $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $ */ ++ ++/* ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 1999 Theo de Raadt ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* ++ * This macro is only for avoiding code duplication, as we need to skip ++ * given number of bytes in the same way in three functions below. ++ */ ++#define CUIO_SKIP() do { \ ++ KASSERT(off >= 0, ("%s: off %d < 0", __func__, off)); \ ++ KASSERT(len >= 0, ("%s: len %d < 0", __func__, len)); \ ++ while (off > 0) { \ ++ KASSERT(iol >= 0, ("%s: empty in skip", __func__)); \ ++ if (off < iov->iov_len) \ ++ break; \ ++ off -= iov->iov_len; \ ++ iol--; \ ++ iov++; \ ++ } \ ++} while (0) ++ ++void ++cuio_copydata(struct uio* uio, int off, int len, caddr_t cp) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ unsigned count; ++ ++ CUIO_SKIP(); ++ while (len > 0) { ++ KASSERT(iol >= 0, ("%s: empty", __func__)); ++ count = min((int)(iov->iov_len - off), len); ++ memcpy(cp, ((caddr_t)iov->iov_base) + off, count); ++ len -= count; ++ cp += count; ++ off = 0; ++ iol--; ++ iov++; ++ } ++} ++ ++void ++cuio_copyback(struct uio* uio, int off, int len, caddr_t cp) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ unsigned count; ++ ++ CUIO_SKIP(); ++ while (len > 0) { ++ KASSERT(iol >= 0, ("%s: empty", __func__)); ++ count = min((int)(iov->iov_len - off), len); ++ memcpy(((caddr_t)iov->iov_base) + off, cp, count); ++ len -= count; ++ cp += count; ++ off = 0; ++ iol--; ++ iov++; ++ } ++} ++ ++/* ++ * Return a pointer to iov/offset of location in iovec list. ++ */ ++struct iovec * ++cuio_getptr(struct uio *uio, int loc, int *off) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int iol = uio->uio_iovcnt; ++ ++ while (loc >= 0) { ++ /* Normal end of search */ ++ if (loc < iov->iov_len) { ++ *off = loc; ++ return (iov); ++ } ++ ++ loc -= iov->iov_len; ++ if (iol == 0) { ++ if (loc == 0) { ++ /* Point at the end of valid data */ ++ *off = iov->iov_len; ++ return (iov); ++ } else ++ return (NULL); ++ } else { ++ iov++, iol--; ++ } ++ } ++ ++ return (NULL); ++} ++ ++EXPORT_SYMBOL(cuio_copyback); ++EXPORT_SYMBOL(cuio_copydata); ++EXPORT_SYMBOL(cuio_getptr); ++ ++ ++static void ++skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len) ++{ ++ int i; ++ if (offset < skb_headlen(skb)) { ++ memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len)); ++ len -= skb_headlen(skb); ++ cp += skb_headlen(skb); ++ } ++ offset -= skb_headlen(skb); ++ for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) { ++ if (offset < skb_shinfo(skb)->frags[i].size) { ++ memcpy(page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ cp, min_t(int, skb_shinfo(skb)->frags[i].size, len)); ++ len -= skb_shinfo(skb)->frags[i].size; ++ cp += skb_shinfo(skb)->frags[i].size; ++ } ++ offset -= skb_shinfo(skb)->frags[i].size; ++ } ++} ++ ++void ++crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in) ++{ ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ skb_copy_bits_back((struct sk_buff *)buf, off, in, size); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ cuio_copyback((struct uio *)buf, off, size, in); ++ else ++ bcopy(in, buf + off, size); ++} ++ ++void ++crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out) ++{ ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ skb_copy_bits((struct sk_buff *)buf, off, out, size); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ cuio_copydata((struct uio *)buf, off, size, out); ++ else ++ bcopy(buf + off, out, size); ++} ++ ++int ++crypto_apply(int flags, caddr_t buf, int off, int len, ++ int (*f)(void *, void *, u_int), void *arg) ++{ ++#if 0 ++ int error; ++ ++ if ((flags & CRYPTO_F_SKBUF) != 0) ++ error = XXXXXX((struct mbuf *)buf, off, len, f, arg); ++ else if ((flags & CRYPTO_F_IOV) != 0) ++ error = cuio_apply((struct uio *)buf, off, len, f, arg); ++ else ++ error = (*f)(arg, buf + off, len); ++ return (error); ++#else ++ KASSERT(0, ("crypto_apply not implemented!\n")); ++#endif ++ return 0; ++} ++ ++EXPORT_SYMBOL(crypto_copyback); ++EXPORT_SYMBOL(crypto_copydata); ++EXPORT_SYMBOL(crypto_apply); ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/crypto.c linux-2.6.30/crypto/ocf/crypto.c +--- linux-2.6.30.orig/crypto/ocf/crypto.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/crypto.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1741 @@ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * Copyright (c) 2002-2006 Sam Leffler. All rights reserved. ++ * ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $"); ++#endif ++ ++/* ++ * Cryptographic Subsystem. ++ * ++ * This code is derived from the Openbsd Cryptographic Framework (OCF) ++ * that has the copyright shown below. Very little of the original ++ * code remains. ++ */ ++/*- ++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * ++ * This code was written by Angelos D. Keromytis in Athens, Greece, in ++ * February 2000. Network Security Technologies Inc. (NSTI) kindly ++ * supported the development of this code. ++ * ++ * Copyright (c) 2000, 2001 Angelos D. Keromytis ++ * ++ * Permission to use, copy, and modify this software with or without fee ++ * is hereby granted, provided that this entire notice is included in ++ * all source code copies of any software which is or includes a copy or ++ * modification of this software. ++ * ++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY ++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE ++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR ++ * PURPOSE. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $"); ++ */ ++ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * keep track of whether or not we have been initialised, a big ++ * issue if we are linked into the kernel and a driver gets started before ++ * us ++ */ ++static int crypto_initted = 0; ++ ++/* ++ * Crypto drivers register themselves by allocating a slot in the ++ * crypto_drivers table with crypto_get_driverid() and then registering ++ * each algorithm they support with crypto_register() and crypto_kregister(). ++ */ ++ ++/* ++ * lock on driver table ++ * we track its state as spin_is_locked does not do anything on non-SMP boxes ++ */ ++static spinlock_t crypto_drivers_lock; ++static int crypto_drivers_locked; /* for non-SMP boxes */ ++ ++#define CRYPTO_DRIVER_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_drivers_lock, d_flags); \ ++ crypto_drivers_locked = 1; \ ++ dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_DRIVER_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \ ++ crypto_drivers_locked = 0; \ ++ spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \ ++ }) ++#define CRYPTO_DRIVER_ASSERT() \ ++ ({ \ ++ if (!crypto_drivers_locked) { \ ++ dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \ ++ } \ ++ }) ++ ++/* ++ * Crypto device/driver capabilities structure. ++ * ++ * Synchronization: ++ * (d) - protected by CRYPTO_DRIVER_LOCK() ++ * (q) - protected by CRYPTO_Q_LOCK() ++ * Not tagged fields are read-only. ++ */ ++struct cryptocap { ++ device_t cc_dev; /* (d) device/driver */ ++ u_int32_t cc_sessions; /* (d) # of sessions */ ++ u_int32_t cc_koperations; /* (d) # os asym operations */ ++ /* ++ * Largest possible operator length (in bits) for each type of ++ * encryption algorithm. XXX not used ++ */ ++ u_int16_t cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1]; ++ u_int8_t cc_alg[CRYPTO_ALGORITHM_MAX + 1]; ++ u_int8_t cc_kalg[CRK_ALGORITHM_MAX + 1]; ++ ++ int cc_flags; /* (d) flags */ ++#define CRYPTOCAP_F_CLEANUP 0x80000000 /* needs resource cleanup */ ++ int cc_qblocked; /* (q) symmetric q blocked */ ++ int cc_kqblocked; /* (q) asymmetric q blocked */ ++}; ++static struct cryptocap *crypto_drivers = NULL; ++static int crypto_drivers_num = 0; ++ ++/* ++ * There are two queues for crypto requests; one for symmetric (e.g. ++ * cipher) operations and one for asymmetric (e.g. MOD)operations. ++ * A single mutex is used to lock access to both queues. We could ++ * have one per-queue but having one simplifies handling of block/unblock ++ * operations. ++ */ ++static int crp_sleep = 0; ++static LIST_HEAD(crp_q); /* request queues */ ++static LIST_HEAD(crp_kq); ++ ++static spinlock_t crypto_q_lock; ++ ++int crypto_all_qblocked = 0; /* protect with Q_LOCK */ ++module_param(crypto_all_qblocked, int, 0444); ++MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked"); ++ ++int crypto_all_kqblocked = 0; /* protect with Q_LOCK */ ++module_param(crypto_all_kqblocked, int, 0444); ++MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked"); ++ ++#define CRYPTO_Q_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_q_lock, q_flags); \ ++ dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_Q_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \ ++ spin_unlock_irqrestore(&crypto_q_lock, q_flags); \ ++ }) ++ ++/* ++ * There are two queues for processing completed crypto requests; one ++ * for the symmetric and one for the asymmetric ops. We only need one ++ * but have two to avoid type futzing (cryptop vs. cryptkop). A single ++ * mutex is used to lock access to both queues. Note that this lock ++ * must be separate from the lock on request queues to insure driver ++ * callbacks don't generate lock order reversals. ++ */ ++static LIST_HEAD(crp_ret_q); /* callback queues */ ++static LIST_HEAD(crp_ret_kq); ++ ++static spinlock_t crypto_ret_q_lock; ++#define CRYPTO_RETQ_LOCK() \ ++ ({ \ ++ spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \ ++ dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \ ++ }) ++#define CRYPTO_RETQ_UNLOCK() \ ++ ({ \ ++ dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \ ++ spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \ ++ }) ++#define CRYPTO_RETQ_EMPTY() (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq)) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static kmem_cache_t *cryptop_zone; ++static kmem_cache_t *cryptodesc_zone; ++#else ++static struct kmem_cache *cryptop_zone; ++static struct kmem_cache *cryptodesc_zone; ++#endif ++ ++#define debug crypto_debug ++int crypto_debug = 0; ++module_param(crypto_debug, int, 0644); ++MODULE_PARM_DESC(crypto_debug, "Enable debug"); ++EXPORT_SYMBOL(crypto_debug); ++ ++/* ++ * Maximum number of outstanding crypto requests before we start ++ * failing requests. We need this to prevent DOS when too many ++ * requests are arriving for us to keep up. Otherwise we will ++ * run the system out of memory. Since crypto is slow, we are ++ * usually the bottleneck that needs to say, enough is enough. ++ * ++ * We cannot print errors when this condition occurs, we are already too ++ * slow, printing anything will just kill us ++ */ ++ ++static int crypto_q_cnt = 0; ++module_param(crypto_q_cnt, int, 0444); ++MODULE_PARM_DESC(crypto_q_cnt, ++ "Current number of outstanding crypto requests"); ++ ++static int crypto_q_max = 1000; ++module_param(crypto_q_max, int, 0644); ++MODULE_PARM_DESC(crypto_q_max, ++ "Maximum number of outstanding crypto requests"); ++ ++#define bootverbose crypto_verbose ++static int crypto_verbose = 0; ++module_param(crypto_verbose, int, 0644); ++MODULE_PARM_DESC(crypto_verbose, ++ "Enable verbose crypto startup"); ++ ++int crypto_usercrypto = 1; /* userland may do crypto reqs */ ++module_param(crypto_usercrypto, int, 0644); ++MODULE_PARM_DESC(crypto_usercrypto, ++ "Enable/disable user-mode access to crypto support"); ++ ++int crypto_userasymcrypto = 1; /* userland may do asym crypto reqs */ ++module_param(crypto_userasymcrypto, int, 0644); ++MODULE_PARM_DESC(crypto_userasymcrypto, ++ "Enable/disable user-mode access to asymmetric crypto support"); ++ ++int crypto_devallowsoft = 0; /* only use hardware crypto */ ++module_param(crypto_devallowsoft, int, 0644); ++MODULE_PARM_DESC(crypto_devallowsoft, ++ "Enable/disable use of software crypto support"); ++ ++static pid_t cryptoproc = (pid_t) -1; ++static struct completion cryptoproc_exited; ++static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait); ++static pid_t cryptoretproc = (pid_t) -1; ++static struct completion cryptoretproc_exited; ++static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait); ++ ++static int crypto_proc(void *arg); ++static int crypto_ret_proc(void *arg); ++static int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint); ++static int crypto_kinvoke(struct cryptkop *krp, int flags); ++static void crypto_exit(void); ++static int crypto_init(void); ++ ++static struct cryptostats cryptostats; ++ ++static struct cryptocap * ++crypto_checkdriver(u_int32_t hid) ++{ ++ if (crypto_drivers == NULL) ++ return NULL; ++ return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]); ++} ++ ++/* ++ * Compare a driver's list of supported algorithms against another ++ * list; return non-zero if all algorithms are supported. ++ */ ++static int ++driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri) ++{ ++ const struct cryptoini *cr; ++ ++ /* See if all the algorithms are supported. */ ++ for (cr = cri; cr; cr = cr->cri_next) ++ if (cap->cc_alg[cr->cri_alg] == 0) ++ return 0; ++ return 1; ++} ++ ++/* ++ * Select a driver for a new session that supports the specified ++ * algorithms and, optionally, is constrained according to the flags. ++ * The algorithm we use here is pretty stupid; just use the ++ * first driver that supports all the algorithms we need. If there ++ * are multiple drivers we choose the driver with the fewest active ++ * sessions. We prefer hardware-backed drivers to software ones. ++ * ++ * XXX We need more smarts here (in real life too, but that's ++ * XXX another story altogether). ++ */ ++static struct cryptocap * ++crypto_select_driver(const struct cryptoini *cri, int flags) ++{ ++ struct cryptocap *cap, *best; ++ int match, hid; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ /* ++ * Look first for hardware crypto devices if permitted. ++ */ ++ if (flags & CRYPTOCAP_F_HARDWARE) ++ match = CRYPTOCAP_F_HARDWARE; ++ else ++ match = CRYPTOCAP_F_SOFTWARE; ++ best = NULL; ++again: ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ cap = &crypto_drivers[hid]; ++ /* ++ * If it's not initialized, is in the process of ++ * going away, or is not appropriate (hardware ++ * or software based on match), then skip. ++ */ ++ if (cap->cc_dev == NULL || ++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || ++ (cap->cc_flags & match) == 0) ++ continue; ++ ++ /* verify all the algorithms are supported. */ ++ if (driver_suitable(cap, cri)) { ++ if (best == NULL || ++ cap->cc_sessions < best->cc_sessions) ++ best = cap; ++ } ++ } ++ if (best != NULL) ++ return best; ++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { ++ /* sort of an Algol 68-style for loop */ ++ match = CRYPTOCAP_F_SOFTWARE; ++ goto again; ++ } ++ return best; ++} ++ ++/* ++ * Create a new session. The crid argument specifies a crypto ++ * driver to use or constraints on a driver to select (hardware ++ * only, software only, either). Whatever driver is selected ++ * must be capable of the requested crypto algorithms. ++ */ ++int ++crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid) ++{ ++ struct cryptocap *cap; ++ u_int32_t hid, lid; ++ int err; ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ /* ++ * Use specified driver; verify it is capable. ++ */ ++ cap = crypto_checkdriver(crid); ++ if (cap != NULL && !driver_suitable(cap, cri)) ++ cap = NULL; ++ } else { ++ /* ++ * No requested driver; select based on crid flags. ++ */ ++ cap = crypto_select_driver(cri, crid); ++ /* ++ * if NULL then can't do everything in one session. ++ * XXX Fix this. We need to inject a "virtual" session ++ * XXX layer right about here. ++ */ ++ } ++ if (cap != NULL) { ++ /* Call the driver initialization routine. */ ++ hid = cap - crypto_drivers; ++ lid = hid; /* Pass the driver ID. */ ++ cap->cc_sessions++; ++ CRYPTO_DRIVER_UNLOCK(); ++ err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri); ++ CRYPTO_DRIVER_LOCK(); ++ if (err == 0) { ++ (*sid) = (cap->cc_flags & 0xff000000) ++ | (hid & 0x00ffffff); ++ (*sid) <<= 32; ++ (*sid) |= (lid & 0xffffffff); ++ } else ++ cap->cc_sessions--; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++static void ++crypto_remove(struct cryptocap *cap) ++{ ++ CRYPTO_DRIVER_ASSERT(); ++ if (cap->cc_sessions == 0 && cap->cc_koperations == 0) ++ bzero(cap, sizeof(*cap)); ++} ++ ++/* ++ * Delete an existing session (or a reserved session on an unregistered ++ * driver). ++ */ ++int ++crypto_freesession(u_int64_t sid) ++{ ++ struct cryptocap *cap; ++ u_int32_t hid; ++ int err = 0; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ if (crypto_drivers == NULL) { ++ err = EINVAL; ++ goto done; ++ } ++ ++ /* Determine two IDs. */ ++ hid = CRYPTO_SESID2HID(sid); ++ ++ if (hid >= crypto_drivers_num) { ++ dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid); ++ err = ENOENT; ++ goto done; ++ } ++ cap = &crypto_drivers[hid]; ++ ++ if (cap->cc_dev) { ++ CRYPTO_DRIVER_UNLOCK(); ++ /* Call the driver cleanup routine, if available, unlocked. */ ++ err = CRYPTODEV_FREESESSION(cap->cc_dev, sid); ++ CRYPTO_DRIVER_LOCK(); ++ } ++ ++ if (cap->cc_sessions) ++ cap->cc_sessions--; ++ ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ++ crypto_remove(cap); ++ ++done: ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Return an unused driver id. Used by drivers prior to registering ++ * support for the algorithms they handle. ++ */ ++int32_t ++crypto_get_driverid(device_t dev, int flags) ++{ ++ struct cryptocap *newdrv; ++ int i; ++ unsigned long d_flags; ++ ++ if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ printf("%s: no flags specified when registering driver\n", ++ device_get_nameunit(dev)); ++ return -1; ++ } ++ ++ CRYPTO_DRIVER_LOCK(); ++ ++ for (i = 0; i < crypto_drivers_num; i++) { ++ if (crypto_drivers[i].cc_dev == NULL && ++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) { ++ break; ++ } ++ } ++ ++ /* Out of entries, allocate some more. */ ++ if (i == crypto_drivers_num) { ++ /* Be careful about wrap-around. */ ++ if (2 * crypto_drivers_num <= crypto_drivers_num) { ++ CRYPTO_DRIVER_UNLOCK(); ++ printk("crypto: driver count wraparound!\n"); ++ return -1; ++ } ++ ++ newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap), ++ GFP_KERNEL); ++ if (newdrv == NULL) { ++ CRYPTO_DRIVER_UNLOCK(); ++ printk("crypto: no space to expand driver table!\n"); ++ return -1; ++ } ++ ++ memcpy(newdrv, crypto_drivers, ++ crypto_drivers_num * sizeof(struct cryptocap)); ++ memset(&newdrv[crypto_drivers_num], 0, ++ crypto_drivers_num * sizeof(struct cryptocap)); ++ ++ crypto_drivers_num *= 2; ++ ++ kfree(crypto_drivers); ++ crypto_drivers = newdrv; ++ } ++ ++ /* NB: state is zero'd on free */ ++ crypto_drivers[i].cc_sessions = 1; /* Mark */ ++ crypto_drivers[i].cc_dev = dev; ++ crypto_drivers[i].cc_flags = flags; ++ if (bootverbose) ++ printf("crypto: assign %s driver id %u, flags %u\n", ++ device_get_nameunit(dev), i, flags); ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ return i; ++} ++ ++/* ++ * Lookup a driver by name. We match against the full device ++ * name and unit, and against just the name. The latter gives ++ * us a simple widlcarding by device name. On success return the ++ * driver/hardware identifier; otherwise return -1. ++ */ ++int ++crypto_find_driver(const char *match) ++{ ++ int i, len = strlen(match); ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ for (i = 0; i < crypto_drivers_num; i++) { ++ device_t dev = crypto_drivers[i].cc_dev; ++ if (dev == NULL || ++ (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP)) ++ continue; ++ if (strncmp(match, device_get_nameunit(dev), len) == 0 || ++ strncmp(match, device_get_name(dev), len) == 0) ++ break; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ return i < crypto_drivers_num ? i : -1; ++} ++ ++/* ++ * Return the device_t for the specified driver or NULL ++ * if the driver identifier is invalid. ++ */ ++device_t ++crypto_find_device_byhid(int hid) ++{ ++ struct cryptocap *cap = crypto_checkdriver(hid); ++ return cap != NULL ? cap->cc_dev : NULL; ++} ++ ++/* ++ * Return the device/driver capabilities. ++ */ ++int ++crypto_getcaps(int hid) ++{ ++ struct cryptocap *cap = crypto_checkdriver(hid); ++ return cap != NULL ? cap->cc_flags : 0; ++} ++ ++/* ++ * Register support for a key-related algorithm. This routine ++ * is called once for each algorithm supported a driver. ++ */ ++int ++crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL && ++ (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) { ++ /* ++ * XXX Do some performance testing to determine placing. ++ * XXX We probably need an auxiliary data structure that ++ * XXX describes relative performances. ++ */ ++ ++ cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; ++ if (bootverbose) ++ printf("crypto: %s registers key alg %u flags %u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , kalg ++ , flags ++ ); ++ err = 0; ++ } else ++ err = EINVAL; ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Register support for a non-key-related algorithm. This routine ++ * is called once for each such algorithm supported by a driver. ++ */ ++int ++crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, ++ u_int32_t flags) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__, ++ driverid, alg, maxoplen, flags); ++ ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ /* NB: algorithms are in the range [1..max] */ ++ if (cap != NULL && ++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) { ++ /* ++ * XXX Do some performance testing to determine placing. ++ * XXX We probably need an auxiliary data structure that ++ * XXX describes relative performances. ++ */ ++ ++ cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; ++ cap->cc_max_op_len[alg] = maxoplen; ++ if (bootverbose) ++ printf("crypto: %s registers alg %u flags %u maxoplen %u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , alg ++ , flags ++ , maxoplen ++ ); ++ cap->cc_sessions = 0; /* Unmark */ ++ err = 0; ++ } else ++ err = EINVAL; ++ ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++static void ++driver_finis(struct cryptocap *cap) ++{ ++ u_int32_t ses, kops; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ ses = cap->cc_sessions; ++ kops = cap->cc_koperations; ++ bzero(cap, sizeof(*cap)); ++ if (ses != 0 || kops != 0) { ++ /* ++ * If there are pending sessions, ++ * just mark as invalid. ++ */ ++ cap->cc_flags |= CRYPTOCAP_F_CLEANUP; ++ cap->cc_sessions = ses; ++ cap->cc_koperations = kops; ++ } ++} ++ ++/* ++ * Unregister a crypto driver. If there are pending sessions using it, ++ * leave enough information around so that subsequent calls using those ++ * sessions will correctly detect the driver has been unregistered and ++ * reroute requests. ++ */ ++int ++crypto_unregister(u_int32_t driverid, int alg) ++{ ++ struct cryptocap *cap; ++ int i, err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL && ++ (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) && ++ cap->cc_alg[alg] != 0) { ++ cap->cc_alg[alg] = 0; ++ cap->cc_max_op_len[alg] = 0; ++ ++ /* Was this the last algorithm ? */ ++ for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) ++ if (cap->cc_alg[i] != 0) ++ break; ++ ++ if (i == CRYPTO_ALGORITHM_MAX + 1) ++ driver_finis(cap); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ return err; ++} ++ ++/* ++ * Unregister all algorithms associated with a crypto driver. ++ * If there are pending sessions using it, leave enough information ++ * around so that subsequent calls using those sessions will ++ * correctly detect the driver has been unregistered and reroute ++ * requests. ++ */ ++int ++crypto_unregister_all(u_int32_t driverid) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ CRYPTO_DRIVER_LOCK(); ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL) { ++ driver_finis(cap); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ return err; ++} ++ ++/* ++ * Clear blockage on a driver. The what parameter indicates whether ++ * the driver is now ready for cryptop's and/or cryptokop's. ++ */ ++int ++crypto_unblock(u_int32_t driverid, int what) ++{ ++ struct cryptocap *cap; ++ int err; ++ unsigned long q_flags; ++ ++ CRYPTO_Q_LOCK(); ++ cap = crypto_checkdriver(driverid); ++ if (cap != NULL) { ++ if (what & CRYPTO_SYMQ) { ++ cap->cc_qblocked = 0; ++ crypto_all_qblocked = 0; ++ } ++ if (what & CRYPTO_ASYMQ) { ++ cap->cc_kqblocked = 0; ++ crypto_all_kqblocked = 0; ++ } ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ err = 0; ++ } else ++ err = EINVAL; ++ CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock ++ ++ return err; ++} ++ ++/* ++ * Add a crypto request to a queue, to be processed by the kernel thread. ++ */ ++int ++crypto_dispatch(struct cryptop *crp) ++{ ++ struct cryptocap *cap; ++ int result = -1; ++ unsigned long q_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ cryptostats.cs_ops++; ++ ++ CRYPTO_Q_LOCK(); ++ if (crypto_q_cnt >= crypto_q_max) { ++ CRYPTO_Q_UNLOCK(); ++ cryptostats.cs_drops++; ++ return ENOMEM; ++ } ++ crypto_q_cnt++; ++ ++ /* ++ * Caller marked the request to be processed immediately; dispatch ++ * it directly to the driver unless the driver is currently blocked. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) { ++ int hid = CRYPTO_SESID2HID(crp->crp_sid); ++ cap = crypto_checkdriver(hid); ++ /* Driver cannot disappear when there is an active session. */ ++ KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__)); ++ if (!cap->cc_qblocked) { ++ crypto_all_qblocked = 0; ++ crypto_drivers[hid].cc_qblocked = 1; ++ CRYPTO_Q_UNLOCK(); ++ result = crypto_invoke(cap, crp, 0); ++ CRYPTO_Q_LOCK(); ++ if (result != ERESTART) ++ crypto_drivers[hid].cc_qblocked = 0; ++ } ++ } ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ list_add(&crp->crp_next, &crp_q); ++ cryptostats.cs_blocks++; ++ } else if (result == -1) { ++ TAILQ_INSERT_TAIL(&crp_q, crp, crp_next); ++ } ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_Q_UNLOCK(); ++ return 0; ++} ++ ++/* ++ * Add an asymetric crypto request to a queue, ++ * to be processed by the kernel thread. ++ */ ++int ++crypto_kdispatch(struct cryptkop *krp) ++{ ++ int error; ++ unsigned long q_flags; ++ ++ cryptostats.cs_kops++; ++ ++ error = crypto_kinvoke(krp, krp->krp_crid); ++ if (error == ERESTART) { ++ CRYPTO_Q_LOCK(); ++ TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next); ++ if (crp_sleep) ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_Q_UNLOCK(); ++ error = 0; ++ } ++ return error; ++} ++ ++/* ++ * Verify a driver is suitable for the specified operation. ++ */ ++static __inline int ++kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp) ++{ ++ return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0; ++} ++ ++/* ++ * Select a driver for an asym operation. The driver must ++ * support the necessary algorithm. The caller can constrain ++ * which device is selected with the flags parameter. The ++ * algorithm we use here is pretty stupid; just use the first ++ * driver that supports the algorithms we need. If there are ++ * multiple suitable drivers we choose the driver with the ++ * fewest active operations. We prefer hardware-backed ++ * drivers to software ones when either may be used. ++ */ ++static struct cryptocap * ++crypto_select_kdriver(const struct cryptkop *krp, int flags) ++{ ++ struct cryptocap *cap, *best, *blocked; ++ int match, hid; ++ ++ CRYPTO_DRIVER_ASSERT(); ++ ++ /* ++ * Look first for hardware crypto devices if permitted. ++ */ ++ if (flags & CRYPTOCAP_F_HARDWARE) ++ match = CRYPTOCAP_F_HARDWARE; ++ else ++ match = CRYPTOCAP_F_SOFTWARE; ++ best = NULL; ++ blocked = NULL; ++again: ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ cap = &crypto_drivers[hid]; ++ /* ++ * If it's not initialized, is in the process of ++ * going away, or is not appropriate (hardware ++ * or software based on match), then skip. ++ */ ++ if (cap->cc_dev == NULL || ++ (cap->cc_flags & CRYPTOCAP_F_CLEANUP) || ++ (cap->cc_flags & match) == 0) ++ continue; ++ ++ /* verify all the algorithms are supported. */ ++ if (kdriver_suitable(cap, krp)) { ++ if (best == NULL || ++ cap->cc_koperations < best->cc_koperations) ++ best = cap; ++ } ++ } ++ if (best != NULL) ++ return best; ++ if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { ++ /* sort of an Algol 68-style for loop */ ++ match = CRYPTOCAP_F_SOFTWARE; ++ goto again; ++ } ++ return best; ++} ++ ++/* ++ * Dispatch an assymetric crypto request. ++ */ ++static int ++crypto_kinvoke(struct cryptkop *krp, int crid) ++{ ++ struct cryptocap *cap = NULL; ++ int error; ++ unsigned long d_flags; ++ ++ KASSERT(krp != NULL, ("%s: krp == NULL", __func__)); ++ KASSERT(krp->krp_callback != NULL, ++ ("%s: krp->crp_callback == NULL", __func__)); ++ ++ CRYPTO_DRIVER_LOCK(); ++ if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) { ++ cap = crypto_checkdriver(crid); ++ if (cap != NULL) { ++ /* ++ * Driver present, it must support the necessary ++ * algorithm and, if s/w drivers are excluded, ++ * it must be registered as hardware-backed. ++ */ ++ if (!kdriver_suitable(cap, krp) || ++ (!crypto_devallowsoft && ++ (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0)) ++ cap = NULL; ++ } ++ } else { ++ /* ++ * No requested driver; select based on crid flags. ++ */ ++ if (!crypto_devallowsoft) /* NB: disallow s/w drivers */ ++ crid &= ~CRYPTOCAP_F_SOFTWARE; ++ cap = crypto_select_kdriver(krp, crid); ++ } ++ if (cap != NULL && !cap->cc_kqblocked) { ++ krp->krp_hid = cap - crypto_drivers; ++ cap->cc_koperations++; ++ CRYPTO_DRIVER_UNLOCK(); ++ error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0); ++ CRYPTO_DRIVER_LOCK(); ++ if (error == ERESTART) { ++ cap->cc_koperations--; ++ CRYPTO_DRIVER_UNLOCK(); ++ return (error); ++ } ++ /* return the actual device used */ ++ krp->krp_crid = krp->krp_hid; ++ } else { ++ /* ++ * NB: cap is !NULL if device is blocked; in ++ * that case return ERESTART so the operation ++ * is resubmitted if possible. ++ */ ++ error = (cap == NULL) ? ENODEV : ERESTART; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ if (error) { ++ krp->krp_status = error; ++ crypto_kdone(krp); ++ } ++ return 0; ++} ++ ++ ++/* ++ * Dispatch a crypto request to the appropriate crypto devices. ++ */ ++static int ++crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint) ++{ ++ KASSERT(crp != NULL, ("%s: crp == NULL", __func__)); ++ KASSERT(crp->crp_callback != NULL, ++ ("%s: crp->crp_callback == NULL", __func__)); ++ KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__)); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++#ifdef CRYPTO_TIMING ++ if (crypto_timing) ++ crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp); ++#endif ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) { ++ struct cryptodesc *crd; ++ u_int64_t nid; ++ ++ /* ++ * Driver has unregistered; migrate the session and return ++ * an error to the caller so they'll resubmit the op. ++ * ++ * XXX: What if there are more already queued requests for this ++ * session? ++ */ ++ crypto_freesession(crp->crp_sid); ++ ++ for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) ++ crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); ++ ++ /* XXX propagate flags from initial session? */ ++ if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), ++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0) ++ crp->crp_sid = nid; ++ ++ crp->crp_etype = EAGAIN; ++ crypto_done(crp); ++ return 0; ++ } else { ++ /* ++ * Invoke the driver to process the request. ++ */ ++ return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint); ++ } ++} ++ ++/* ++ * Release a set of crypto descriptors. ++ */ ++void ++crypto_freereq(struct cryptop *crp) ++{ ++ struct cryptodesc *crd; ++ ++ if (crp == NULL) ++ return; ++ ++#ifdef DIAGNOSTIC ++ { ++ struct cryptop *crp2; ++ unsigned long q_flags; ++ ++ CRYPTO_Q_LOCK(); ++ TAILQ_FOREACH(crp2, &crp_q, crp_next) { ++ KASSERT(crp2 != crp, ++ ("Freeing cryptop from the crypto queue (%p).", ++ crp)); ++ } ++ CRYPTO_Q_UNLOCK(); ++ CRYPTO_RETQ_LOCK(); ++ TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) { ++ KASSERT(crp2 != crp, ++ ("Freeing cryptop from the return queue (%p).", ++ crp)); ++ } ++ CRYPTO_RETQ_UNLOCK(); ++ } ++#endif ++ ++ while ((crd = crp->crp_desc) != NULL) { ++ crp->crp_desc = crd->crd_next; ++ kmem_cache_free(cryptodesc_zone, crd); ++ } ++ kmem_cache_free(cryptop_zone, crp); ++} ++ ++/* ++ * Acquire a set of crypto descriptors. ++ */ ++struct cryptop * ++crypto_getreq(int num) ++{ ++ struct cryptodesc *crd; ++ struct cryptop *crp; ++ ++ crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC); ++ if (crp != NULL) { ++ memset(crp, 0, sizeof(*crp)); ++ INIT_LIST_HEAD(&crp->crp_next); ++ init_waitqueue_head(&crp->crp_waitq); ++ while (num--) { ++ crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC); ++ if (crd == NULL) { ++ crypto_freereq(crp); ++ return NULL; ++ } ++ memset(crd, 0, sizeof(*crd)); ++ crd->crd_next = crp->crp_desc; ++ crp->crp_desc = crd; ++ } ++ } ++ return crp; ++} ++ ++/* ++ * Invoke the callback on behalf of the driver. ++ */ ++void ++crypto_done(struct cryptop *crp) ++{ ++ unsigned long q_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if ((crp->crp_flags & CRYPTO_F_DONE) == 0) { ++ crp->crp_flags |= CRYPTO_F_DONE; ++ CRYPTO_Q_LOCK(); ++ crypto_q_cnt--; ++ CRYPTO_Q_UNLOCK(); ++ } else ++ printk("crypto: crypto_done op already done, flags 0x%x", ++ crp->crp_flags); ++ if (crp->crp_etype != 0) ++ cryptostats.cs_errs++; ++ /* ++ * CBIMM means unconditionally do the callback immediately; ++ * CBIFSYNC means do the callback immediately only if the ++ * operation was done synchronously. Both are used to avoid ++ * doing extraneous context switches; the latter is mostly ++ * used with the software crypto driver. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_CBIMM) || ++ ((crp->crp_flags & CRYPTO_F_CBIFSYNC) && ++ (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) { ++ /* ++ * Do the callback directly. This is ok when the ++ * callback routine does very little (e.g. the ++ * /dev/crypto callback method just does a wakeup). ++ */ ++ crp->crp_callback(crp); ++ } else { ++ unsigned long r_flags; ++ /* ++ * Normal case; queue the callback for the thread. ++ */ ++ CRYPTO_RETQ_LOCK(); ++ if (CRYPTO_RETQ_EMPTY()) ++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ ++ TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next); ++ CRYPTO_RETQ_UNLOCK(); ++ } ++} ++ ++/* ++ * Invoke the callback on behalf of the driver. ++ */ ++void ++crypto_kdone(struct cryptkop *krp) ++{ ++ struct cryptocap *cap; ++ unsigned long d_flags; ++ ++ if ((krp->krp_flags & CRYPTO_KF_DONE) != 0) ++ printk("crypto: crypto_kdone op already done, flags 0x%x", ++ krp->krp_flags); ++ krp->krp_flags |= CRYPTO_KF_DONE; ++ if (krp->krp_status != 0) ++ cryptostats.cs_kerrs++; ++ ++ CRYPTO_DRIVER_LOCK(); ++ /* XXX: What if driver is loaded in the meantime? */ ++ if (krp->krp_hid < crypto_drivers_num) { ++ cap = &crypto_drivers[krp->krp_hid]; ++ cap->cc_koperations--; ++ KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0")); ++ if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ++ crypto_remove(cap); ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ /* ++ * CBIMM means unconditionally do the callback immediately; ++ * This is used to avoid doing extraneous context switches ++ */ ++ if ((krp->krp_flags & CRYPTO_KF_CBIMM)) { ++ /* ++ * Do the callback directly. This is ok when the ++ * callback routine does very little (e.g. the ++ * /dev/crypto callback method just does a wakeup). ++ */ ++ krp->krp_callback(krp); ++ } else { ++ unsigned long r_flags; ++ /* ++ * Normal case; queue the callback for the thread. ++ */ ++ CRYPTO_RETQ_LOCK(); ++ if (CRYPTO_RETQ_EMPTY()) ++ wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */ ++ TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next); ++ CRYPTO_RETQ_UNLOCK(); ++ } ++} ++ ++int ++crypto_getfeat(int *featp) ++{ ++ int hid, kalg, feat = 0; ++ unsigned long d_flags; ++ ++ CRYPTO_DRIVER_LOCK(); ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ const struct cryptocap *cap = &crypto_drivers[hid]; ++ ++ if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) && ++ !crypto_devallowsoft) { ++ continue; ++ } ++ for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++) ++ if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED) ++ feat |= 1 << kalg; ++ } ++ CRYPTO_DRIVER_UNLOCK(); ++ *featp = feat; ++ return (0); ++} ++ ++/* ++ * Crypto thread, dispatches crypto requests. ++ */ ++static int ++crypto_proc(void *arg) ++{ ++ struct cryptop *crp, *submit; ++ struct cryptkop *krp, *krpp; ++ struct cryptocap *cap; ++ u_int32_t hid; ++ int result, hint; ++ unsigned long q_flags; ++ ++ ocf_daemonize("crypto"); ++ ++ CRYPTO_Q_LOCK(); ++ for (;;) { ++ /* ++ * we need to make sure we don't get into a busy loop with nothing ++ * to do, the two crypto_all_*blocked vars help us find out when ++ * we are all full and can do nothing on any driver or Q. If so we ++ * wait for an unblock. ++ */ ++ crypto_all_qblocked = !list_empty(&crp_q); ++ ++ /* ++ * Find the first element in the queue that can be ++ * processed and look-ahead to see if multiple ops ++ * are ready for the same driver. ++ */ ++ submit = NULL; ++ hint = 0; ++ list_for_each_entry(crp, &crp_q, crp_next) { ++ hid = CRYPTO_SESID2HID(crp->crp_sid); ++ cap = crypto_checkdriver(hid); ++ /* ++ * Driver cannot disappear when there is an active ++ * session. ++ */ ++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.", ++ __func__, __LINE__)); ++ if (cap == NULL || cap->cc_dev == NULL) { ++ /* Op needs to be migrated, process it. */ ++ if (submit == NULL) ++ submit = crp; ++ break; ++ } ++ if (!cap->cc_qblocked) { ++ if (submit != NULL) { ++ /* ++ * We stop on finding another op, ++ * regardless whether its for the same ++ * driver or not. We could keep ++ * searching the queue but it might be ++ * better to just use a per-driver ++ * queue instead. ++ */ ++ if (CRYPTO_SESID2HID(submit->crp_sid) == hid) ++ hint = CRYPTO_HINT_MORE; ++ break; ++ } else { ++ submit = crp; ++ if ((submit->crp_flags & CRYPTO_F_BATCH) == 0) ++ break; ++ /* keep scanning for more are q'd */ ++ } ++ } ++ } ++ if (submit != NULL) { ++ hid = CRYPTO_SESID2HID(submit->crp_sid); ++ crypto_all_qblocked = 0; ++ list_del(&submit->crp_next); ++ crypto_drivers[hid].cc_qblocked = 1; ++ cap = crypto_checkdriver(hid); ++ CRYPTO_Q_UNLOCK(); ++ KASSERT(cap != NULL, ("%s:%u Driver disappeared.", ++ __func__, __LINE__)); ++ result = crypto_invoke(cap, submit, hint); ++ CRYPTO_Q_LOCK(); ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ /* XXX validate sid again? */ ++ list_add(&submit->crp_next, &crp_q); ++ cryptostats.cs_blocks++; ++ } else ++ crypto_drivers[hid].cc_qblocked=0; ++ } ++ ++ crypto_all_kqblocked = !list_empty(&crp_kq); ++ ++ /* As above, but for key ops */ ++ krp = NULL; ++ list_for_each_entry(krpp, &crp_kq, krp_next) { ++ cap = crypto_checkdriver(krpp->krp_hid); ++ if (cap == NULL || cap->cc_dev == NULL) { ++ /* ++ * Operation needs to be migrated, invalidate ++ * the assigned device so it will reselect a ++ * new one below. Propagate the original ++ * crid selection flags if supplied. ++ */ ++ krp->krp_hid = krp->krp_crid & ++ (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE); ++ if (krp->krp_hid == 0) ++ krp->krp_hid = ++ CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE; ++ break; ++ } ++ if (!cap->cc_kqblocked) { ++ krp = krpp; ++ break; ++ } ++ } ++ if (krp != NULL) { ++ crypto_all_kqblocked = 0; ++ list_del(&krp->krp_next); ++ crypto_drivers[krp->krp_hid].cc_kqblocked = 1; ++ CRYPTO_Q_UNLOCK(); ++ result = crypto_kinvoke(krp, krp->krp_hid); ++ CRYPTO_Q_LOCK(); ++ if (result == ERESTART) { ++ /* ++ * The driver ran out of resources, mark the ++ * driver ``blocked'' for cryptkop's and put ++ * the request back in the queue. It would ++ * best to put the request back where we got ++ * it but that's hard so for now we put it ++ * at the front. This should be ok; putting ++ * it at the end does not work. ++ */ ++ /* XXX validate sid again? */ ++ list_add(&krp->krp_next, &crp_kq); ++ cryptostats.cs_kblocks++; ++ } else ++ crypto_drivers[krp->krp_hid].cc_kqblocked = 0; ++ } ++ ++ if (submit == NULL && krp == NULL) { ++ /* ++ * Nothing more to be processed. Sleep until we're ++ * woken because there are more ops to process. ++ * This happens either by submission or by a driver ++ * becoming unblocked and notifying us through ++ * crypto_unblock. Note that when we wakeup we ++ * start processing each queue again from the ++ * front. It's not clear that it's important to ++ * preserve this ordering since ops may finish ++ * out of order if dispatched to different devices ++ * and some become blocked while others do not. ++ */ ++ dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n", ++ __FUNCTION__, ++ list_empty(&crp_q), crypto_all_qblocked, ++ list_empty(&crp_kq), crypto_all_kqblocked); ++ CRYPTO_Q_UNLOCK(); ++ crp_sleep = 1; ++ wait_event_interruptible(cryptoproc_wait, ++ !(list_empty(&crp_q) || crypto_all_qblocked) || ++ !(list_empty(&crp_kq) || crypto_all_kqblocked) || ++ cryptoproc == (pid_t) -1); ++ crp_sleep = 0; ++ if (signal_pending (current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ CRYPTO_Q_LOCK(); ++ dprintk("%s - awake\n", __FUNCTION__); ++ if (cryptoproc == (pid_t) -1) ++ break; ++ cryptostats.cs_intrs++; ++ } ++ } ++ CRYPTO_Q_UNLOCK(); ++ complete_and_exit(&cryptoproc_exited, 0); ++} ++ ++/* ++ * Crypto returns thread, does callbacks for processed crypto requests. ++ * Callbacks are done here, rather than in the crypto drivers, because ++ * callbacks typically are expensive and would slow interrupt handling. ++ */ ++static int ++crypto_ret_proc(void *arg) ++{ ++ struct cryptop *crpt; ++ struct cryptkop *krpt; ++ unsigned long r_flags; ++ ++ ocf_daemonize("crypto_ret"); ++ ++ CRYPTO_RETQ_LOCK(); ++ for (;;) { ++ /* Harvest return q's for completed ops */ ++ crpt = NULL; ++ if (!list_empty(&crp_ret_q)) ++ crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next); ++ if (crpt != NULL) ++ list_del(&crpt->crp_next); ++ ++ krpt = NULL; ++ if (!list_empty(&crp_ret_kq)) ++ krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next); ++ if (krpt != NULL) ++ list_del(&krpt->krp_next); ++ ++ if (crpt != NULL || krpt != NULL) { ++ CRYPTO_RETQ_UNLOCK(); ++ /* ++ * Run callbacks unlocked. ++ */ ++ if (crpt != NULL) ++ crpt->crp_callback(crpt); ++ if (krpt != NULL) ++ krpt->krp_callback(krpt); ++ CRYPTO_RETQ_LOCK(); ++ } else { ++ /* ++ * Nothing more to be processed. Sleep until we're ++ * woken because there are more returns to process. ++ */ ++ dprintk("%s - sleeping\n", __FUNCTION__); ++ CRYPTO_RETQ_UNLOCK(); ++ wait_event_interruptible(cryptoretproc_wait, ++ cryptoretproc == (pid_t) -1 || ++ !list_empty(&crp_ret_q) || ++ !list_empty(&crp_ret_kq)); ++ if (signal_pending (current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ CRYPTO_RETQ_LOCK(); ++ dprintk("%s - awake\n", __FUNCTION__); ++ if (cryptoretproc == (pid_t) -1) { ++ dprintk("%s - EXITING!\n", __FUNCTION__); ++ break; ++ } ++ cryptostats.cs_rets++; ++ } ++ } ++ CRYPTO_RETQ_UNLOCK(); ++ complete_and_exit(&cryptoretproc_exited, 0); ++} ++ ++ ++#if 0 /* should put this into /proc or something */ ++static void ++db_show_drivers(void) ++{ ++ int hid; ++ ++ db_printf("%12s %4s %4s %8s %2s %2s\n" ++ , "Device" ++ , "Ses" ++ , "Kops" ++ , "Flags" ++ , "QB" ++ , "KB" ++ ); ++ for (hid = 0; hid < crypto_drivers_num; hid++) { ++ const struct cryptocap *cap = &crypto_drivers[hid]; ++ if (cap->cc_dev == NULL) ++ continue; ++ db_printf("%-12s %4u %4u %08x %2u %2u\n" ++ , device_get_nameunit(cap->cc_dev) ++ , cap->cc_sessions ++ , cap->cc_koperations ++ , cap->cc_flags ++ , cap->cc_qblocked ++ , cap->cc_kqblocked ++ ); ++ } ++} ++ ++DB_SHOW_COMMAND(crypto, db_show_crypto) ++{ ++ struct cryptop *crp; ++ ++ db_show_drivers(); ++ db_printf("\n"); ++ ++ db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n", ++ "HID", "Caps", "Ilen", "Olen", "Etype", "Flags", ++ "Desc", "Callback"); ++ TAILQ_FOREACH(crp, &crp_q, crp_next) { ++ db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n" ++ , (int) CRYPTO_SESID2HID(crp->crp_sid) ++ , (int) CRYPTO_SESID2CAPS(crp->crp_sid) ++ , crp->crp_ilen, crp->crp_olen ++ , crp->crp_etype ++ , crp->crp_flags ++ , crp->crp_desc ++ , crp->crp_callback ++ ); ++ } ++ if (!TAILQ_EMPTY(&crp_ret_q)) { ++ db_printf("\n%4s %4s %4s %8s\n", ++ "HID", "Etype", "Flags", "Callback"); ++ TAILQ_FOREACH(crp, &crp_ret_q, crp_next) { ++ db_printf("%4u %4u %04x %8p\n" ++ , (int) CRYPTO_SESID2HID(crp->crp_sid) ++ , crp->crp_etype ++ , crp->crp_flags ++ , crp->crp_callback ++ ); ++ } ++ } ++} ++ ++DB_SHOW_COMMAND(kcrypto, db_show_kcrypto) ++{ ++ struct cryptkop *krp; ++ ++ db_show_drivers(); ++ db_printf("\n"); ++ ++ db_printf("%4s %5s %4s %4s %8s %4s %8s\n", ++ "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback"); ++ TAILQ_FOREACH(krp, &crp_kq, krp_next) { ++ db_printf("%4u %5u %4u %4u %08x %4u %8p\n" ++ , krp->krp_op ++ , krp->krp_status ++ , krp->krp_iparams, krp->krp_oparams ++ , krp->krp_crid, krp->krp_hid ++ , krp->krp_callback ++ ); ++ } ++ if (!TAILQ_EMPTY(&crp_ret_q)) { ++ db_printf("%4s %5s %8s %4s %8s\n", ++ "Op", "Status", "CRID", "HID", "Callback"); ++ TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) { ++ db_printf("%4u %5u %08x %4u %8p\n" ++ , krp->krp_op ++ , krp->krp_status ++ , krp->krp_crid, krp->krp_hid ++ , krp->krp_callback ++ ); ++ } ++ } ++} ++#endif ++ ++ ++static int ++crypto_init(void) ++{ ++ int error; ++ ++ dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init); ++ ++ if (crypto_initted) ++ return 0; ++ crypto_initted = 1; ++ ++ spin_lock_init(&crypto_drivers_lock); ++ spin_lock_init(&crypto_q_lock); ++ spin_lock_init(&crypto_ret_q_lock); ++ ++ cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop), ++ 0, SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ ++ cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc), ++ 0, SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ ++ if (cryptodesc_zone == NULL || cryptop_zone == NULL) { ++ printk("crypto: crypto_init cannot setup crypto zones\n"); ++ error = ENOMEM; ++ goto bad; ++ } ++ ++ crypto_drivers_num = CRYPTO_DRIVERS_INITIAL; ++ crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap), ++ GFP_KERNEL); ++ if (crypto_drivers == NULL) { ++ printk("crypto: crypto_init cannot setup crypto drivers\n"); ++ error = ENOMEM; ++ goto bad; ++ } ++ ++ memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap)); ++ ++ init_completion(&cryptoproc_exited); ++ init_completion(&cryptoretproc_exited); ++ ++ cryptoproc = 0; /* to avoid race condition where proc runs first */ ++ cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (cryptoproc < 0) { ++ error = cryptoproc; ++ printk("crypto: crypto_init cannot start crypto thread; error %d", ++ error); ++ goto bad; ++ } ++ ++ cryptoretproc = 0; /* to avoid race condition where proc runs first */ ++ cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (cryptoretproc < 0) { ++ error = cryptoretproc; ++ printk("crypto: crypto_init cannot start cryptoret thread; error %d", ++ error); ++ goto bad; ++ } ++ ++ return 0; ++bad: ++ crypto_exit(); ++ return error; ++} ++ ++ ++static void ++crypto_exit(void) ++{ ++ pid_t p; ++ unsigned long d_flags; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* ++ * Terminate any crypto threads. ++ */ ++ ++ CRYPTO_DRIVER_LOCK(); ++ p = cryptoproc; ++ cryptoproc = (pid_t) -1; ++ kill_pid(p, SIGTERM, 1); ++ wake_up_interruptible(&cryptoproc_wait); ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ wait_for_completion(&cryptoproc_exited); ++ ++ CRYPTO_DRIVER_LOCK(); ++ p = cryptoretproc; ++ cryptoretproc = (pid_t) -1; ++ kill_pid(p, SIGTERM, 1); ++ wake_up_interruptible(&cryptoretproc_wait); ++ CRYPTO_DRIVER_UNLOCK(); ++ ++ wait_for_completion(&cryptoretproc_exited); ++ ++ /* XXX flush queues??? */ ++ ++ /* ++ * Reclaim dynamically allocated resources. ++ */ ++ if (crypto_drivers != NULL) ++ kfree(crypto_drivers); ++ ++ if (cryptodesc_zone != NULL) ++ kmem_cache_destroy(cryptodesc_zone); ++ if (cryptop_zone != NULL) ++ kmem_cache_destroy(cryptop_zone); ++} ++ ++ ++EXPORT_SYMBOL(crypto_newsession); ++EXPORT_SYMBOL(crypto_freesession); ++EXPORT_SYMBOL(crypto_get_driverid); ++EXPORT_SYMBOL(crypto_kregister); ++EXPORT_SYMBOL(crypto_register); ++EXPORT_SYMBOL(crypto_unregister); ++EXPORT_SYMBOL(crypto_unregister_all); ++EXPORT_SYMBOL(crypto_unblock); ++EXPORT_SYMBOL(crypto_dispatch); ++EXPORT_SYMBOL(crypto_kdispatch); ++EXPORT_SYMBOL(crypto_freereq); ++EXPORT_SYMBOL(crypto_getreq); ++EXPORT_SYMBOL(crypto_done); ++EXPORT_SYMBOL(crypto_kdone); ++EXPORT_SYMBOL(crypto_getfeat); ++EXPORT_SYMBOL(crypto_userasymcrypto); ++EXPORT_SYMBOL(crypto_getcaps); ++EXPORT_SYMBOL(crypto_find_driver); ++EXPORT_SYMBOL(crypto_find_device_byhid); ++ ++module_init(crypto_init); ++module_exit(crypto_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptodev.c linux-2.6.30/crypto/ocf/cryptodev.c +--- linux-2.6.30.orig/crypto/ocf/cryptodev.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptodev.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1048 @@ ++/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ ++ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2001 Theo de Raadt ++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++extern asmlinkage long sys_dup(unsigned int fildes); ++ ++#define debug cryptodev_debug ++int cryptodev_debug = 0; ++module_param(cryptodev_debug, int, 0644); ++MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug"); ++ ++struct csession_info { ++ u_int16_t blocksize; ++ u_int16_t minkey, maxkey; ++ ++ u_int16_t keysize; ++ /* u_int16_t hashsize; */ ++ u_int16_t authsize; ++ /* u_int16_t ctxsize; */ ++}; ++ ++struct csession { ++ struct list_head list; ++ u_int64_t sid; ++ u_int32_t ses; ++ ++ wait_queue_head_t waitq; ++ ++ u_int32_t cipher; ++ ++ u_int32_t mac; ++ ++ caddr_t key; ++ int keylen; ++ u_char tmp_iv[EALG_MAX_BLOCK_LEN]; ++ ++ caddr_t mackey; ++ int mackeylen; ++ ++ struct csession_info info; ++ ++ struct iovec iovec; ++ struct uio uio; ++ int error; ++}; ++ ++struct fcrypt { ++ struct list_head csessions; ++ int sesn; ++}; ++ ++static struct csession *csefind(struct fcrypt *, u_int); ++static int csedelete(struct fcrypt *, struct csession *); ++static struct csession *cseadd(struct fcrypt *, struct csession *); ++static struct csession *csecreate(struct fcrypt *, u_int64_t, ++ struct cryptoini *crie, struct cryptoini *cria, struct csession_info *); ++static int csefree(struct csession *); ++ ++static int cryptodev_op(struct csession *, struct crypt_op *); ++static int cryptodev_key(struct crypt_kop *); ++static int cryptodev_find(struct crypt_find_op *); ++ ++static int cryptodev_cb(void *); ++static int cryptodev_open(struct inode *inode, struct file *filp); ++ ++/* ++ * Check a crypto identifier to see if it requested ++ * a valid crid and it's capabilities match. ++ */ ++static int ++checkcrid(int crid) ++{ ++ int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); ++ int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE); ++ int caps = 0; ++ ++ /* if the user hasn't selected a driver, then just call newsession */ ++ if (hid == 0 && typ != 0) ++ return 0; ++ ++ caps = crypto_getcaps(hid); ++ ++ /* didn't find anything with capabilities */ ++ if (caps == 0) { ++ dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ); ++ return EINVAL; ++ } ++ ++ /* the user didn't specify SW or HW, so the driver is ok */ ++ if (typ == 0) ++ return 0; ++ ++ /* if the type specified didn't match */ ++ if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) { ++ dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__, ++ hid, typ, caps); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++cryptodev_op(struct csession *cse, struct crypt_op *cop) ++{ ++ struct cryptop *crp = NULL; ++ struct cryptodesc *crde = NULL, *crda = NULL; ++ int error = 0; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (cop->len > CRYPTO_MAX_DATA_LEN) { ++ dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN); ++ return (E2BIG); ++ } ++ ++ if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) { ++ dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize, ++ cop->len); ++ return (EINVAL); ++ } ++ ++ cse->uio.uio_iov = &cse->iovec; ++ cse->uio.uio_iovcnt = 1; ++ cse->uio.uio_offset = 0; ++#if 0 ++ cse->uio.uio_resid = cop->len; ++ cse->uio.uio_segflg = UIO_SYSSPACE; ++ cse->uio.uio_rw = UIO_WRITE; ++ cse->uio.uio_td = td; ++#endif ++ cse->uio.uio_iov[0].iov_len = cop->len; ++ if (cse->info.authsize) ++ cse->uio.uio_iov[0].iov_len += cse->info.authsize; ++ cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len, ++ GFP_KERNEL); ++ ++ if (cse->uio.uio_iov[0].iov_base == NULL) { ++ dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__, ++ cse->uio.uio_iov[0].iov_len); ++ return (ENOMEM); ++ } ++ ++ crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0)); ++ if (crp == NULL) { ++ dprintk("%s: ENOMEM\n", __FUNCTION__); ++ error = ENOMEM; ++ goto bail; ++ } ++ ++ if (cse->info.authsize) { ++ crda = crp->crp_desc; ++ if (cse->info.blocksize) ++ crde = crda->crd_next; ++ } else { ++ if (cse->info.blocksize) ++ crde = crp->crp_desc; ++ else { ++ dprintk("%s: bad request\n", __FUNCTION__); ++ error = EINVAL; ++ goto bail; ++ } ++ } ++ ++ if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src, ++ cop->len))) { ++ dprintk("%s: bad copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (crda) { ++ crda->crd_skip = 0; ++ crda->crd_len = cop->len; ++ crda->crd_inject = cop->len; ++ ++ crda->crd_alg = cse->mac; ++ crda->crd_key = cse->mackey; ++ crda->crd_klen = cse->mackeylen * 8; ++ } ++ ++ if (crde) { ++ if (cop->op == COP_ENCRYPT) ++ crde->crd_flags |= CRD_F_ENCRYPT; ++ else ++ crde->crd_flags &= ~CRD_F_ENCRYPT; ++ crde->crd_len = cop->len; ++ crde->crd_inject = 0; ++ ++ crde->crd_alg = cse->cipher; ++ crde->crd_key = cse->key; ++ crde->crd_klen = cse->keylen * 8; ++ } ++ ++ crp->crp_ilen = cse->uio.uio_iov[0].iov_len; ++ crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM ++ | (cop->flags & COP_F_BATCH); ++ crp->crp_buf = (caddr_t)&cse->uio; ++ crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; ++ crp->crp_sid = cse->sid; ++ crp->crp_opaque = (void *)cse; ++ ++ if (cop->iv) { ++ if (crde == NULL) { ++ error = EINVAL; ++ dprintk("%s no crde\n", __FUNCTION__); ++ goto bail; ++ } ++ if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ ++ error = EINVAL; ++ dprintk("%s arc4 with IV\n", __FUNCTION__); ++ goto bail; ++ } ++ if ((error = copy_from_user(cse->tmp_iv, cop->iv, ++ cse->info.blocksize))) { ++ dprintk("%s bad iv copy\n", __FUNCTION__); ++ goto bail; ++ } ++ memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize); ++ crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; ++ crde->crd_skip = 0; ++ } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ ++ crde->crd_skip = 0; ++ } else if (crde) { ++ crde->crd_flags |= CRD_F_IV_PRESENT; ++ crde->crd_skip = cse->info.blocksize; ++ crde->crd_len -= cse->info.blocksize; ++ } ++ ++ if (cop->mac && crda == NULL) { ++ error = EINVAL; ++ dprintk("%s no crda\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ /* ++ * Let the dispatch run unlocked, then, interlock against the ++ * callback before checking if the operation completed and going ++ * to sleep. This insures drivers don't inherit our lock which ++ * results in a lock order reversal between crypto_dispatch forced ++ * entry and the crypto_done callback into us. ++ */ ++ error = crypto_dispatch(crp); ++ if (error == 0) { ++ dprintk("%s about to WAIT\n", __FUNCTION__); ++ /* ++ * we really need to wait for driver to complete to maintain ++ * state, luckily interrupts will be remembered ++ */ ++ do { ++ error = wait_event_interruptible(crp->crp_waitq, ++ ((crp->crp_flags & CRYPTO_F_DONE) != 0)); ++ /* ++ * we can't break out of this loop or we will leave behind ++ * a huge mess, however, staying here means if your driver ++ * is broken user applications can hang and not be killed. ++ * The solution, fix your driver :-) ++ */ ++ if (error) { ++ schedule(); ++ error = 0; ++ } ++ } while ((crp->crp_flags & CRYPTO_F_DONE) == 0); ++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); ++ } ++ ++ if (crp->crp_etype != 0) { ++ error = crp->crp_etype; ++ dprintk("%s error in crp processing\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cse->error) { ++ error = cse->error; ++ dprintk("%s error in cse processing\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cop->dst && (error = copy_to_user(cop->dst, ++ cse->uio.uio_iov[0].iov_base, cop->len))) { ++ dprintk("%s bad dst copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++ if (cop->mac && ++ (error=copy_to_user(cop->mac, ++ (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, ++ cse->info.authsize))) { ++ dprintk("%s bad mac copy\n", __FUNCTION__); ++ goto bail; ++ } ++ ++bail: ++ if (crp) ++ crypto_freereq(crp); ++ if (cse->uio.uio_iov[0].iov_base) ++ kfree(cse->uio.uio_iov[0].iov_base); ++ ++ return (error); ++} ++ ++static int ++cryptodev_cb(void *op) ++{ ++ struct cryptop *crp = (struct cryptop *) op; ++ struct csession *cse = (struct csession *)crp->crp_opaque; ++ int error; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ error = crp->crp_etype; ++ if (error == EAGAIN) { ++ crp->crp_flags &= ~CRYPTO_F_DONE; ++#ifdef NOTYET ++ /* ++ * DAVIDM I am fairly sure that we should turn this into a batch ++ * request to stop bad karma/lockup, revisit ++ */ ++ crp->crp_flags |= CRYPTO_F_BATCH; ++#endif ++ return crypto_dispatch(crp); ++ } ++ if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) { ++ cse->error = error; ++ wake_up_interruptible(&crp->crp_waitq); ++ } ++ return (0); ++} ++ ++static int ++cryptodevkey_cb(void *op) ++{ ++ struct cryptkop *krp = (struct cryptkop *) op; ++ dprintk("%s()\n", __FUNCTION__); ++ wake_up_interruptible(&krp->krp_waitq); ++ return (0); ++} ++ ++static int ++cryptodev_key(struct crypt_kop *kop) ++{ ++ struct cryptkop *krp = NULL; ++ int error = EINVAL; ++ int in, out, size, i; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { ++ dprintk("%s params too big\n", __FUNCTION__); ++ return (EFBIG); ++ } ++ ++ in = kop->crk_iparams; ++ out = kop->crk_oparams; ++ switch (kop->crk_op) { ++ case CRK_MOD_EXP: ++ if (in == 3 && out == 1) ++ break; ++ return (EINVAL); ++ case CRK_MOD_EXP_CRT: ++ if (in == 6 && out == 1) ++ break; ++ return (EINVAL); ++ case CRK_DSA_SIGN: ++ if (in == 5 && out == 2) ++ break; ++ return (EINVAL); ++ case CRK_DSA_VERIFY: ++ if (in == 7 && out == 0) ++ break; ++ return (EINVAL); ++ case CRK_DH_COMPUTE_KEY: ++ if (in == 3 && out == 1) ++ break; ++ return (EINVAL); ++ default: ++ return (EINVAL); ++ } ++ ++ krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL); ++ if (!krp) ++ return (ENOMEM); ++ bzero(krp, sizeof *krp); ++ krp->krp_op = kop->crk_op; ++ krp->krp_status = kop->crk_status; ++ krp->krp_iparams = kop->crk_iparams; ++ krp->krp_oparams = kop->crk_oparams; ++ krp->krp_crid = kop->crk_crid; ++ krp->krp_status = 0; ++ krp->krp_flags = CRYPTO_KF_CBIMM; ++ krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; ++ init_waitqueue_head(&krp->krp_waitq); ++ ++ for (i = 0; i < CRK_MAXPARAM; i++) ++ krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; ++ for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { ++ size = (krp->krp_param[i].crp_nbits + 7) / 8; ++ if (size == 0) ++ continue; ++ krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL); ++ if (i >= krp->krp_iparams) ++ continue; ++ error = copy_from_user(krp->krp_param[i].crp_p, ++ kop->crk_param[i].crp_p, size); ++ if (error) ++ goto fail; ++ } ++ ++ error = crypto_kdispatch(krp); ++ if (error) ++ goto fail; ++ ++ do { ++ error = wait_event_interruptible(krp->krp_waitq, ++ ((krp->krp_flags & CRYPTO_KF_DONE) != 0)); ++ /* ++ * we can't break out of this loop or we will leave behind ++ * a huge mess, however, staying here means if your driver ++ * is broken user applications can hang and not be killed. ++ * The solution, fix your driver :-) ++ */ ++ if (error) { ++ schedule(); ++ error = 0; ++ } ++ } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0); ++ ++ dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); ++ ++ kop->crk_crid = krp->krp_crid; /* device that did the work */ ++ if (krp->krp_status != 0) { ++ error = krp->krp_status; ++ goto fail; ++ } ++ ++ for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { ++ size = (krp->krp_param[i].crp_nbits + 7) / 8; ++ if (size == 0) ++ continue; ++ error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, ++ size); ++ if (error) ++ goto fail; ++ } ++ ++fail: ++ if (krp) { ++ kop->crk_status = krp->krp_status; ++ for (i = 0; i < CRK_MAXPARAM; i++) { ++ if (krp->krp_param[i].crp_p) ++ kfree(krp->krp_param[i].crp_p); ++ } ++ kfree(krp); ++ } ++ return (error); ++} ++ ++static int ++cryptodev_find(struct crypt_find_op *find) ++{ ++ device_t dev; ++ ++ if (find->crid != -1) { ++ dev = crypto_find_device_byhid(find->crid); ++ if (dev == NULL) ++ return (ENOENT); ++ strlcpy(find->name, device_get_nameunit(dev), ++ sizeof(find->name)); ++ } else { ++ find->crid = crypto_find_driver(find->name); ++ if (find->crid == -1) ++ return (ENOENT); ++ } ++ return (0); ++} ++ ++static struct csession * ++csefind(struct fcrypt *fcr, u_int ses) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ list_for_each_entry(cse, &fcr->csessions, list) ++ if (cse->ses == ses) ++ return (cse); ++ return (NULL); ++} ++ ++static int ++csedelete(struct fcrypt *fcr, struct csession *cse_del) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ list_for_each_entry(cse, &fcr->csessions, list) { ++ if (cse == cse_del) { ++ list_del(&cse->list); ++ return (1); ++ } ++ } ++ return (0); ++} ++ ++static struct csession * ++cseadd(struct fcrypt *fcr, struct csession *cse) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ list_add_tail(&cse->list, &fcr->csessions); ++ cse->ses = fcr->sesn++; ++ return (cse); ++} ++ ++static struct csession * ++csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie, ++ struct cryptoini *cria, struct csession_info *info) ++{ ++ struct csession *cse; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL); ++ if (cse == NULL) ++ return NULL; ++ memset(cse, 0, sizeof(struct csession)); ++ ++ INIT_LIST_HEAD(&cse->list); ++ init_waitqueue_head(&cse->waitq); ++ ++ cse->key = crie->cri_key; ++ cse->keylen = crie->cri_klen/8; ++ cse->mackey = cria->cri_key; ++ cse->mackeylen = cria->cri_klen/8; ++ cse->sid = sid; ++ cse->cipher = crie->cri_alg; ++ cse->mac = cria->cri_alg; ++ cse->info = *info; ++ cseadd(fcr, cse); ++ return (cse); ++} ++ ++static int ++csefree(struct csession *cse) ++{ ++ int error; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ error = crypto_freesession(cse->sid); ++ if (cse->key) ++ kfree(cse->key); ++ if (cse->mackey) ++ kfree(cse->mackey); ++ kfree(cse); ++ return(error); ++} ++ ++static int ++cryptodev_ioctl( ++ struct inode *inode, ++ struct file *filp, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ struct cryptoini cria, crie; ++ struct fcrypt *fcr = filp->private_data; ++ struct csession *cse; ++ struct csession_info info; ++ struct session2_op sop; ++ struct crypt_op cop; ++ struct crypt_kop kop; ++ struct crypt_find_op fop; ++ u_int64_t sid; ++ u_int32_t ses; ++ int feat, fd, error = 0, crid; ++ mm_segment_t fs; ++ ++ dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg); ++ ++ switch (cmd) { ++ ++ case CRIOGET: { ++ dprintk("%s(CRIOGET)\n", __FUNCTION__); ++ fs = get_fs(); ++ set_fs(get_ds()); ++ for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++) ++ if (files_fdtable(current->files)->fd[fd] == filp) ++ break; ++ fd = sys_dup(fd); ++ set_fs(fs); ++ put_user(fd, (int *) arg); ++ return IS_ERR_VALUE(fd) ? fd : 0; ++ } ++ ++#define CIOCGSESSSTR (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2") ++ case CIOCGSESSION: ++ case CIOCGSESSION2: ++ dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR); ++ memset(&crie, 0, sizeof(crie)); ++ memset(&cria, 0, sizeof(cria)); ++ memset(&info, 0, sizeof(info)); ++ memset(&sop, 0, sizeof(sop)); ++ ++ if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ? ++ sizeof(struct session_op) : sizeof(sop))) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ ++ switch (sop.cipher) { ++ case 0: ++ dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR); ++ break; ++ case CRYPTO_NULL_CBC: ++ info.blocksize = NULL_BLOCK_LEN; ++ info.minkey = NULL_MIN_KEY_LEN; ++ info.maxkey = NULL_MAX_KEY_LEN; ++ break; ++ case CRYPTO_DES_CBC: ++ info.blocksize = DES_BLOCK_LEN; ++ info.minkey = DES_MIN_KEY_LEN; ++ info.maxkey = DES_MAX_KEY_LEN; ++ break; ++ case CRYPTO_3DES_CBC: ++ info.blocksize = DES3_BLOCK_LEN; ++ info.minkey = DES3_MIN_KEY_LEN; ++ info.maxkey = DES3_MAX_KEY_LEN; ++ break; ++ case CRYPTO_BLF_CBC: ++ info.blocksize = BLOWFISH_BLOCK_LEN; ++ info.minkey = BLOWFISH_MIN_KEY_LEN; ++ info.maxkey = BLOWFISH_MAX_KEY_LEN; ++ break; ++ case CRYPTO_CAST_CBC: ++ info.blocksize = CAST128_BLOCK_LEN; ++ info.minkey = CAST128_MIN_KEY_LEN; ++ info.maxkey = CAST128_MAX_KEY_LEN; ++ break; ++ case CRYPTO_SKIPJACK_CBC: ++ info.blocksize = SKIPJACK_BLOCK_LEN; ++ info.minkey = SKIPJACK_MIN_KEY_LEN; ++ info.maxkey = SKIPJACK_MAX_KEY_LEN; ++ break; ++ case CRYPTO_AES_CBC: ++ info.blocksize = AES_BLOCK_LEN; ++ info.minkey = AES_MIN_KEY_LEN; ++ info.maxkey = AES_MAX_KEY_LEN; ++ break; ++ case CRYPTO_ARC4: ++ info.blocksize = ARC4_BLOCK_LEN; ++ info.minkey = ARC4_MIN_KEY_LEN; ++ info.maxkey = ARC4_MAX_KEY_LEN; ++ break; ++ case CRYPTO_CAMELLIA_CBC: ++ info.blocksize = CAMELLIA_BLOCK_LEN; ++ info.minkey = CAMELLIA_MIN_KEY_LEN; ++ info.maxkey = CAMELLIA_MAX_KEY_LEN; ++ break; ++ default: ++ dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ switch (sop.mac) { ++ case 0: ++ dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR); ++ break; ++ case CRYPTO_NULL_HMAC: ++ info.authsize = NULL_HASH_LEN; ++ break; ++ case CRYPTO_MD5: ++ info.authsize = MD5_HASH_LEN; ++ break; ++ case CRYPTO_SHA1: ++ info.authsize = SHA1_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_256: ++ info.authsize = SHA2_256_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_384: ++ info.authsize = SHA2_384_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_512: ++ info.authsize = SHA2_512_HASH_LEN; ++ break; ++ case CRYPTO_RIPEMD160: ++ info.authsize = RIPEMD160_HASH_LEN; ++ break; ++ case CRYPTO_MD5_HMAC: ++ info.authsize = MD5_HASH_LEN; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ info.authsize = SHA1_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_256_HMAC: ++ info.authsize = SHA2_256_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_384_HMAC: ++ info.authsize = SHA2_384_HASH_LEN; ++ break; ++ case CRYPTO_SHA2_512_HMAC: ++ info.authsize = SHA2_512_HASH_LEN; ++ break; ++ case CRYPTO_RIPEMD160_HMAC: ++ info.authsize = RIPEMD160_HASH_LEN; ++ break; ++ default: ++ dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ if (info.blocksize) { ++ crie.cri_alg = sop.cipher; ++ crie.cri_klen = sop.keylen * 8; ++ if ((info.maxkey && sop.keylen > info.maxkey) || ++ sop.keylen < info.minkey) { ++ dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL); ++ if (copy_from_user(crie.cri_key, sop.key, ++ crie.cri_klen/8)) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ if (info.authsize) ++ crie.cri_next = &cria; ++ } ++ ++ if (info.authsize) { ++ cria.cri_alg = sop.mac; ++ cria.cri_klen = sop.mackeylen * 8; ++ if ((info.maxkey && sop.mackeylen > info.maxkey) || ++ sop.keylen < info.minkey) { ++ dprintk("%s(%s) - mackeylen %d\n", __FUNCTION__, CIOCGSESSSTR, ++ sop.mackeylen); ++ error = EINVAL; ++ goto bail; ++ } ++ ++ if (cria.cri_klen) { ++ cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL); ++ if (copy_from_user(cria.cri_key, sop.mackey, ++ cria.cri_klen / 8)) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ goto bail; ++ } ++ } ++ } ++ ++ /* NB: CIOGSESSION2 has the crid */ ++ if (cmd == CIOCGSESSION2) { ++ crid = sop.crid; ++ error = checkcrid(crid); ++ if (error) { ++ dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__, ++ CIOCGSESSSTR, error); ++ goto bail; ++ } ++ } else { ++ /* allow either HW or SW to be used */ ++ crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; ++ } ++ error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid); ++ if (error) { ++ dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error); ++ goto bail; ++ } ++ ++ cse = csecreate(fcr, sid, &crie, &cria, &info); ++ if (cse == NULL) { ++ crypto_freesession(sid); ++ error = EINVAL; ++ dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR); ++ goto bail; ++ } ++ sop.ses = cse->ses; ++ ++ if (cmd == CIOCGSESSION2) { ++ /* return hardware/driver id */ ++ sop.crid = CRYPTO_SESID2HID(cse->sid); ++ } ++ ++ if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ? ++ sizeof(struct session_op) : sizeof(sop))) { ++ dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR); ++ error = EFAULT; ++ } ++bail: ++ if (error) { ++ dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error); ++ if (crie.cri_key) ++ kfree(crie.cri_key); ++ if (cria.cri_key) ++ kfree(cria.cri_key); ++ } ++ break; ++ case CIOCFSESSION: ++ dprintk("%s(CIOCFSESSION)\n", __FUNCTION__); ++ get_user(ses, (uint32_t*)arg); ++ cse = csefind(fcr, ses); ++ if (cse == NULL) { ++ error = EINVAL; ++ dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error); ++ break; ++ } ++ csedelete(fcr, cse); ++ error = csefree(cse); ++ break; ++ case CIOCCRYPT: ++ dprintk("%s(CIOCCRYPT)\n", __FUNCTION__); ++ if(copy_from_user(&cop, (void*)arg, sizeof(cop))) { ++ dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ cse = csefind(fcr, cop.ses); ++ if (cse == NULL) { ++ error = EINVAL; ++ dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error); ++ break; ++ } ++ error = cryptodev_op(cse, &cop); ++ if(copy_to_user((void*)arg, &cop, sizeof(cop))) { ++ dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ case CIOCKEY: ++ case CIOCKEY2: ++ dprintk("%s(CIOCKEY)\n", __FUNCTION__); ++ if (!crypto_userasymcrypto) ++ return (EPERM); /* XXX compat? */ ++ if(copy_from_user(&kop, (void*)arg, sizeof(kop))) { ++ dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ if (cmd == CIOCKEY) { ++ /* NB: crypto core enforces s/w driver use */ ++ kop.crk_crid = ++ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; ++ } ++ error = cryptodev_key(&kop); ++ if(copy_to_user((void*)arg, &kop, sizeof(kop))) { ++ dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ case CIOCASYMFEAT: ++ dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__); ++ if (!crypto_userasymcrypto) { ++ /* ++ * NB: if user asym crypto operations are ++ * not permitted return "no algorithms" ++ * so well-behaved applications will just ++ * fallback to doing them in software. ++ */ ++ feat = 0; ++ } else ++ error = crypto_getfeat(&feat); ++ if (!error) { ++ error = copy_to_user((void*)arg, &feat, sizeof(feat)); ++ } ++ break; ++ case CIOCFINDDEV: ++ if (copy_from_user(&fop, (void*)arg, sizeof(fop))) { ++ dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ error = cryptodev_find(&fop); ++ if (copy_to_user((void*)arg, &fop, sizeof(fop))) { ++ dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__); ++ error = EFAULT; ++ goto bail; ++ } ++ break; ++ default: ++ dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd); ++ error = EINVAL; ++ break; ++ } ++ return(-error); ++} ++ ++#ifdef HAVE_UNLOCKED_IOCTL ++static long ++cryptodev_unlocked_ioctl( ++ struct file *filp, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ return cryptodev_ioctl(NULL, filp, cmd, arg); ++} ++#endif ++ ++static int ++cryptodev_open(struct inode *inode, struct file *filp) ++{ ++ struct fcrypt *fcr; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (filp->private_data) { ++ printk("cryptodev: Private data already exists !\n"); ++ return(0); ++ } ++ ++ fcr = kmalloc(sizeof(*fcr), GFP_KERNEL); ++ if (!fcr) { ++ dprintk("%s() - malloc failed\n", __FUNCTION__); ++ return(-ENOMEM); ++ } ++ memset(fcr, 0, sizeof(*fcr)); ++ ++ INIT_LIST_HEAD(&fcr->csessions); ++ filp->private_data = fcr; ++ return(0); ++} ++ ++static int ++cryptodev_release(struct inode *inode, struct file *filp) ++{ ++ struct fcrypt *fcr = filp->private_data; ++ struct csession *cse, *tmp; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (!filp) { ++ printk("cryptodev: No private data on release\n"); ++ return(0); ++ } ++ ++ list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) { ++ list_del(&cse->list); ++ (void)csefree(cse); ++ } ++ filp->private_data = NULL; ++ kfree(fcr); ++ return(0); ++} ++ ++static struct file_operations cryptodev_fops = { ++ .owner = THIS_MODULE, ++ .open = cryptodev_open, ++ .release = cryptodev_release, ++ .ioctl = cryptodev_ioctl, ++#ifdef HAVE_UNLOCKED_IOCTL ++ .unlocked_ioctl = cryptodev_unlocked_ioctl, ++#endif ++}; ++ ++static struct miscdevice cryptodev = { ++ .minor = CRYPTODEV_MINOR, ++ .name = "crypto", ++ .fops = &cryptodev_fops, ++}; ++ ++static int __init ++cryptodev_init(void) ++{ ++ int rc; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init); ++ rc = misc_register(&cryptodev); ++ if (rc) { ++ printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n"); ++ return(rc); ++ } ++ ++ return(0); ++} ++ ++static void __exit ++cryptodev_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ misc_deregister(&cryptodev); ++} ++ ++module_init(cryptodev_init); ++module_exit(cryptodev_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Cryptodev (user interface to OCF)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptodev.h linux-2.6.30/crypto/ocf/cryptodev.h +--- linux-2.6.30.orig/crypto/ocf/cryptodev.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptodev.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,478 @@ ++/* $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $ */ ++/* $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $ */ ++ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting ++ * ++ * This code was written by Angelos D. Keromytis in Athens, Greece, in ++ * February 2000. Network Security Technologies Inc. (NSTI) kindly ++ * supported the development of this code. ++ * ++ * Copyright (c) 2000 Angelos D. Keromytis ++ * ++ * Permission to use, copy, and modify this software with or without fee ++ * is hereby granted, provided that this entire notice is included in ++ * all source code copies of any software which is or includes a copy or ++ * modification of this software. ++ * ++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY ++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE ++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR ++ * PURPOSE. ++ * ++ * Copyright (c) 2001 Theo de Raadt ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++ ++#ifndef _CRYPTO_CRYPTO_H_ ++#define _CRYPTO_CRYPTO_H_ ++ ++/* Some initial values */ ++#define CRYPTO_DRIVERS_INITIAL 4 ++#define CRYPTO_SW_SESSIONS 32 ++ ++/* Hash values */ ++#define NULL_HASH_LEN 0 ++#define MD5_HASH_LEN 16 ++#define SHA1_HASH_LEN 20 ++#define RIPEMD160_HASH_LEN 20 ++#define SHA2_256_HASH_LEN 32 ++#define SHA2_384_HASH_LEN 48 ++#define SHA2_512_HASH_LEN 64 ++#define MD5_KPDK_HASH_LEN 16 ++#define SHA1_KPDK_HASH_LEN 20 ++/* Maximum hash algorithm result length */ ++#define HASH_MAX_LEN SHA2_512_HASH_LEN /* Keep this updated */ ++ ++/* HMAC values */ ++#define NULL_HMAC_BLOCK_LEN 1 ++#define MD5_HMAC_BLOCK_LEN 64 ++#define SHA1_HMAC_BLOCK_LEN 64 ++#define RIPEMD160_HMAC_BLOCK_LEN 64 ++#define SHA2_256_HMAC_BLOCK_LEN 64 ++#define SHA2_384_HMAC_BLOCK_LEN 128 ++#define SHA2_512_HMAC_BLOCK_LEN 128 ++/* Maximum HMAC block length */ ++#define HMAC_MAX_BLOCK_LEN SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */ ++#define HMAC_IPAD_VAL 0x36 ++#define HMAC_OPAD_VAL 0x5C ++ ++/* Encryption algorithm block sizes */ ++#define NULL_BLOCK_LEN 1 ++#define DES_BLOCK_LEN 8 ++#define DES3_BLOCK_LEN 8 ++#define BLOWFISH_BLOCK_LEN 8 ++#define SKIPJACK_BLOCK_LEN 8 ++#define CAST128_BLOCK_LEN 8 ++#define RIJNDAEL128_BLOCK_LEN 16 ++#define AES_BLOCK_LEN RIJNDAEL128_BLOCK_LEN ++#define CAMELLIA_BLOCK_LEN 16 ++#define ARC4_BLOCK_LEN 1 ++#define EALG_MAX_BLOCK_LEN AES_BLOCK_LEN /* Keep this updated */ ++ ++/* Encryption algorithm min and max key sizes */ ++#define NULL_MIN_KEY_LEN 0 ++#define NULL_MAX_KEY_LEN 0 ++#define DES_MIN_KEY_LEN 8 ++#define DES_MAX_KEY_LEN 8 ++#define DES3_MIN_KEY_LEN 24 ++#define DES3_MAX_KEY_LEN 24 ++#define BLOWFISH_MIN_KEY_LEN 4 ++#define BLOWFISH_MAX_KEY_LEN 56 ++#define SKIPJACK_MIN_KEY_LEN 10 ++#define SKIPJACK_MAX_KEY_LEN 10 ++#define CAST128_MIN_KEY_LEN 5 ++#define CAST128_MAX_KEY_LEN 16 ++#define RIJNDAEL128_MIN_KEY_LEN 16 ++#define RIJNDAEL128_MAX_KEY_LEN 32 ++#define AES_MIN_KEY_LEN RIJNDAEL128_MIN_KEY_LEN ++#define AES_MAX_KEY_LEN RIJNDAEL128_MAX_KEY_LEN ++#define CAMELLIA_MIN_KEY_LEN 16 ++#define CAMELLIA_MAX_KEY_LEN 32 ++#define ARC4_MIN_KEY_LEN 1 ++#define ARC4_MAX_KEY_LEN 256 ++ ++/* Max size of data that can be processed */ ++#define CRYPTO_MAX_DATA_LEN 64*1024 - 1 ++ ++#define CRYPTO_ALGORITHM_MIN 1 ++#define CRYPTO_DES_CBC 1 ++#define CRYPTO_3DES_CBC 2 ++#define CRYPTO_BLF_CBC 3 ++#define CRYPTO_CAST_CBC 4 ++#define CRYPTO_SKIPJACK_CBC 5 ++#define CRYPTO_MD5_HMAC 6 ++#define CRYPTO_SHA1_HMAC 7 ++#define CRYPTO_RIPEMD160_HMAC 8 ++#define CRYPTO_MD5_KPDK 9 ++#define CRYPTO_SHA1_KPDK 10 ++#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */ ++#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */ ++#define CRYPTO_ARC4 12 ++#define CRYPTO_MD5 13 ++#define CRYPTO_SHA1 14 ++#define CRYPTO_NULL_HMAC 15 ++#define CRYPTO_NULL_CBC 16 ++#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression algorithm */ ++#define CRYPTO_SHA2_256_HMAC 18 ++#define CRYPTO_SHA2_384_HMAC 19 ++#define CRYPTO_SHA2_512_HMAC 20 ++#define CRYPTO_CAMELLIA_CBC 21 ++#define CRYPTO_SHA2_256 22 ++#define CRYPTO_SHA2_384 23 ++#define CRYPTO_SHA2_512 24 ++#define CRYPTO_RIPEMD160 25 ++#define CRYPTO_ALGORITHM_MAX 25 /* Keep updated - see below */ ++ ++/* Algorithm flags */ ++#define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ ++#define CRYPTO_ALG_FLAG_RNG_ENABLE 0x02 /* Has HW RNG for DH/DSA */ ++#define CRYPTO_ALG_FLAG_DSA_SHA 0x04 /* Can do SHA on msg */ ++ ++/* ++ * Crypto driver/device flags. They can set in the crid ++ * parameter when creating a session or submitting a key ++ * op to affect the device/driver assigned. If neither ++ * of these are specified then the crid is assumed to hold ++ * the driver id of an existing (and suitable) device that ++ * must be used to satisfy the request. ++ */ ++#define CRYPTO_FLAG_HARDWARE 0x01000000 /* hardware accelerated */ ++#define CRYPTO_FLAG_SOFTWARE 0x02000000 /* software implementation */ ++ ++/* NB: deprecated */ ++struct session_op { ++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ ++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ ++ ++ u_int32_t keylen; /* cipher key */ ++ caddr_t key; ++ int mackeylen; /* mac key */ ++ caddr_t mackey; ++ ++ u_int32_t ses; /* returns: session # */ ++}; ++ ++struct session2_op { ++ u_int32_t cipher; /* ie. CRYPTO_DES_CBC */ ++ u_int32_t mac; /* ie. CRYPTO_MD5_HMAC */ ++ ++ u_int32_t keylen; /* cipher key */ ++ caddr_t key; ++ int mackeylen; /* mac key */ ++ caddr_t mackey; ++ ++ u_int32_t ses; /* returns: session # */ ++ int crid; /* driver id + flags (rw) */ ++ int pad[4]; /* for future expansion */ ++}; ++ ++struct crypt_op { ++ u_int32_t ses; ++ u_int16_t op; /* i.e. COP_ENCRYPT */ ++#define COP_NONE 0 ++#define COP_ENCRYPT 1 ++#define COP_DECRYPT 2 ++ u_int16_t flags; ++#define COP_F_BATCH 0x0008 /* Batch op if possible */ ++ u_int len; ++ caddr_t src, dst; /* become iov[] inside kernel */ ++ caddr_t mac; /* must be big enough for chosen MAC */ ++ caddr_t iv; ++}; ++ ++/* ++ * Parameters for looking up a crypto driver/device by ++ * device name or by id. The latter are returned for ++ * created sessions (crid) and completed key operations. ++ */ ++struct crypt_find_op { ++ int crid; /* driver id + flags */ ++ char name[32]; /* device/driver name */ ++}; ++ ++/* bignum parameter, in packed bytes, ... */ ++struct crparam { ++ caddr_t crp_p; ++ u_int crp_nbits; ++}; ++ ++#define CRK_MAXPARAM 8 ++ ++struct crypt_kop { ++ u_int crk_op; /* ie. CRK_MOD_EXP or other */ ++ u_int crk_status; /* return status */ ++ u_short crk_iparams; /* # of input parameters */ ++ u_short crk_oparams; /* # of output parameters */ ++ u_int crk_crid; /* NB: only used by CIOCKEY2 (rw) */ ++ struct crparam crk_param[CRK_MAXPARAM]; ++}; ++#define CRK_ALGORITM_MIN 0 ++#define CRK_MOD_EXP 0 ++#define CRK_MOD_EXP_CRT 1 ++#define CRK_DSA_SIGN 2 ++#define CRK_DSA_VERIFY 3 ++#define CRK_DH_COMPUTE_KEY 4 ++#define CRK_ALGORITHM_MAX 4 /* Keep updated - see below */ ++ ++#define CRF_MOD_EXP (1 << CRK_MOD_EXP) ++#define CRF_MOD_EXP_CRT (1 << CRK_MOD_EXP_CRT) ++#define CRF_DSA_SIGN (1 << CRK_DSA_SIGN) ++#define CRF_DSA_VERIFY (1 << CRK_DSA_VERIFY) ++#define CRF_DH_COMPUTE_KEY (1 << CRK_DH_COMPUTE_KEY) ++ ++/* ++ * done against open of /dev/crypto, to get a cloned descriptor. ++ * Please use F_SETFD against the cloned descriptor. ++ */ ++#define CRIOGET _IOWR('c', 100, u_int32_t) ++#define CRIOASYMFEAT CIOCASYMFEAT ++#define CRIOFINDDEV CIOCFINDDEV ++ ++/* the following are done against the cloned descriptor */ ++#define CIOCGSESSION _IOWR('c', 101, struct session_op) ++#define CIOCFSESSION _IOW('c', 102, u_int32_t) ++#define CIOCCRYPT _IOWR('c', 103, struct crypt_op) ++#define CIOCKEY _IOWR('c', 104, struct crypt_kop) ++#define CIOCASYMFEAT _IOR('c', 105, u_int32_t) ++#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op) ++#define CIOCKEY2 _IOWR('c', 107, struct crypt_kop) ++#define CIOCFINDDEV _IOWR('c', 108, struct crypt_find_op) ++ ++struct cryptotstat { ++ struct timespec acc; /* total accumulated time */ ++ struct timespec min; /* min time */ ++ struct timespec max; /* max time */ ++ u_int32_t count; /* number of observations */ ++}; ++ ++struct cryptostats { ++ u_int32_t cs_ops; /* symmetric crypto ops submitted */ ++ u_int32_t cs_errs; /* symmetric crypto ops that failed */ ++ u_int32_t cs_kops; /* asymetric/key ops submitted */ ++ u_int32_t cs_kerrs; /* asymetric/key ops that failed */ ++ u_int32_t cs_intrs; /* crypto swi thread activations */ ++ u_int32_t cs_rets; /* crypto return thread activations */ ++ u_int32_t cs_blocks; /* symmetric op driver block */ ++ u_int32_t cs_kblocks; /* symmetric op driver block */ ++ /* ++ * When CRYPTO_TIMING is defined at compile time and the ++ * sysctl debug.crypto is set to 1, the crypto system will ++ * accumulate statistics about how long it takes to process ++ * crypto requests at various points during processing. ++ */ ++ struct cryptotstat cs_invoke; /* crypto_dipsatch -> crypto_invoke */ ++ struct cryptotstat cs_done; /* crypto_invoke -> crypto_done */ ++ struct cryptotstat cs_cb; /* crypto_done -> callback */ ++ struct cryptotstat cs_finis; /* callback -> callback return */ ++ ++ u_int32_t cs_drops; /* crypto ops dropped due to congestion */ ++}; ++ ++#ifdef __KERNEL__ ++ ++/* Standard initialization structure beginning */ ++struct cryptoini { ++ int cri_alg; /* Algorithm to use */ ++ int cri_klen; /* Key length, in bits */ ++ int cri_mlen; /* Number of bytes we want from the ++ entire hash. 0 means all. */ ++ caddr_t cri_key; /* key to use */ ++ u_int8_t cri_iv[EALG_MAX_BLOCK_LEN]; /* IV to use */ ++ struct cryptoini *cri_next; ++}; ++ ++/* Describe boundaries of a single crypto operation */ ++struct cryptodesc { ++ int crd_skip; /* How many bytes to ignore from start */ ++ int crd_len; /* How many bytes to process */ ++ int crd_inject; /* Where to inject results, if applicable */ ++ int crd_flags; ++ ++#define CRD_F_ENCRYPT 0x01 /* Set when doing encryption */ ++#define CRD_F_IV_PRESENT 0x02 /* When encrypting, IV is already in ++ place, so don't copy. */ ++#define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */ ++#define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */ ++#define CRD_F_KEY_EXPLICIT 0x10 /* Key explicitly provided */ ++#define CRD_F_COMP 0x0f /* Set when doing compression */ ++ ++ struct cryptoini CRD_INI; /* Initialization/context data */ ++#define crd_iv CRD_INI.cri_iv ++#define crd_key CRD_INI.cri_key ++#define crd_alg CRD_INI.cri_alg ++#define crd_klen CRD_INI.cri_klen ++ ++ struct cryptodesc *crd_next; ++}; ++ ++/* Structure describing complete operation */ ++struct cryptop { ++ struct list_head crp_next; ++ wait_queue_head_t crp_waitq; ++ ++ u_int64_t crp_sid; /* Session ID */ ++ int crp_ilen; /* Input data total length */ ++ int crp_olen; /* Result total length */ ++ ++ int crp_etype; /* ++ * Error type (zero means no error). ++ * All error codes except EAGAIN ++ * indicate possible data corruption (as in, ++ * the data have been touched). On all ++ * errors, the crp_sid may have changed ++ * (reset to a new one), so the caller ++ * should always check and use the new ++ * value on future requests. ++ */ ++ int crp_flags; ++ ++#define CRYPTO_F_SKBUF 0x0001 /* Input/output are skbuf chains */ ++#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ ++#define CRYPTO_F_REL 0x0004 /* Must return data in same place */ ++#define CRYPTO_F_BATCH 0x0008 /* Batch op if possible */ ++#define CRYPTO_F_CBIMM 0x0010 /* Do callback immediately */ ++#define CRYPTO_F_DONE 0x0020 /* Operation completed */ ++#define CRYPTO_F_CBIFSYNC 0x0040 /* Do CBIMM if op is synchronous */ ++ ++ caddr_t crp_buf; /* Data to be processed */ ++ caddr_t crp_opaque; /* Opaque pointer, passed along */ ++ struct cryptodesc *crp_desc; /* Linked list of processing descriptors */ ++ ++ int (*crp_callback)(struct cryptop *); /* Callback function */ ++}; ++ ++#define CRYPTO_BUF_CONTIG 0x0 ++#define CRYPTO_BUF_IOV 0x1 ++#define CRYPTO_BUF_SKBUF 0x2 ++ ++#define CRYPTO_OP_DECRYPT 0x0 ++#define CRYPTO_OP_ENCRYPT 0x1 ++ ++/* ++ * Hints passed to process methods. ++ */ ++#define CRYPTO_HINT_MORE 0x1 /* more ops coming shortly */ ++ ++struct cryptkop { ++ struct list_head krp_next; ++ wait_queue_head_t krp_waitq; ++ ++ int krp_flags; ++#define CRYPTO_KF_DONE 0x0001 /* Operation completed */ ++#define CRYPTO_KF_CBIMM 0x0002 /* Do callback immediately */ ++ ++ u_int krp_op; /* ie. CRK_MOD_EXP or other */ ++ u_int krp_status; /* return status */ ++ u_short krp_iparams; /* # of input parameters */ ++ u_short krp_oparams; /* # of output parameters */ ++ u_int krp_crid; /* desired device, etc. */ ++ u_int32_t krp_hid; ++ struct crparam krp_param[CRK_MAXPARAM]; /* kvm */ ++ int (*krp_callback)(struct cryptkop *); ++}; ++ ++#include ++ ++/* ++ * Session ids are 64 bits. The lower 32 bits contain a "local id" which ++ * is a driver-private session identifier. The upper 32 bits contain a ++ * "hardware id" used by the core crypto code to identify the driver and ++ * a copy of the driver's capabilities that can be used by client code to ++ * optimize operation. ++ */ ++#define CRYPTO_SESID2HID(_sid) (((_sid) >> 32) & 0x00ffffff) ++#define CRYPTO_SESID2CAPS(_sid) (((_sid) >> 32) & 0xff000000) ++#define CRYPTO_SESID2LID(_sid) (((u_int32_t) (_sid)) & 0xffffffff) ++ ++extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard); ++extern int crypto_freesession(u_int64_t sid); ++#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE ++#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE ++#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */ ++extern int32_t crypto_get_driverid(device_t dev, int flags); ++extern int crypto_find_driver(const char *); ++extern device_t crypto_find_device_byhid(int hid); ++extern int crypto_getcaps(int hid); ++extern int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen, ++ u_int32_t flags); ++extern int crypto_kregister(u_int32_t, int, u_int32_t); ++extern int crypto_unregister(u_int32_t driverid, int alg); ++extern int crypto_unregister_all(u_int32_t driverid); ++extern int crypto_dispatch(struct cryptop *crp); ++extern int crypto_kdispatch(struct cryptkop *); ++#define CRYPTO_SYMQ 0x1 ++#define CRYPTO_ASYMQ 0x2 ++extern int crypto_unblock(u_int32_t, int); ++extern void crypto_done(struct cryptop *crp); ++extern void crypto_kdone(struct cryptkop *); ++extern int crypto_getfeat(int *); ++ ++extern void crypto_freereq(struct cryptop *crp); ++extern struct cryptop *crypto_getreq(int num); ++ ++extern int crypto_usercrypto; /* userland may do crypto requests */ ++extern int crypto_userasymcrypto; /* userland may do asym crypto reqs */ ++extern int crypto_devallowsoft; /* only use hardware crypto */ ++ ++/* ++ * random number support, crypto_unregister_all will unregister ++ */ ++extern int crypto_rregister(u_int32_t driverid, ++ int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg); ++extern int crypto_runregister_all(u_int32_t driverid); ++ ++/* ++ * Crypto-related utility routines used mainly by drivers. ++ * ++ * XXX these don't really belong here; but for now they're ++ * kept apart from the rest of the system. ++ */ ++struct uio; ++extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp); ++extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp); ++extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off); ++ ++extern void crypto_copyback(int flags, caddr_t buf, int off, int size, ++ caddr_t in); ++extern void crypto_copydata(int flags, caddr_t buf, int off, int size, ++ caddr_t out); ++extern int crypto_apply(int flags, caddr_t buf, int off, int len, ++ int (*f)(void *, void *, u_int), void *arg); ++ ++#endif /* __KERNEL__ */ ++#endif /* _CRYPTO_CRYPTO_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/cryptosoft.c linux-2.6.30/crypto/ocf/cryptosoft.c +--- linux-2.6.30.orig/crypto/ocf/cryptosoft.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/cryptosoft.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,898 @@ ++/* ++ * An OCF module that uses the linux kernel cryptoapi, based on the ++ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu) ++ * but is mostly unrecognisable, ++ * ++ * Written by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ * --------------------------------------------------------------------------- ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct { ++ softc_device_decl sc_dev; ++} swcr_softc; ++ ++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) ++ ++/* Software session entry */ ++ ++#define SW_TYPE_CIPHER 0 ++#define SW_TYPE_HMAC 1 ++#define SW_TYPE_AUTH2 2 ++#define SW_TYPE_HASH 3 ++#define SW_TYPE_COMP 4 ++#define SW_TYPE_BLKCIPHER 5 ++ ++struct swcr_data { ++ int sw_type; ++ int sw_alg; ++ struct crypto_tfm *sw_tfm; ++ union { ++ struct { ++ char *sw_key; ++ int sw_klen; ++ int sw_mlen; ++ } hmac; ++ void *sw_comp_buf; ++ } u; ++ struct swcr_data *sw_next; ++}; ++ ++#ifndef CRYPTO_TFM_MODE_CBC ++/* ++ * As of linux-2.6.21 this is no longer defined, and presumably no longer ++ * needed to be passed into the crypto core code. ++ */ ++#define CRYPTO_TFM_MODE_CBC 0 ++#define CRYPTO_TFM_MODE_ECB 0 ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ /* ++ * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new ++ * API into old API. ++ */ ++ ++ /* Symmetric/Block Cipher */ ++ struct blkcipher_desc ++ { ++ struct crypto_tfm *tfm; ++ void *info; ++ }; ++ #define ecb(X) #X ++ #define cbc(X) #X ++ #define crypto_has_blkcipher(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_blkcipher_cast(X) X ++ #define crypto_blkcipher_tfm(X) X ++ #define crypto_alloc_blkcipher(X, Y, Z) crypto_alloc_tfm(X, mode) ++ #define crypto_blkcipher_ivsize(X) crypto_tfm_alg_ivsize(X) ++ #define crypto_blkcipher_blocksize(X) crypto_tfm_alg_blocksize(X) ++ #define crypto_blkcipher_setkey(X, Y, Z) crypto_cipher_setkey(X, Y, Z) ++ #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \ ++ crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) ++ #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \ ++ crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info)) ++ ++ /* Hash/HMAC/Digest */ ++ struct hash_desc ++ { ++ struct crypto_tfm *tfm; ++ }; ++ #define hmac(X) #X ++ #define crypto_has_hash(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_hash_cast(X) X ++ #define crypto_hash_tfm(X) X ++ #define crypto_alloc_hash(X, Y, Z) crypto_alloc_tfm(X, mode) ++ #define crypto_hash_digestsize(X) crypto_tfm_alg_digestsize(X) ++ #define crypto_hash_digest(W, X, Y, Z) \ ++ crypto_digest_digest((W)->tfm, X, sg_num, Z) ++ ++ /* Asymmetric Cipher */ ++ #define crypto_has_cipher(X, Y, Z) crypto_alg_available(X, 0) ++ ++ /* Compression */ ++ #define crypto_has_comp(X, Y, Z) crypto_alg_available(X, 0) ++ #define crypto_comp_tfm(X) X ++ #define crypto_comp_cast(X) X ++ #define crypto_alloc_comp(X, Y, Z) crypto_alloc_tfm(X, mode) ++#else ++ #define ecb(X) "ecb(" #X ")" ++ #define cbc(X) "cbc(" #X ")" ++ #define hmac(X) "hmac(" #X ")" ++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ ++ ++struct crypto_details ++{ ++ char *alg_name; ++ int mode; ++ int sw_type; ++}; ++ ++/* ++ * This needs to be kept updated with CRYPTO_xxx list (cryptodev.h). ++ * If the Algorithm is not supported, then insert a {NULL, 0, 0} entry. ++ * ++ * IMPORTANT: The index to the array IS CRYPTO_xxx. ++ */ ++static struct crypto_details crypto_details[CRYPTO_ALGORITHM_MAX + 1] = { ++ { NULL, 0, 0 }, ++ /* CRYPTO_xxx index starts at 1 */ ++ { cbc(des), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(des3_ede), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(blowfish), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(cast5), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { cbc(skipjack), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { hmac(md5), 0, SW_TYPE_HMAC }, ++ { hmac(sha1), 0, SW_TYPE_HMAC }, ++ { hmac(ripemd160), 0, SW_TYPE_HMAC }, ++ { "md5-kpdk??", 0, SW_TYPE_HASH }, ++ { "sha1-kpdk??", 0, SW_TYPE_HASH }, ++ { cbc(aes), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { ecb(arc4), CRYPTO_TFM_MODE_ECB, SW_TYPE_BLKCIPHER }, ++ { "md5", 0, SW_TYPE_HASH }, ++ { "sha1", 0, SW_TYPE_HASH }, ++ { hmac(digest_null), 0, SW_TYPE_HMAC }, ++ { cbc(cipher_null), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { "deflate", 0, SW_TYPE_COMP }, ++ { hmac(sha256), 0, SW_TYPE_HMAC }, ++ { hmac(sha384), 0, SW_TYPE_HMAC }, ++ { hmac(sha512), 0, SW_TYPE_HMAC }, ++ { cbc(camellia), CRYPTO_TFM_MODE_CBC, SW_TYPE_BLKCIPHER }, ++ { "sha256", 0, SW_TYPE_HASH }, ++ { "sha384", 0, SW_TYPE_HASH }, ++ { "sha512", 0, SW_TYPE_HASH }, ++ { "ripemd160", 0, SW_TYPE_HASH }, ++}; ++ ++int32_t swcr_id = -1; ++module_param(swcr_id, int, 0444); ++MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver"); ++ ++int swcr_fail_if_compression_grows = 1; ++module_param(swcr_fail_if_compression_grows, int, 0644); ++MODULE_PARM_DESC(swcr_fail_if_compression_grows, ++ "Treat compression that results in more data as a failure"); ++ ++static struct swcr_data **swcr_sessions = NULL; ++static u_int32_t swcr_sesnum = 0; ++ ++static int swcr_process(device_t, struct cryptop *, int); ++static int swcr_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int swcr_freesession(device_t, u_int64_t); ++ ++static device_method_t swcr_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, swcr_newsession), ++ DEVMETHOD(cryptodev_freesession,swcr_freesession), ++ DEVMETHOD(cryptodev_process, swcr_process), ++}; ++ ++#define debug swcr_debug ++int swcr_debug = 0; ++module_param(swcr_debug, int, 0644); ++MODULE_PARM_DESC(swcr_debug, "Enable debug"); ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) ++{ ++ struct swcr_data **swd; ++ u_int32_t i; ++ int error; ++ char *algo; ++ int mode, sw_type; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (swcr_sessions) { ++ for (i = 1; i < swcr_sesnum; i++) ++ if (swcr_sessions[i] == NULL) ++ break; ++ } else ++ i = 1; /* NB: to silence compiler warning */ ++ ++ if (swcr_sessions == NULL || i == swcr_sesnum) { ++ if (swcr_sessions == NULL) { ++ i = 1; /* We leave swcr_sessions[0] empty */ ++ swcr_sesnum = CRYPTO_SW_SESSIONS; ++ } else ++ swcr_sesnum *= 2; ++ ++ swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC); ++ if (swd == NULL) { ++ /* Reset session number */ ++ if (swcr_sesnum == CRYPTO_SW_SESSIONS) ++ swcr_sesnum = 0; ++ else ++ swcr_sesnum /= 2; ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *)); ++ ++ /* Copy existing sessions */ ++ if (swcr_sessions) { ++ memcpy(swd, swcr_sessions, ++ (swcr_sesnum / 2) * sizeof(struct swcr_data *)); ++ kfree(swcr_sessions); ++ } ++ ++ swcr_sessions = swd; ++ } ++ ++ swd = &swcr_sessions[i]; ++ *sid = i; ++ ++ while (cri) { ++ *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data), ++ SLAB_ATOMIC); ++ if (*swd == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(*swd, 0, sizeof(struct swcr_data)); ++ ++ if (cri->cri_alg > CRYPTO_ALGORITHM_MAX) { ++ printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ algo = crypto_details[cri->cri_alg].alg_name; ++ if (!algo || !*algo) { ++ printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ mode = crypto_details[cri->cri_alg].mode; ++ sw_type = crypto_details[cri->cri_alg].sw_type; ++ ++ /* Algorithm specific configuration */ ++ switch (cri->cri_alg) { ++ case CRYPTO_NULL_CBC: ++ cri->cri_klen = 0; /* make it work with crypto API */ ++ break; ++ default: ++ break; ++ } ++ ++ if (sw_type == SW_TYPE_BLKCIPHER) { ++ dprintk("%s crypto_alloc_blkcipher(%s, 0x%x)\n", __FUNCTION__, ++ algo, mode); ++ ++ (*swd)->sw_tfm = crypto_blkcipher_tfm( ++ crypto_alloc_blkcipher(algo, 0, ++ CRYPTO_ALG_ASYNC)); ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s,0x%x)\n", ++ algo,mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ if (debug) { ++ dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d", ++ __FUNCTION__,cri->cri_klen,(cri->cri_klen + 7)/8); ++ for (i = 0; i < (cri->cri_klen + 7) / 8; i++) ++ { ++ dprintk("%s0x%x", (i % 8) ? " " : "\n ",cri->cri_key[i]); ++ } ++ dprintk("\n"); ++ } ++ error = crypto_blkcipher_setkey( ++ crypto_blkcipher_cast((*swd)->sw_tfm), cri->cri_key, ++ (cri->cri_klen + 7) / 8); ++ if (error) { ++ printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error, ++ (*swd)->sw_tfm->crt_flags); ++ swcr_freesession(NULL, i); ++ return error; ++ } ++ } else if (sw_type == SW_TYPE_HMAC || sw_type == SW_TYPE_HASH) { ++ dprintk("%s crypto_alloc_hash(%s, 0x%x)\n", __FUNCTION__, ++ algo, mode); ++ ++ (*swd)->sw_tfm = crypto_hash_tfm( ++ crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC)); ++ ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n", ++ algo, mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8; ++ (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen, ++ SLAB_ATOMIC); ++ if ((*swd)->u.hmac.sw_key == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen); ++ if (cri->cri_mlen) { ++ (*swd)->u.hmac.sw_mlen = cri->cri_mlen; ++ } else { ++ (*swd)->u.hmac.sw_mlen = ++ crypto_hash_digestsize( ++ crypto_hash_cast((*swd)->sw_tfm)); ++ } ++ } else if (sw_type == SW_TYPE_COMP) { ++ (*swd)->sw_tfm = crypto_comp_tfm( ++ crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC)); ++ if (!(*swd)->sw_tfm) { ++ dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n", ++ algo, mode); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC); ++ if ((*swd)->u.sw_comp_buf == NULL) { ++ swcr_freesession(NULL, i); ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ } else { ++ printk("cryptosoft: Unhandled sw_type %d\n", sw_type); ++ swcr_freesession(NULL, i); ++ return EINVAL; ++ } ++ ++ (*swd)->sw_alg = cri->cri_alg; ++ (*swd)->sw_type = sw_type; ++ ++ cri = cri->cri_next; ++ swd = &((*swd)->sw_next); ++ } ++ return 0; ++} ++ ++/* ++ * Free a session. ++ */ ++static int ++swcr_freesession(device_t dev, u_int64_t tid) ++{ ++ struct swcr_data *swd; ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > swcr_sesnum || swcr_sessions == NULL || ++ swcr_sessions[sid] == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return(EINVAL); ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return(0); ++ ++ while ((swd = swcr_sessions[sid]) != NULL) { ++ swcr_sessions[sid] = swd->sw_next; ++ if (swd->sw_tfm) ++ crypto_free_tfm(swd->sw_tfm); ++ if (swd->sw_type == SW_TYPE_COMP) { ++ if (swd->u.sw_comp_buf) ++ kfree(swd->u.sw_comp_buf); ++ } else { ++ if (swd->u.hmac.sw_key) ++ kfree(swd->u.hmac.sw_key); ++ } ++ kfree(swd); ++ } ++ return 0; ++} ++ ++/* ++ * Process a software request. ++ */ ++static int ++swcr_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct cryptodesc *crd; ++ struct swcr_data *sw; ++ u_int32_t lid; ++#define SCATTERLIST_MAX 16 ++ struct scatterlist sg[SCATTERLIST_MAX]; ++ int sg_num, sg_len, skip; ++ struct sk_buff *skb = NULL; ++ struct uio *uiop = NULL; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL || ++ swcr_sessions[lid] == NULL) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ /* ++ * do some error checking outside of the loop for SKB and IOV processing ++ * this leaves us with valid skb or uiop pointers for later ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ skb = (struct sk_buff *) crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags >= SCATTERLIST_MAX) { ++ printk("%s,%d: %d nr_frags > SCATTERLIST_MAX", __FILE__, __LINE__, ++ skb_shinfo(skb)->nr_frags); ++ goto done; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ uiop = (struct uio *) crp->crp_buf; ++ if (uiop->uio_iovcnt > SCATTERLIST_MAX) { ++ printk("%s,%d: %d uio_iovcnt > SCATTERLIST_MAX", __FILE__, __LINE__, ++ uiop->uio_iovcnt); ++ goto done; ++ } ++ } ++ ++ /* Go through crypto descriptors, processing as we go */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ /* ++ * Find the crypto context. ++ * ++ * XXX Note that the logic here prevents us from having ++ * XXX the same algorithm multiple times in a session ++ * XXX (or rather, we can but it won't give us the right ++ * XXX results). To do that, we'd need some way of differentiating ++ * XXX between the various instances of an algorithm (so we can ++ * XXX locate the correct crypto context). ++ */ ++ for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg; ++ sw = sw->sw_next) ++ ; ++ ++ /* No such context ? */ ++ if (sw == NULL) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ skip = crd->crd_skip; ++ ++ /* ++ * setup the SG list skip from the start of the buffer ++ */ ++ memset(sg, 0, sizeof(sg)); ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ int i, len; ++ ++ sg_num = 0; ++ sg_len = 0; ++ ++ if (skip < skb_headlen(skb)) { ++ len = skb_headlen(skb) - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ virt_to_page(skb->data + skip), len, ++ offset_in_page(skb->data + skip)); ++ sg_len += len; ++ sg_num++; ++ skip = 0; ++ } else ++ skip -= skb_headlen(skb); ++ ++ for (i = 0; sg_len < crd->crd_len && ++ i < skb_shinfo(skb)->nr_frags && ++ sg_num < SCATTERLIST_MAX; i++) { ++ if (skip < skb_shinfo(skb)->frags[i].size) { ++ len = skb_shinfo(skb)->frags[i].size - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ skb_shinfo(skb)->frags[i].page, ++ len, ++ skb_shinfo(skb)->frags[i].page_offset + skip); ++ sg_len += len; ++ sg_num++; ++ skip = 0; ++ } else ++ skip -= skb_shinfo(skb)->frags[i].size; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ int len; ++ ++ sg_len = 0; ++ for (sg_num = 0; sg_len <= crd->crd_len && ++ sg_num < uiop->uio_iovcnt && ++ sg_num < SCATTERLIST_MAX; sg_num++) { ++ if (skip <= uiop->uio_iov[sg_num].iov_len) { ++ len = uiop->uio_iov[sg_num].iov_len - skip; ++ if (len + sg_len > crd->crd_len) ++ len = crd->crd_len - sg_len; ++ sg_set_page(&sg[sg_num], ++ virt_to_page(uiop->uio_iov[sg_num].iov_base+skip), ++ len, ++ offset_in_page(uiop->uio_iov[sg_num].iov_base+skip)); ++ sg_len += len; ++ skip = 0; ++ } else ++ skip -= uiop->uio_iov[sg_num].iov_len; ++ } ++ } else { ++ sg_len = (crp->crp_ilen - skip); ++ if (sg_len > crd->crd_len) ++ sg_len = crd->crd_len; ++ sg_set_page(&sg[0], virt_to_page(crp->crp_buf + skip), ++ sg_len, offset_in_page(crp->crp_buf + skip)); ++ sg_num = 1; ++ } ++ ++ ++ switch (sw->sw_type) { ++ case SW_TYPE_BLKCIPHER: { ++ unsigned char iv[EALG_MAX_BLOCK_LEN]; ++ unsigned char *ivp = iv; ++ int ivsize = ++ crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm)); ++ struct blkcipher_desc desc; ++ ++ if (sg_len < crypto_blkcipher_blocksize( ++ crypto_blkcipher_cast(sw->sw_tfm))) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__, ++ sg_len, crypto_blkcipher_blocksize( ++ crypto_blkcipher_cast(sw->sw_tfm))); ++ goto done; ++ } ++ ++ if (ivsize > sizeof(iv)) { ++ crp->crp_etype = EINVAL; ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++ if (crd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ int i, error; ++ ++ if (debug) { ++ dprintk("%s key:", __FUNCTION__); ++ for (i = 0; i < (crd->crd_klen + 7) / 8; i++) ++ dprintk("%s0x%x", (i % 8) ? " " : "\n ", ++ crd->crd_key[i]); ++ dprintk("\n"); ++ } ++ error = crypto_blkcipher_setkey( ++ crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key, ++ (crd->crd_klen + 7) / 8); ++ if (error) { ++ dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", ++ error, sw->sw_tfm->crt_flags); ++ crp->crp_etype = -error; ++ } ++ } ++ ++ memset(&desc, 0, sizeof(desc)); ++ desc.tfm = crypto_blkcipher_cast(sw->sw_tfm); ++ ++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ ++ ++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { ++ ivp = crd->crd_iv; ++ } else { ++ get_random_bytes(ivp, ivsize); ++ } ++ /* ++ * do we have to copy the IV back to the buffer ? ++ */ ++ if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ivsize, (caddr_t)ivp); ++ } ++ desc.info = ivp; ++ crypto_blkcipher_encrypt_iv(&desc, sg, sg, sg_len); ++ ++ } else { /*decrypt */ ++ ++ if (crd->crd_flags & CRD_F_IV_EXPLICIT) { ++ ivp = crd->crd_iv; ++ } else { ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ivsize, (caddr_t)ivp); ++ } ++ desc.info = ivp; ++ crypto_blkcipher_decrypt_iv(&desc, sg, sg, sg_len); ++ } ++ } break; ++ case SW_TYPE_HMAC: ++ case SW_TYPE_HASH: ++ { ++ char result[HASH_MAX_LEN]; ++ struct hash_desc desc; ++ ++ /* check we have room for the result */ ++ if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) { ++ dprintk( ++ "cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d digestsize=%d\n", ++ crp->crp_ilen, crd->crd_skip + sg_len, crd->crd_inject, ++ sw->u.hmac.sw_mlen); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ memset(&desc, 0, sizeof(desc)); ++ desc.tfm = crypto_hash_cast(sw->sw_tfm); ++ ++ memset(result, 0, sizeof(result)); ++ ++ if (sw->sw_type == SW_TYPE_HMAC) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++ crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen, ++ sg, sg_num, result); ++#else ++ crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key, ++ sw->u.hmac.sw_klen); ++ crypto_hash_digest(&desc, sg, sg_len, result); ++#endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */ ++ ++ } else { /* SW_TYPE_HASH */ ++ crypto_hash_digest(&desc, sg, sg_len, result); ++ } ++ ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, sw->u.hmac.sw_mlen, result); ++ } ++ break; ++ ++ case SW_TYPE_COMP: { ++ void *ibuf = NULL; ++ void *obuf = sw->u.sw_comp_buf; ++ int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN; ++ int ret = 0; ++ ++ /* ++ * we need to use an additional copy if there is more than one ++ * input chunk since the kernel comp routines do not handle ++ * SG yet. Otherwise we just use the input buffer as is. ++ * Rather than allocate another buffer we just split the tmp ++ * buffer we already have. ++ * Perhaps we should just use zlib directly ? ++ */ ++ if (sg_num > 1) { ++ int blk; ++ ++ ibuf = obuf; ++ for (blk = 0; blk < sg_num; blk++) { ++ memcpy(obuf, sg_virt(&sg[blk]), ++ sg[blk].length); ++ obuf += sg[blk].length; ++ } ++ olen -= sg_len; ++ } else ++ ibuf = sg_virt(&sg[0]); ++ ++ if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */ ++ ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm), ++ ibuf, ilen, obuf, &olen); ++ if (!ret && olen > crd->crd_len) { ++ dprintk("cryptosoft: ERANGE compress %d into %d\n", ++ crd->crd_len, olen); ++ if (swcr_fail_if_compression_grows) ++ ret = ERANGE; ++ } ++ } else { /* decompress */ ++ ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm), ++ ibuf, ilen, obuf, &olen); ++ if (!ret && (olen + crd->crd_inject) > crp->crp_olen) { ++ dprintk("cryptosoft: ETOOSMALL decompress %d into %d, " ++ "space for %d,at offset %d\n", ++ crd->crd_len, olen, crp->crp_olen, crd->crd_inject); ++ ret = ETOOSMALL; ++ } ++ } ++ if (ret) ++ dprintk("%s,%d: ret = %d\n", __FILE__, __LINE__, ret); ++ ++ /* ++ * on success copy result back, ++ * linux crpyto API returns -errno, we need to fix that ++ */ ++ crp->crp_etype = ret < 0 ? -ret : ret; ++ if (ret == 0) { ++ /* copy back the result and return it's size */ ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, olen, obuf); ++ crp->crp_olen = olen; ++ } ++ ++ ++ } break; ++ ++ default: ++ /* Unknown/unsupported algorithm */ ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ } ++ ++done: ++ crypto_done(crp); ++ return 0; ++} ++ ++static int ++cryptosoft_init(void) ++{ ++ int i, sw_type, mode; ++ char *algo; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init); ++ ++ softc_device_init(&swcr_softc, "cryptosoft", 0, swcr_methods); ++ ++ swcr_id = crypto_get_driverid(softc_get_device(&swcr_softc), ++ CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC); ++ if (swcr_id < 0) { ++ printk("Software crypto device cannot initialize!"); ++ return -ENODEV; ++ } ++ ++#define REGISTER(alg) \ ++ crypto_register(swcr_id, alg, 0,0); ++ ++ for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; ++i) ++ { ++ ++ algo = crypto_details[i].alg_name; ++ if (!algo || !*algo) ++ { ++ dprintk("%s:Algorithm %d not supported\n", __FUNCTION__, i); ++ continue; ++ } ++ ++ mode = crypto_details[i].mode; ++ sw_type = crypto_details[i].sw_type; ++ ++ switch (sw_type) ++ { ++ case SW_TYPE_CIPHER: ++ if (crypto_has_cipher(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:CIPHER algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_HMAC: ++ if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:HMAC algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_HASH: ++ if (crypto_has_hash(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:HASH algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_COMP: ++ if (crypto_has_comp(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:COMP algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ case SW_TYPE_BLKCIPHER: ++ if (crypto_has_blkcipher(algo, 0, CRYPTO_ALG_ASYNC)) ++ { ++ REGISTER(i); ++ } ++ else ++ { ++ dprintk("%s:BLKCIPHER algorithm %d:'%s' not supported\n", ++ __FUNCTION__, i, algo); ++ } ++ break; ++ default: ++ dprintk( ++ "%s:Algorithm Type %d not supported (algorithm %d:'%s')\n", ++ __FUNCTION__, sw_type, i, algo); ++ break; ++ } ++ } ++ ++ return(0); ++} ++ ++static void ++cryptosoft_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(swcr_id); ++ swcr_id = -1; ++} ++ ++module_init(cryptosoft_init); ++module_exit(cryptosoft_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_asym.c linux-2.6.30/crypto/ocf/ep80579/icp_asym.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_asym.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_asym.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1375 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++#include "icp_ocf.h" ++ ++/*The following define values (containing the word 'INDEX') are used to find ++the index of each input buffer of the crypto_kop struct (see OCF cryptodev.h). ++These values were found through analysis of the OCF OpenSSL patch. If the ++calling program uses different input buffer positions, these defines will have ++to be changed.*/ ++ ++/*DIFFIE HELLMAN buffer index values*/ ++#define ICP_DH_KRP_PARAM_PRIME_INDEX (0) ++#define ICP_DH_KRP_PARAM_BASE_INDEX (1) ++#define ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX (2) ++#define ICP_DH_KRP_PARAM_RESULT_INDEX (3) ++ ++/*MOD EXP buffer index values*/ ++#define ICP_MOD_EXP_KRP_PARAM_BASE_INDEX (0) ++#define ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX (1) ++#define ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX (2) ++#define ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX (3) ++ ++#define SINGLE_BYTE_VALUE (4) ++ ++/*MOD EXP CRT buffer index values*/ ++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX (0) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX (1) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX (2) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX (3) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX (4) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX (5) ++#define ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX (6) ++ ++/*DSA sign buffer index values*/ ++#define ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX (0) ++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX (1) ++#define ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX (2) ++#define ICP_DSA_SIGN_KRP_PARAM_G_INDEX (3) ++#define ICP_DSA_SIGN_KRP_PARAM_X_INDEX (4) ++#define ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX (5) ++#define ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX (6) ++ ++/*DSA verify buffer index values*/ ++#define ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX (0) ++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX (1) ++#define ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX (2) ++#define ICP_DSA_VERIFY_KRP_PARAM_G_INDEX (3) ++#define ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX (4) ++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX (5) ++#define ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX (6) ++ ++/*DSA sign prime Q vs random number K size check values*/ ++#define DONT_RUN_LESS_THAN_CHECK (0) ++#define FAIL_A_IS_GREATER_THAN_B (1) ++#define FAIL_A_IS_EQUAL_TO_B (1) ++#define SUCCESS_A_IS_LESS_THAN_B (0) ++#define DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS (500) ++ ++/* We need to set a cryptokp success value just in case it is set or allocated ++ and not set to zero outside of this module */ ++#define CRYPTO_OP_SUCCESS (0) ++ ++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp); ++ ++static int icp_ocfDrvModExp(struct cryptkop *krp); ++ ++static int icp_ocfDrvModExpCRT(struct cryptkop *krp); ++ ++static int ++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck); ++ ++static int icp_ocfDrvDsaSign(struct cryptkop *krp); ++ ++static int icp_ocfDrvDsaVerify(struct cryptkop *krp); ++ ++static void ++icp_ocfDrvDhP1CallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV); ++ ++static void ++icp_ocfDrvModExpCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pResult); ++ ++static void ++icp_ocfDrvModExpCRTCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pOutputData); ++ ++static void ++icp_ocfDrvDsaVerifyCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaBoolean verifyStatus); ++ ++static void ++icp_ocfDrvDsaRSSignCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, ++ CpaBoolean protocolStatus, ++ CpaFlatBuffer * pR, CpaFlatBuffer * pS); ++ ++/* Name : icp_ocfDrvPkeProcess ++ * ++ * Description : This function will choose which PKE process to follow ++ * based on the input arguments ++ */ ++int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ ++ if (NULL == krp) { ++ DPRINTK("%s(): Invalid input parameters, cryptkop = %p\n", ++ __FUNCTION__, krp); ++ return EINVAL; ++ } ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ switch (krp->krp_op) { ++ case CRK_DH_COMPUTE_KEY: ++ DPRINTK("%s() doing DH_COMPUTE_KEY\n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDHComputeKey(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDHComputeKey failed " ++ "(%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_MOD_EXP: ++ DPRINTK("%s() doing MOD_EXP \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvModExp(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvModExp failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_MOD_EXP_CRT: ++ DPRINTK("%s() doing MOD_EXP_CRT \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvModExpCRT(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvModExpCRT " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_DSA_SIGN: ++ DPRINTK("%s() doing DSA_SIGN \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDsaSign(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDsaSign " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ case CRK_DSA_VERIFY: ++ DPRINTK("%s() doing DSA_VERIFY \n", __FUNCTION__); ++ lacStatus = icp_ocfDrvDsaVerify(krp); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_ocfDrvDsaVerify " ++ "failed (%d).\n", __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ return ECANCELED; ++ } ++ ++ break; ++ ++ default: ++ EPRINTK("%s(): Asymettric function not " ++ "supported (%d).\n", __FUNCTION__, krp->krp_op); ++ krp->krp_status = EOPNOTSUPP; ++ return EOPNOTSUPP; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvSwapBytes ++ * ++ * Description : This function is used to swap the byte order of a buffer. ++ * It has been seen that in general we are passed little endian byte order ++ * buffers, but LAC only accepts big endian byte order buffers. ++ */ ++static void inline ++icp_ocfDrvSwapBytes(u_int8_t * num, u_int32_t buff_len_bytes) ++{ ++ ++ int i; ++ u_int8_t *end_ptr; ++ u_int8_t hold_val; ++ ++ end_ptr = num + (buff_len_bytes - 1); ++ buff_len_bytes = buff_len_bytes >> 1; ++ for (i = 0; i < buff_len_bytes; i++) { ++ hold_val = *num; ++ *num = *end_ptr; ++ num++; ++ *end_ptr = hold_val; ++ end_ptr--; ++ } ++} ++ ++/* Name : icp_ocfDrvDHComputeKey ++ * ++ * Description : This function will map Diffie Hellman calls from OCF ++ * to the LAC API. OCF uses this function for Diffie Hellman Phase1 and ++ * Phase2. LAC has a separate Diffie Hellman Phase2 call, however both phases ++ * break down to a modular exponentiation. ++ */ ++static int icp_ocfDrvDHComputeKey(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ void *callbackTag = NULL; ++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; ++ CpaFlatBuffer *pLocalOctetStringPV = NULL; ++ uint32_t dh_prime_len_bytes = 0, dh_prime_len_bits = 0; ++ ++ /* Input checks - check prime is a multiple of 8 bits to allow for ++ allocation later */ ++ dh_prime_len_bits = ++ (krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_nbits); ++ ++ /* LAC can reject prime lengths based on prime key sizes, we just ++ need to make sure we can allocate space for the base and ++ exponent buffers correctly */ ++ if ((dh_prime_len_bits % NUM_BITS_IN_BYTE) != 0) { ++ APRINTK("%s(): Warning Prime number buffer size is not a " ++ "multiple of 8 bits\n", __FUNCTION__); ++ } ++ ++ /* Result storage space should be the same size as the prime as this ++ value can take up the same amount of storage space */ ++ if (dh_prime_len_bits != ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits) { ++ DPRINTK("%s(): Return Buffer must be the same size " ++ "as the Prime buffer\n", __FUNCTION__); ++ krp->krp_status = EINVAL; ++ return EINVAL; ++ } ++ /* Switch to size in bytes */ ++ BITS_TO_BYTES(dh_prime_len_bytes, dh_prime_len_bits); ++ ++ callbackTag = krp; ++ ++ pPhase1OpData = kmem_cache_zalloc(drvDH_zone, GFP_KERNEL); ++ if (NULL == pPhase1OpData) { ++ APRINTK("%s():Failed to get memory for key gen data\n", ++ __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pLocalOctetStringPV = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pLocalOctetStringPV) { ++ APRINTK("%s():Failed to get memory for pLocalOctetStringPV\n", ++ __FUNCTION__); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ pPhase1OpData->primeP.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIME_INDEX].crp_p; ++ ++ pPhase1OpData->primeP.dataLenInBytes = dh_prime_len_bytes; ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->primeP.pData, dh_prime_len_bytes); ++ ++ pPhase1OpData->baseG.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pPhase1OpData->baseG.dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_BASE_INDEX].crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->baseG.pData, ++ pPhase1OpData->baseG.dataLenInBytes); ++ ++ pPhase1OpData->privateValueX.pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pPhase1OpData->privateValueX.dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_PRIVATE_VALUE_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pPhase1OpData->privateValueX.pData, ++ pPhase1OpData->privateValueX.dataLenInBytes); ++ ++ /* Output parameters */ ++ pLocalOctetStringPV->pData = ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_p; ++ ++ BITS_TO_BYTES(pLocalOctetStringPV->dataLenInBytes, ++ krp->krp_param[ICP_DH_KRP_PARAM_RESULT_INDEX].crp_nbits); ++ ++ lacStatus = cpaCyDhKeyGenPhase1(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDhP1CallBack, ++ callbackTag, pPhase1OpData, ++ pLocalOctetStringPV); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DH Phase 1 Key Gen failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvModExp ++ * ++ * Description : This function will map ordinary Modular Exponentiation calls ++ * from OCF to the LAC API. ++ * ++ */ ++static int icp_ocfDrvModExp(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ void *callbackTag = NULL; ++ CpaCyLnModExpOpData *pModExpOpData = NULL; ++ CpaFlatBuffer *pResult = NULL; ++ ++ if ((krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits % ++ NUM_BITS_IN_BYTE) != 0) { ++ DPRINTK("%s(): Warning - modulus buffer size (%d) is not a " ++ "multiple of 8 bits\n", __FUNCTION__, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. ++ crp_nbits); ++ } ++ ++ /* Result storage space should be the same size as the prime as this ++ value can take up the same amount of storage space */ ++ if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_nbits > ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_nbits) { ++ APRINTK("%s(): Return Buffer size must be the same or" ++ " greater than the Modulus buffer\n", __FUNCTION__); ++ krp->krp_status = EINVAL; ++ return EINVAL; ++ } ++ ++ callbackTag = krp; ++ ++ pModExpOpData = kmem_cache_zalloc(drvLnModExp_zone, GFP_KERNEL); ++ if (NULL == pModExpOpData) { ++ APRINTK("%s():Failed to get memory for key gen data\n", ++ __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pResult = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pResult) { ++ APRINTK("%s():Failed to get memory for ModExp result\n", ++ __FUNCTION__); ++ kmem_cache_free(drvLnModExp_zone, pModExpOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ pModExpOpData->modulus.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->modulus.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_MODULUS_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pModExpOpData->modulus.pData, ++ pModExpOpData->modulus.dataLenInBytes); ++ ++ /*OCF patch to Openswan Pluto regularly sends the base value as 2 ++ bits in size. In this case, it has been found it is better to ++ use the base size memory space as the input buffer (if the number ++ is in bits is less than a byte, the number of bits is the input ++ value) */ ++ if (krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits < ++ NUM_BITS_IN_BYTE) { ++ DPRINTK("%s : base is small (%d)\n", __FUNCTION__, krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); ++ pModExpOpData->base.dataLenInBytes = SINGLE_BYTE_VALUE; ++ pModExpOpData->base.pData = ++ (uint8_t *) & (krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits); ++ *((uint32_t *) pModExpOpData->base.pData) = ++ htonl(*((uint32_t *) pModExpOpData->base.pData)); ++ ++ } else { ++ ++ DPRINTK("%s : base is big (%d)\n", __FUNCTION__, krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_nbits); ++ pModExpOpData->base.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->base.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(pModExpOpData->base.pData, ++ pModExpOpData->base.dataLenInBytes); ++ } ++ ++ pModExpOpData->exponent.pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX].crp_p; ++ BITS_TO_BYTES(pModExpOpData->exponent.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_EXPONENT_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(pModExpOpData->exponent.pData, ++ pModExpOpData->exponent.dataLenInBytes); ++ /* Output parameters */ ++ pResult->pData = ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX].crp_p, ++ BITS_TO_BYTES(pResult->dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_KRP_PARAM_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyLnModExp(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvModExpCallBack, ++ callbackTag, pModExpOpData, pResult); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): Mod Exp Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pResult); ++ kmem_cache_free(drvLnModExp_zone, pModExpOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvModExpCRT ++ * ++ * Description : This function will map ordinary Modular Exponentiation Chinese ++ * Remainder Theorem implementaion calls from OCF to the LAC API. ++ * ++ * Note : Mod Exp CRT for this driver is accelerated through LAC RSA type 2 ++ * decrypt operation. Therefore P and Q input values must always be prime ++ * numbers. Although basic primality checks are done in LAC, it is up to the ++ * user to do any correct prime number checking before passing the inputs. ++ */ ++ ++static int icp_ocfDrvModExpCRT(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyRsaDecryptOpData *rsaDecryptOpData = NULL; ++ void *callbackTag = NULL; ++ CpaFlatBuffer *pOutputData = NULL; ++ ++ /*Parameter input checks are all done by LAC, no need to repeat ++ them here. */ ++ callbackTag = krp; ++ ++ rsaDecryptOpData = kmem_cache_zalloc(drvRSADecrypt_zone, GFP_KERNEL); ++ if (NULL == rsaDecryptOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for MOD EXP CRT Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey ++ = kmem_cache_zalloc(drvRSAPrivateKey_zone, GFP_KERNEL); ++ if (NULL == rsaDecryptOpData->pRecipientPrivateKey) { ++ APRINTK("%s():Failed to get memory for MOD EXP CRT" ++ " private key values struct\n", __FUNCTION__); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ version = CPA_CY_RSA_VERSION_TWO_PRIME; ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; ++ ++ pOutputData = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pOutputData) { ++ APRINTK("%s():Failed to get memory" ++ " for MOD EXP CRT output data\n", __FUNCTION__); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ rsaDecryptOpData->pRecipientPrivateKey); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ version = CPA_CY_RSA_VERSION_TWO_PRIME; ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRepType = CPA_CY_RSA_PRIVATE_KEY_REP_TYPE_2; ++ ++ /* Link parameters */ ++ rsaDecryptOpData->inputData.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->inputData.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_I_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->inputData.pData, ++ rsaDecryptOpData->inputData.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime1P.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ prime1P.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime1P.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime1P.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2.prime2Q.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ prime2Q.dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime2Q.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.prime2Q.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey->privateKeyRep2. ++ exponent1Dp.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DP_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent1Dp.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_EXPONENT_DQ_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.exponent2Dq.dataLenInBytes); ++ ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX].crp_p; ++ BITS_TO_BYTES(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.dataLenInBytes, ++ krp-> ++ krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_COEFF_QINV_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.pData, ++ rsaDecryptOpData->pRecipientPrivateKey-> ++ privateKeyRep2.coefficientQInv.dataLenInBytes); ++ ++ /* Output Parameter */ ++ pOutputData->pData = ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pOutputData->dataLenInBytes, ++ krp->krp_param[ICP_MOD_EXP_CRT_KRP_PARAM_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyRsaDecrypt(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvModExpCRTCallBack, ++ callbackTag, rsaDecryptOpData, pOutputData); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): Mod Exp CRT Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pOutputData); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ rsaDecryptOpData->pRecipientPrivateKey); ++ kmem_cache_free(drvRSADecrypt_zone, rsaDecryptOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvCheckALessThanB ++ * ++ * Description : This function will check whether the first argument is less ++ * than the second. It is used to check whether the DSA RS sign Random K ++ * value is less than the Prime Q value (as defined in the specification) ++ * ++ */ ++static int ++icp_ocfDrvCheckALessThanB(CpaFlatBuffer * pK, CpaFlatBuffer * pQ, int *doCheck) ++{ ++ ++ uint8_t *MSB_K = pK->pData; ++ uint8_t *MSB_Q = pQ->pData; ++ uint32_t buffer_lengths_in_bytes = pQ->dataLenInBytes; ++ ++ if (DONT_RUN_LESS_THAN_CHECK == *doCheck) { ++ return FAIL_A_IS_GREATER_THAN_B; ++ } ++ ++/*Check MSBs ++if A == B, check next MSB ++if A > B, return A_IS_GREATER_THAN_B ++if A < B, return A_IS_LESS_THAN_B (success) ++*/ ++ while (*MSB_K == *MSB_Q) { ++ MSB_K++; ++ MSB_Q++; ++ ++ buffer_lengths_in_bytes--; ++ if (0 == buffer_lengths_in_bytes) { ++ DPRINTK("%s() Buffers have equal value!!\n", ++ __FUNCTION__); ++ return FAIL_A_IS_EQUAL_TO_B; ++ } ++ ++ } ++ ++ if (*MSB_K < *MSB_Q) { ++ return SUCCESS_A_IS_LESS_THAN_B; ++ } else { ++ return FAIL_A_IS_GREATER_THAN_B; ++ } ++ ++} ++ ++/* Name : icp_ocfDrvDsaSign ++ * ++ * Description : This function will map DSA RS Sign from OCF to the LAC API. ++ * ++ * NOTE: From looking at OCF patch to OpenSSL and even the number of input ++ * parameters, OCF expects us to generate the random seed value. This value ++ * is generated and passed to LAC, however the number is discared in the ++ * callback and not returned to the user. ++ */ ++static int icp_ocfDrvDsaSign(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyDsaRSSignOpData *dsaRsSignOpData = NULL; ++ void *callbackTag = NULL; ++ CpaCyRandGenOpData randGenOpData; ++ int primeQSizeInBytes = 0; ++ int doCheck = 0; ++ CpaFlatBuffer randData; ++ CpaBoolean protocolStatus = CPA_FALSE; ++ CpaFlatBuffer *pR = NULL; ++ CpaFlatBuffer *pS = NULL; ++ ++ callbackTag = krp; ++ ++ BITS_TO_BYTES(primeQSizeInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ if (DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES != primeQSizeInBytes) { ++ APRINTK("%s(): DSA PRIME Q size not equal to the " ++ "FIPS defined 20bytes, = %d\n", ++ __FUNCTION__, primeQSizeInBytes); ++ krp->krp_status = EDOM; ++ return EDOM; ++ } ++ ++ dsaRsSignOpData = kmem_cache_zalloc(drvDSARSSign_zone, GFP_KERNEL); ++ if (NULL == dsaRsSignOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA RS Sign Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ dsaRsSignOpData->K.pData = ++ kmem_cache_alloc(drvDSARSSignKValue_zone, GFP_ATOMIC); ++ ++ if (NULL == dsaRsSignOpData->K.pData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA RS Sign Op Random value\n", __FUNCTION__); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pR = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pR) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA signature R\n", __FUNCTION__); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ pS = kmem_cache_zalloc(drvFlatBuffer_zone, GFP_KERNEL); ++ if (NULL == pS) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA signature S\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /*link prime number parameter for ease of processing */ ++ dsaRsSignOpData->P.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->P.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->P.pData, ++ dsaRsSignOpData->P.dataLenInBytes); ++ ++ dsaRsSignOpData->Q.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->Q.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->Q.pData, ++ dsaRsSignOpData->Q.dataLenInBytes); ++ ++ /*generate random number with equal buffer size to Prime value Q, ++ but value less than Q */ ++ dsaRsSignOpData->K.dataLenInBytes = dsaRsSignOpData->Q.dataLenInBytes; ++ ++ randGenOpData.generateBits = CPA_TRUE; ++ randGenOpData.lenInBytes = dsaRsSignOpData->K.dataLenInBytes; ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer(dsaRsSignOpData->K.pData, ++ dsaRsSignOpData->K.dataLenInBytes, ++ &randData); ++ ++ doCheck = 0; ++ while (icp_ocfDrvCheckALessThanB(&(dsaRsSignOpData->K), ++ &(dsaRsSignOpData->Q), &doCheck)) { ++ ++ if (CPA_STATUS_SUCCESS ++ != cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, &randGenOpData, &randData)) { ++ APRINTK("%s(): ERROR - Failed to generate DSA RS Sign K" ++ "value\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = EAGAIN; ++ return EAGAIN; ++ } ++ ++ doCheck++; ++ if (DSA_SIGN_RAND_GEN_VAL_CHECK_MAX_ITERATIONS == doCheck) { ++ APRINTK("%s(): ERROR - Failed to find DSA RS Sign K " ++ "value less than Q value\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ krp->krp_status = EAGAIN; ++ return EAGAIN; ++ } ++ ++ } ++ /*Rand Data - no need to swap bytes for pK */ ++ ++ /* Link parameters */ ++ dsaRsSignOpData->G.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->G.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_G_INDEX].crp_nbits); ++ ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->G.pData, ++ dsaRsSignOpData->G.dataLenInBytes); ++ ++ dsaRsSignOpData->X.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->X.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_X_INDEX].crp_nbits); ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->X.pData, ++ dsaRsSignOpData->X.dataLenInBytes); ++ ++ dsaRsSignOpData->M.pData = ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX].crp_p; ++ BITS_TO_BYTES(dsaRsSignOpData->M.dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_DGST_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaRsSignOpData->M.pData, ++ dsaRsSignOpData->M.dataLenInBytes); ++ ++ /* Output Parameters */ ++ pS->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pS->dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_S_RESULT_INDEX]. ++ crp_nbits); ++ ++ pR->pData = krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX].crp_p; ++ BITS_TO_BYTES(pR->dataLenInBytes, ++ krp->krp_param[ICP_DSA_SIGN_KRP_PARAM_R_RESULT_INDEX]. ++ crp_nbits); ++ ++ lacStatus = cpaCyDsaSignRS(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDsaRSSignCallBack, ++ callbackTag, dsaRsSignOpData, ++ &protocolStatus, pR, pS); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DSA RS Sign Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ krp->krp_status = ECANCELED; ++ icp_ocfDrvFreeFlatBuffer(pS); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSignKValue_zone, ++ dsaRsSignOpData->K.pData); ++ kmem_cache_free(drvDSARSSign_zone, dsaRsSignOpData); ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvDsaVerify ++ * ++ * Description : This function will map DSA RS Verify from OCF to the LAC API. ++ * ++ */ ++static int icp_ocfDrvDsaVerify(struct cryptkop *krp) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyDsaVerifyOpData *dsaVerifyOpData = NULL; ++ void *callbackTag = NULL; ++ CpaBoolean verifyStatus = CPA_FALSE; ++ ++ callbackTag = krp; ++ ++ dsaVerifyOpData = kmem_cache_zalloc(drvDSAVerify_zone, GFP_KERNEL); ++ if (NULL == dsaVerifyOpData) { ++ APRINTK("%s():Failed to get memory" ++ " for DSA Verify Op data struct\n", __FUNCTION__); ++ krp->krp_status = ENOMEM; ++ return ENOMEM; ++ } ++ ++ /* Link parameters */ ++ dsaVerifyOpData->P.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->P.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_P_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->P.pData, ++ dsaVerifyOpData->P.dataLenInBytes); ++ ++ dsaVerifyOpData->Q.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->Q.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PRIME_Q_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Q.pData, ++ dsaVerifyOpData->Q.dataLenInBytes); ++ ++ dsaVerifyOpData->G.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->G.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_G_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->G.pData, ++ dsaVerifyOpData->G.dataLenInBytes); ++ ++ dsaVerifyOpData->Y.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->Y.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_PUBKEY_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->Y.pData, ++ dsaVerifyOpData->Y.dataLenInBytes); ++ ++ dsaVerifyOpData->M.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->M.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_DGST_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->M.pData, ++ dsaVerifyOpData->M.dataLenInBytes); ++ ++ dsaVerifyOpData->R.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->R.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_R_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->R.pData, ++ dsaVerifyOpData->R.dataLenInBytes); ++ ++ dsaVerifyOpData->S.pData = ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX].crp_p; ++ BITS_TO_BYTES(dsaVerifyOpData->S.dataLenInBytes, ++ krp->krp_param[ICP_DSA_VERIFY_KRP_PARAM_SIG_S_INDEX]. ++ crp_nbits); ++ icp_ocfDrvSwapBytes(dsaVerifyOpData->S.pData, ++ dsaVerifyOpData->S.dataLenInBytes); ++ ++ lacStatus = cpaCyDsaVerify(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvDsaVerifyCallBack, ++ callbackTag, dsaVerifyOpData, &verifyStatus); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): DSA Verify Operation failed (%d).\n", ++ __FUNCTION__, lacStatus); ++ kmem_cache_free(drvDSAVerify_zone, dsaVerifyOpData); ++ krp->krp_status = ECANCELED; ++ } ++ ++ return lacStatus; ++} ++ ++/* Name : icp_ocfDrvReadRandom ++ * ++ * Description : This function will map RNG functionality calls from OCF ++ * to the LAC API. ++ */ ++int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ CpaCyRandGenOpData randGenOpData; ++ CpaFlatBuffer randData; ++ ++ if (NULL == buf) { ++ APRINTK("%s(): Invalid input parameters\n", __FUNCTION__); ++ return EINVAL; ++ } ++ ++ /* maxwords here is number of integers to generate data for */ ++ randGenOpData.generateBits = CPA_TRUE; ++ ++ randGenOpData.lenInBytes = maxwords * sizeof(uint32_t); ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) buf, ++ randGenOpData.lenInBytes, &randData); ++ ++ lacStatus = cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, &randGenOpData, &randData); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): icp_LacSymRandGen failed (%d). \n", ++ __FUNCTION__, lacStatus); ++ return RETURN_RAND_NUM_GEN_FAILED; ++ } ++ ++ return randGenOpData.lenInBytes / sizeof(uint32_t); ++} ++ ++/* Name : icp_ocfDrvDhP1Callback ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DH operation. ++ */ ++static void ++icp_ocfDrvDhP1CallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pLocalOctetStringPV) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyDhPhase1KeyGenOpData *pPhase1OpData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pPhase1OpData = (CpaCyDhPhase1KeyGenOpData *) pOpData; ++ ++ if (NULL == pLocalOctetStringPV) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "pLocalOctetStringPV Data is NULL\n", __FUNCTION__); ++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): Diffie Hellman Phase1 Key Gen failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pLocalOctetStringPV->pData, ++ pLocalOctetStringPV->dataLenInBytes); ++ ++ icp_ocfDrvFreeFlatBuffer(pLocalOctetStringPV); ++ memset(pPhase1OpData, 0, sizeof(CpaCyDhPhase1KeyGenOpData)); ++ kmem_cache_free(drvDH_zone, pPhase1OpData); ++ ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvModExpCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the Mod Exp operation. ++ */ ++static void ++icp_ocfDrvModExpCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpdata, CpaFlatBuffer * pResult) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyLnModExpOpData *pLnModExpOpData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpdata) { ++ DPRINTK("%s(): Invalid Mod Exp input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pLnModExpOpData = (CpaCyLnModExpOpData *) pOpdata; ++ ++ if (NULL == pResult) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "pResult data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); ++ kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): LAC Mod Exp Operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pResult->pData, pResult->dataLenInBytes); ++ ++ /*switch base size value back to original */ ++ if (pLnModExpOpData->base.pData == ++ (uint8_t *) & (krp-> ++ krp_param[ICP_MOD_EXP_KRP_PARAM_BASE_INDEX]. ++ crp_nbits)) { ++ *((uint32_t *) pLnModExpOpData->base.pData) = ++ ntohl(*((uint32_t *) pLnModExpOpData->base.pData)); ++ } ++ icp_ocfDrvFreeFlatBuffer(pResult); ++ memset(pLnModExpOpData, 0, sizeof(CpaCyLnModExpOpData)); ++ kmem_cache_free(drvLnModExp_zone, pLnModExpOpData); ++ ++ crypto_kdone(krp); ++ ++ return; ++ ++} ++ ++/* Name : icp_ocfDrvModExpCRTCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the Mod Exp CRT operation. ++ */ ++static void ++icp_ocfDrvModExpCRTCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaFlatBuffer * pOutputData) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyRsaDecryptOpData *pDecryptData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pDecryptData = (CpaCyRsaDecryptOpData *) pOpData; ++ ++ if (NULL == pOutputData) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pOutputData is NULL\n", __FUNCTION__); ++ memset(pDecryptData->pRecipientPrivateKey, 0, ++ sizeof(CpaCyRsaPrivateKey)); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ pDecryptData->pRecipientPrivateKey); ++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); ++ kmem_cache_free(drvRSADecrypt_zone, pDecryptData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ } else { ++ APRINTK("%s(): LAC Mod Exp CRT operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } ++ ++ icp_ocfDrvSwapBytes(pOutputData->pData, pOutputData->dataLenInBytes); ++ ++ icp_ocfDrvFreeFlatBuffer(pOutputData); ++ memset(pDecryptData->pRecipientPrivateKey, 0, ++ sizeof(CpaCyRsaPrivateKey)); ++ kmem_cache_free(drvRSAPrivateKey_zone, ++ pDecryptData->pRecipientPrivateKey); ++ memset(pDecryptData, 0, sizeof(CpaCyRsaDecryptOpData)); ++ kmem_cache_free(drvRSADecrypt_zone, pDecryptData); ++ ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvDsaRSSignCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DSA RS sign operation. ++ */ ++static void ++icp_ocfDrvDsaRSSignCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, ++ CpaBoolean protocolStatus, ++ CpaFlatBuffer * pR, CpaFlatBuffer * pS) ++{ ++ struct cryptkop *krp = NULL; ++ CpaCyDsaRSSignOpData *pSignData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pSignData = (CpaCyDsaRSSignOpData *) pOpData; ++ ++ if (NULL == pR) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pR sign is NULL\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (NULL == pS) { ++ DPRINTK("%s(): Invalid input parameter - " ++ "pS sign is NULL\n", __FUNCTION__); ++ icp_ocfDrvFreeFlatBuffer(pR); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS != status) { ++ APRINTK("%s(): LAC DSA RS Sign operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } else { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ ++ if (CPA_TRUE != protocolStatus) { ++ DPRINTK("%s(): LAC DSA RS Sign operation failed due " ++ "to protocol error\n", __FUNCTION__); ++ krp->krp_status = EIO; ++ } ++ } ++ ++ /* Swap bytes only when the callback status is successful and ++ protocolStatus is set to true */ ++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == protocolStatus) { ++ icp_ocfDrvSwapBytes(pR->pData, pR->dataLenInBytes); ++ icp_ocfDrvSwapBytes(pS->pData, pS->dataLenInBytes); ++ } ++ ++ icp_ocfDrvFreeFlatBuffer(pR); ++ icp_ocfDrvFreeFlatBuffer(pS); ++ memset(pSignData->K.pData, 0, pSignData->K.dataLenInBytes); ++ kmem_cache_free(drvDSARSSignKValue_zone, pSignData->K.pData); ++ memset(pSignData, 0, sizeof(CpaCyDsaRSSignOpData)); ++ kmem_cache_free(drvDSARSSign_zone, pSignData); ++ crypto_kdone(krp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvDsaVerifyCallback ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the DSA Verify operation. ++ */ ++static void ++icp_ocfDrvDsaVerifyCallBack(void *callbackTag, ++ CpaStatus status, ++ void *pOpData, CpaBoolean verifyStatus) ++{ ++ ++ struct cryptkop *krp = NULL; ++ CpaCyDsaVerifyOpData *pVerData = NULL; ++ ++ if (NULL == callbackTag) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "callbackTag data is NULL\n", __FUNCTION__); ++ return; ++ } ++ ++ krp = (struct cryptkop *)callbackTag; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): Invalid input parameters - " ++ "Operation Data is NULL\n", __FUNCTION__); ++ krp->krp_status = ECANCELED; ++ crypto_kdone(krp); ++ return; ++ } ++ pVerData = (CpaCyDsaVerifyOpData *) pOpData; ++ ++ if (CPA_STATUS_SUCCESS != status) { ++ APRINTK("%s(): LAC DSA Verify operation failed - " ++ "Operation Status = %d\n", __FUNCTION__, status); ++ krp->krp_status = ECANCELED; ++ } else { ++ krp->krp_status = CRYPTO_OP_SUCCESS; ++ ++ if (CPA_TRUE != verifyStatus) { ++ DPRINTK("%s(): DSA signature invalid\n", __FUNCTION__); ++ krp->krp_status = EIO; ++ } ++ } ++ ++ /* Swap bytes only when the callback status is successful and ++ verifyStatus is set to true */ ++ /*Just swapping back the key values for now. Possibly all ++ swapped buffers need to be reverted */ ++ if (CPA_STATUS_SUCCESS == status && CPA_TRUE == verifyStatus) { ++ icp_ocfDrvSwapBytes(pVerData->R.pData, ++ pVerData->R.dataLenInBytes); ++ icp_ocfDrvSwapBytes(pVerData->S.pData, ++ pVerData->S.dataLenInBytes); ++ } ++ ++ memset(pVerData, 0, sizeof(CpaCyDsaVerifyOpData)); ++ kmem_cache_free(drvDSAVerify_zone, pVerData); ++ crypto_kdone(krp); ++ ++ return; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_common.c linux-2.6.30/crypto/ocf/ep80579/icp_common.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_common.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,891 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++/* ++ * An OCF module that uses Intel® QuickAssist Integrated Accelerator to do the ++ * crypto. ++ * ++ * This driver requires the ICP Access Library that is available from Intel in ++ * order to operate. ++ */ ++ ++#include "icp_ocf.h" ++ ++#define ICP_OCF_COMP_NAME "ICP_OCF" ++#define ICP_OCF_VER_MAIN (2) ++#define ICP_OCF_VER_MJR (0) ++#define ICP_OCF_VER_MNR (0) ++ ++#define MAX_DEREG_RETRIES (100) ++#define DEFAULT_DEREG_RETRIES (10) ++#define DEFAULT_DEREG_DELAY_IN_JIFFIES (10) ++ ++/* This defines the maximum number of sessions possible between OCF ++ and the OCF Tolapai Driver. If set to zero, there is no limit. */ ++#define DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT (0) ++#define NUM_SUPPORTED_CAPABILITIES (21) ++ ++/*Slabs zones*/ ++struct kmem_cache *drvSessionData_zone = NULL; ++struct kmem_cache *drvOpData_zone = NULL; ++struct kmem_cache *drvDH_zone = NULL; ++struct kmem_cache *drvLnModExp_zone = NULL; ++struct kmem_cache *drvRSADecrypt_zone = NULL; ++struct kmem_cache *drvRSAPrivateKey_zone = NULL; ++struct kmem_cache *drvDSARSSign_zone = NULL; ++struct kmem_cache *drvDSARSSignKValue_zone = NULL; ++struct kmem_cache *drvDSAVerify_zone = NULL; ++ ++/*Slab zones for flatbuffers and bufferlist*/ ++struct kmem_cache *drvFlatBuffer_zone = NULL; ++ ++static int icp_ocfDrvInit(void); ++static void icp_ocfDrvExit(void); ++static void icp_ocfDrvFreeCaches(void); ++static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg); ++ ++int32_t icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ ++/* Module parameter - gives the number of times LAC deregistration shall be ++ re-tried */ ++int num_dereg_retries = DEFAULT_DEREG_RETRIES; ++ ++/* Module parameter - gives the delay time in jiffies before a LAC session ++ shall be attempted to be deregistered again */ ++int dereg_retry_delay_in_jiffies = DEFAULT_DEREG_DELAY_IN_JIFFIES; ++ ++/* Module parameter - gives the maximum number of sessions possible between ++ OCF and the OCF Tolapai Driver. If set to zero, there is no limit.*/ ++int max_sessions = DEFAULT_OCF_TO_DRV_MAX_SESSION_COUNT; ++ ++/* This is set when the module is removed from the system, no further ++ processing can take place if this is set */ ++atomic_t icp_ocfDrvIsExiting = ATOMIC_INIT(0); ++ ++/* This is used to show how many lac sessions were not deregistered*/ ++atomic_t lac_session_failed_dereg_count = ATOMIC_INIT(0); ++ ++/* This is used to track the number of registered sessions between OCF and ++ * and the OCF Tolapai driver, when max_session is set to value other than ++ * zero. This ensures that the max_session set for the OCF and the driver ++ * is equal to the LAC registered sessions */ ++atomic_t num_ocf_to_drv_registered_sessions = ATOMIC_INIT(0); ++ ++/* Head of linked list used to store session data */ ++struct list_head icp_ocfDrvGlobalSymListHead; ++struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; ++ ++spinlock_t icp_ocfDrvSymSessInfoListSpinlock = SPIN_LOCK_UNLOCKED; ++rwlock_t icp_kmem_cache_destroy_alloc_lock = RW_LOCK_UNLOCKED; ++ ++struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; ++ ++struct icp_drvBuffListInfo defBuffListInfo; ++ ++static struct { ++ softc_device_decl sc_dev; ++} icpDev; ++ ++static device_method_t icp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, icp_ocfDrvNewSession), ++ DEVMETHOD(cryptodev_freesession, icp_ocfDrvFreeLACSession), ++ DEVMETHOD(cryptodev_process, icp_ocfDrvSymProcess), ++ DEVMETHOD(cryptodev_kprocess, icp_ocfDrvPkeProcess), ++}; ++ ++module_param(num_dereg_retries, int, S_IRUGO); ++module_param(dereg_retry_delay_in_jiffies, int, S_IRUGO); ++module_param(max_sessions, int, S_IRUGO); ++ ++MODULE_PARM_DESC(num_dereg_retries, ++ "Number of times to retry LAC Sym Session Deregistration. " ++ "Default 10, Max 100"); ++MODULE_PARM_DESC(dereg_retry_delay_in_jiffies, "Delay in jiffies " ++ "(added to a schedule() function call) before a LAC Sym " ++ "Session Dereg is retried. Default 10"); ++MODULE_PARM_DESC(max_sessions, "This sets the maximum number of sessions " ++ "between OCF and this driver. If this value is set to zero, " ++ "max session count checking is disabled. Default is zero(0)"); ++ ++/* Name : icp_ocfDrvInit ++ * ++ * Description : This function will register all the symmetric and asymmetric ++ * functionality that will be accelerated by the hardware. It will also ++ * get a unique driver ID from the OCF and initialise all slab caches ++ */ ++static int __init icp_ocfDrvInit(void) ++{ ++ int ocfStatus = 0; ++ ++ IPRINTK("=== %s ver %d.%d.%d ===\n", ICP_OCF_COMP_NAME, ++ ICP_OCF_VER_MAIN, ICP_OCF_VER_MJR, ICP_OCF_VER_MNR); ++ ++ if (MAX_DEREG_RETRIES < num_dereg_retries) { ++ EPRINTK("Session deregistration retry count set to greater " ++ "than %d", MAX_DEREG_RETRIES); ++ return -1; ++ } ++ ++ /* Initialize and Start the Cryptographic component */ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyStartInstance(CPA_INSTANCE_HANDLE_SINGLE)) { ++ EPRINTK("Failed to initialize and start the instance " ++ "of the Cryptographic component.\n"); ++ return -1; ++ } ++ ++ /* Set the default size of BufferList to allocate */ ++ memset(&defBuffListInfo, 0, sizeof(struct icp_drvBuffListInfo)); ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvBufferListMemInfo(ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS, ++ &defBuffListInfo)) { ++ EPRINTK("Failed to get bufferlist memory info.\n"); ++ return -1; ++ } ++ ++ /*Register OCF Tolapai Driver with OCF */ ++ memset(&icpDev, 0, sizeof(icpDev)); ++ softc_device_init(&icpDev, "icp", 0, icp_methods); ++ ++ icp_ocfDrvDriverId = crypto_get_driverid(softc_get_device(&icpDev), ++ CRYPTOCAP_F_HARDWARE); ++ ++ if (icp_ocfDrvDriverId < 0) { ++ EPRINTK("%s : ICP driver failed to register with OCF!\n", ++ __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ /*Create all the slab caches used by the OCF Tolapai Driver */ ++ drvSessionData_zone = ++ ICP_CACHE_CREATE("ICP Session Data", struct icp_drvSessionData); ++ ICP_CACHE_NULL_CHECK(drvSessionData_zone); ++ ++ /* ++ * Allocation of the OpData includes the allocation space for meta data. ++ * The memory after the opData structure is reserved for this meta data. ++ */ ++ drvOpData_zone = ++ kmem_cache_create("ICP Op Data", sizeof(struct icp_drvOpData) + ++ defBuffListInfo.metaSize ,0, SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ++ ++ ICP_CACHE_NULL_CHECK(drvOpData_zone); ++ ++ drvDH_zone = ICP_CACHE_CREATE("ICP DH data", CpaCyDhPhase1KeyGenOpData); ++ ICP_CACHE_NULL_CHECK(drvDH_zone); ++ ++ drvLnModExp_zone = ++ ICP_CACHE_CREATE("ICP ModExp data", CpaCyLnModExpOpData); ++ ICP_CACHE_NULL_CHECK(drvLnModExp_zone); ++ ++ drvRSADecrypt_zone = ++ ICP_CACHE_CREATE("ICP RSA decrypt data", CpaCyRsaDecryptOpData); ++ ICP_CACHE_NULL_CHECK(drvRSADecrypt_zone); ++ ++ drvRSAPrivateKey_zone = ++ ICP_CACHE_CREATE("ICP RSA private key data", CpaCyRsaPrivateKey); ++ ICP_CACHE_NULL_CHECK(drvRSAPrivateKey_zone); ++ ++ drvDSARSSign_zone = ++ ICP_CACHE_CREATE("ICP DSA Sign", CpaCyDsaRSSignOpData); ++ ICP_CACHE_NULL_CHECK(drvDSARSSign_zone); ++ ++ /*too awkward to use a macro here */ ++ drvDSARSSignKValue_zone = ++ kmem_cache_create("ICP DSA Sign Rand Val", ++ DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES, 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ICP_CACHE_NULL_CHECK(drvDSARSSignKValue_zone); ++ ++ drvDSAVerify_zone = ++ ICP_CACHE_CREATE("ICP DSA Verify", CpaCyDsaVerifyOpData); ++ ICP_CACHE_NULL_CHECK(drvDSAVerify_zone); ++ ++ drvFlatBuffer_zone = ++ ICP_CACHE_CREATE("ICP Flat Buffers", CpaFlatBuffer); ++ ICP_CACHE_NULL_CHECK(drvFlatBuffer_zone); ++ ++ /* Register the ICP symmetric crypto support. */ ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_NULL_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_DES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_3DES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_AES_CBC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_ARC4); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_MD5_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA1_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_256_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_384_HMAC); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512); ++ ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(CRYPTO_SHA2_512_HMAC); ++ ++ /* Register the ICP asymmetric algorithm support */ ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DH_COMPUTE_KEY); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_MOD_EXP_CRT); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_SIGN); ++ ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(CRK_DSA_VERIFY); ++ ++ /* Register the ICP random number generator support */ ++ if (OCF_REGISTRATION_STATUS_SUCCESS == ++ crypto_rregister(icp_ocfDrvDriverId, icp_ocfDrvReadRandom, NULL)) { ++ ocfStatus++; ++ } ++ ++ if (OCF_ZERO_FUNCTIONALITY_REGISTERED == ocfStatus) { ++ DPRINTK("%s: Failed to register any device capabilities\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeCaches(); ++ icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ return -ECANCELED; ++ } ++ ++ DPRINTK("%s: Registered %d of %d device capabilities\n", ++ __FUNCTION__, ocfStatus, NUM_SUPPORTED_CAPABILITIES); ++ ++/*Session data linked list used during module exit*/ ++ INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead); ++ INIT_LIST_HEAD(&icp_ocfDrvGlobalSymListHead_FreeMemList); ++ ++ icp_ocfDrvFreeLacSessionWorkQ = ++ create_singlethread_workqueue("ocfLacDeregWorkQueue"); ++ ++ return 0; ++} ++ ++/* Name : icp_ocfDrvExit ++ * ++ * Description : This function will deregister all the symmetric sessions ++ * registered with the LAC component. It will also deregister all symmetric ++ * and asymmetric functionality that can be accelerated by the hardware via OCF ++ * and random number generation if it is enabled. ++ */ ++static void icp_ocfDrvExit(void) ++{ ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ struct icp_drvSessionData *sessionData = NULL; ++ struct icp_drvSessionData *tempSessionData = NULL; ++ int i, remaining_delay_time_in_jiffies = 0; ++ /* There is a possibility of a process or new session command being */ ++ /* sent before this variable is incremented. The aim of this variable */ ++ /* is to stop a loop of calls creating a deadlock situation which */ ++ /* would prevent the driver from exiting. */ ++ ++ atomic_inc(&icp_ocfDrvIsExiting); ++ ++ /*Existing sessions will be routed to another driver after these calls */ ++ crypto_unregister_all(icp_ocfDrvDriverId); ++ crypto_runregister_all(icp_ocfDrvDriverId); ++ ++ /*If any sessions are waiting to be deregistered, do that. This also ++ flushes the work queue */ ++ destroy_workqueue(icp_ocfDrvFreeLacSessionWorkQ); ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ list_for_each_entry_safe(tempSessionData, sessionData, ++ &icp_ocfDrvGlobalSymListHead, listNode) { ++ for (i = 0; i < num_dereg_retries; i++) { ++ /*No harm if bad input - LAC will handle error cases */ ++ if (ICP_SESSION_RUNNING == tempSessionData->inUse) { ++ lacStatus = ++ cpaCySymRemoveSession ++ (CPA_INSTANCE_HANDLE_SINGLE, ++ tempSessionData->sessHandle); ++ if (CPA_STATUS_SUCCESS == lacStatus) { ++ /* Succesfully deregistered */ ++ break; ++ } else if (CPA_STATUS_RETRY != lacStatus) { ++ atomic_inc ++ (&lac_session_failed_dereg_count); ++ break; ++ } ++ ++ /*schedule_timout returns the time left for completion if ++ * this task is set to TASK_INTERRUPTIBLE */ ++ remaining_delay_time_in_jiffies = ++ dereg_retry_delay_in_jiffies; ++ while (0 > remaining_delay_time_in_jiffies) { ++ remaining_delay_time_in_jiffies = ++ schedule_timeout ++ (remaining_delay_time_in_jiffies); ++ } ++ ++ DPRINTK ++ ("%s(): Retry %d to deregistrate the session\n", ++ __FUNCTION__, i); ++ } ++ } ++ ++ /*remove from current list */ ++ list_del(&(tempSessionData->listNode)); ++ /*add to free mem linked list */ ++ list_add(&(tempSessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead_FreeMemList); ++ ++ } ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ /*set back to initial values */ ++ sessionData = NULL; ++ /*still have a reference in our list! */ ++ tempSessionData = NULL; ++ /*free memory */ ++ list_for_each_entry_safe(tempSessionData, sessionData, ++ &icp_ocfDrvGlobalSymListHead_FreeMemList, ++ listNode) { ++ ++ list_del(&(tempSessionData->listNode)); ++ /* Free allocated CpaCySymSessionCtx */ ++ if (NULL != tempSessionData->sessHandle) { ++ kfree(tempSessionData->sessHandle); ++ } ++ memset(tempSessionData, 0, sizeof(struct icp_drvSessionData)); ++ kmem_cache_free(drvSessionData_zone, tempSessionData); ++ } ++ ++ if (0 != atomic_read(&lac_session_failed_dereg_count)) { ++ DPRINTK("%s(): %d LAC sessions were not deregistered " ++ "correctly. This is not a clean exit! \n", ++ __FUNCTION__, ++ atomic_read(&lac_session_failed_dereg_count)); ++ } ++ ++ icp_ocfDrvFreeCaches(); ++ icp_ocfDrvDriverId = INVALID_DRIVER_ID; ++ ++ /* Shutdown the Cryptographic component */ ++ lacStatus = cpaCyStopInstance(CPA_INSTANCE_HANDLE_SINGLE); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ DPRINTK("%s(): Failed to stop instance of the " ++ "Cryptographic component.(status == %d)\n", ++ __FUNCTION__, lacStatus); ++ } ++ ++} ++ ++/* Name : icp_ocfDrvFreeCaches ++ * ++ * Description : This function deregisters all slab caches ++ */ ++static void icp_ocfDrvFreeCaches(void) ++{ ++ if (atomic_read(&icp_ocfDrvIsExiting) != CPA_TRUE) { ++ atomic_set(&icp_ocfDrvIsExiting, 1); ++ } ++ ++ /*Sym Zones */ ++ ICP_CACHE_DESTROY(drvSessionData_zone); ++ ICP_CACHE_DESTROY(drvOpData_zone); ++ ++ /*Asym zones */ ++ ICP_CACHE_DESTROY(drvDH_zone); ++ ICP_CACHE_DESTROY(drvLnModExp_zone); ++ ICP_CACHE_DESTROY(drvRSADecrypt_zone); ++ ICP_CACHE_DESTROY(drvRSAPrivateKey_zone); ++ ICP_CACHE_DESTROY(drvDSARSSignKValue_zone); ++ ICP_CACHE_DESTROY(drvDSARSSign_zone); ++ ICP_CACHE_DESTROY(drvDSAVerify_zone); ++ ++ /*FlatBuffer and BufferList Zones */ ++ ICP_CACHE_DESTROY(drvFlatBuffer_zone); ++ ++} ++ ++/* Name : icp_ocfDrvDeregRetry ++ * ++ * Description : This function will try to farm the session deregistration ++ * off to a work queue. If it fails, nothing more can be done and it ++ * returns an error ++ */ ++ ++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister) ++{ ++ struct icp_ocfDrvFreeLacSession *workstore = NULL; ++ ++ DPRINTK("%s(): Retry - Deregistering session (%p)\n", ++ __FUNCTION__, sessionToDeregister); ++ ++ /*make sure the session is not available to be allocated during this ++ process */ ++ atomic_inc(&lac_session_failed_dereg_count); ++ ++ /*Farm off to work queue */ ++ workstore = ++ kmalloc(sizeof(struct icp_ocfDrvFreeLacSession), GFP_ATOMIC); ++ if (NULL == workstore) { ++ DPRINTK("%s(): unable to free session - no memory available " ++ "for work queue\n", __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ workstore->sessionToDeregister = sessionToDeregister; ++ ++ INIT_WORK(&(workstore->work), icp_ocfDrvDeferedFreeLacSessionProcess, ++ workstore); ++ queue_work(icp_ocfDrvFreeLacSessionWorkQ, &(workstore->work)); ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ ++} ++ ++/* Name : icp_ocfDrvDeferedFreeLacSessionProcess ++ * ++ * Description : This function will retry (module input parameter) ++ * 'num_dereg_retries' times to deregister any symmetric session that recieves a ++ * CPA_STATUS_RETRY message from the LAC component. This function is run in ++ * Thread context because it is called from a worker thread ++ */ ++static void icp_ocfDrvDeferedFreeLacSessionProcess(void *arg) ++{ ++ struct icp_ocfDrvFreeLacSession *workstore = NULL; ++ CpaCySymSessionCtx sessionToDeregister = NULL; ++ int i = 0; ++ int remaining_delay_time_in_jiffies = 0; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ ++ workstore = (struct icp_ocfDrvFreeLacSession *)arg; ++ if (NULL == workstore) { ++ DPRINTK("%s() function called with null parameter \n", ++ __FUNCTION__); ++ return; ++ } ++ ++ sessionToDeregister = workstore->sessionToDeregister; ++ kfree(workstore); ++ ++ /*if exiting, give deregistration one more blast only */ ++ if (atomic_read(&icp_ocfDrvIsExiting) == CPA_TRUE) { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ ++ if (lacStatus != CPA_STATUS_SUCCESS) { ++ DPRINTK("%s() Failed to Dereg LAC session %p " ++ "during module exit\n", __FUNCTION__, ++ sessionToDeregister); ++ return; ++ } ++ ++ atomic_dec(&lac_session_failed_dereg_count); ++ return; ++ } ++ ++ for (i = 0; i <= num_dereg_retries; i++) { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ ++ if (lacStatus == CPA_STATUS_SUCCESS) { ++ atomic_dec(&lac_session_failed_dereg_count); ++ return; ++ } ++ if (lacStatus != CPA_STATUS_RETRY) { ++ DPRINTK("%s() Failed to deregister session - lacStatus " ++ " = %d", __FUNCTION__, lacStatus); ++ break; ++ } ++ ++ /*schedule_timout returns the time left for completion if this ++ task is set to TASK_INTERRUPTIBLE */ ++ remaining_delay_time_in_jiffies = dereg_retry_delay_in_jiffies; ++ while (0 > remaining_delay_time_in_jiffies) { ++ remaining_delay_time_in_jiffies = ++ schedule_timeout(remaining_delay_time_in_jiffies); ++ } ++ ++ } ++ ++ DPRINTK("%s(): Unable to deregister session\n", __FUNCTION__); ++ DPRINTK("%s(): Number of unavailable LAC sessions = %d\n", __FUNCTION__, ++ atomic_read(&lac_session_failed_dereg_count)); ++} ++ ++/* Name : icp_ocfDrvPtrAndLenToFlatBuffer ++ * ++ * Description : This function converts a "pointer and length" buffer ++ * structure to Fredericksburg Flat Buffer (CpaFlatBuffer) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, ++ CpaFlatBuffer * pFlatBuffer) ++{ ++ pFlatBuffer->pData = pData; ++ pFlatBuffer->dataLenInBytes = len; ++} ++ ++/* Name : icp_ocfDrvSingleSkBuffToFlatBuffer ++ * ++ * Description : This function converts a single socket buffer (sk_buff) ++ * structure to a Fredericksburg Flat Buffer (CpaFlatBuffer) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++static inline void ++icp_ocfDrvSingleSkBuffToFlatBuffer(struct sk_buff *pSkb, ++ CpaFlatBuffer * pFlatBuffer) ++{ ++ pFlatBuffer->pData = pSkb->data; ++ pFlatBuffer->dataLenInBytes = skb_headlen(pSkb); ++} ++ ++/* Name : icp_ocfDrvSkBuffToBufferList ++ * ++ * Description : This function converts a socket buffer (sk_buff) structure to ++ * Fredericksburg Scatter/Gather (CpaBufferList) buffer format. ++ * ++ * This function assumes that the bufferlist has been allocated with the correct ++ * number of buffer arrays. ++ * ++ */ ++inline int ++icp_ocfDrvSkBuffToBufferList(struct sk_buff *pSkb, CpaBufferList * bufferList) ++{ ++ CpaFlatBuffer *curFlatBuffer = NULL; ++ char *skbuffPageAddr = NULL; ++ struct sk_buff *pCurFrag = NULL; ++ struct skb_shared_info *pShInfo = NULL; ++ uint32_t page_offset = 0, i = 0; ++ ++ DPRINTK("%s(): Entry Point\n", __FUNCTION__); ++ ++ /* ++ * In all cases, the first skb needs to be translated to FlatBuffer. ++ * Perform a buffer translation for the first skbuff ++ */ ++ curFlatBuffer = bufferList->pBuffers; ++ icp_ocfDrvSingleSkBuffToFlatBuffer(pSkb, curFlatBuffer); ++ ++ /* Set the userData to point to the original sk_buff */ ++ bufferList->pUserData = (void *)pSkb; ++ ++ /* We now know we'll have at least one element in the SGL */ ++ bufferList->numBuffers = 1; ++ ++ if (0 == skb_is_nonlinear(pSkb)) { ++ /* Is a linear buffer - therefore it's a single skbuff */ ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ ++ curFlatBuffer++; ++ pShInfo = skb_shinfo(pSkb); ++ if (pShInfo->frag_list != NULL && pShInfo->nr_frags != 0) { ++ EPRINTK("%s():" ++ "Translation for a combination of frag_list " ++ "and frags[] array not supported!\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } else if (pShInfo->frag_list != NULL) { ++ /* ++ * Non linear skbuff supported through frag_list ++ * Perform translation for each fragment (sk_buff) ++ * in the frag_list of the first sk_buff. ++ */ ++ for (pCurFrag = pShInfo->frag_list; ++ pCurFrag != NULL; pCurFrag = pCurFrag->next) { ++ icp_ocfDrvSingleSkBuffToFlatBuffer(pCurFrag, ++ curFlatBuffer); ++ curFlatBuffer++; ++ bufferList->numBuffers++; ++ } ++ } else if (pShInfo->nr_frags != 0) { ++ /* ++ * Perform translation for each fragment in frags array ++ * and add to the BufferList ++ */ ++ for (i = 0; i < pShInfo->nr_frags; i++) { ++ /* Get the page address and offset of this frag */ ++ skbuffPageAddr = (char *)pShInfo->frags[i].page; ++ page_offset = pShInfo->frags[i].page_offset; ++ ++ /* Convert a pointer and length to a flat buffer */ ++ icp_ocfDrvPtrAndLenToFlatBuffer(skbuffPageAddr + ++ page_offset, ++ pShInfo->frags[i].size, ++ curFlatBuffer); ++ curFlatBuffer++; ++ bufferList->numBuffers++; ++ } ++ } else { ++ EPRINTK("%s():" "Could not recognize skbuff fragments!\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvBufferListToSkBuff ++ * ++ * Description : This function converts a Fredericksburg Scatter/Gather ++ * (CpaBufferList) buffer format to socket buffer structure. ++ */ ++inline int ++icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, struct sk_buff **skb) ++{ ++ DPRINTK("%s(): Entry Point\n", __FUNCTION__); ++ ++ /* Retrieve the orignal skbuff */ ++ *skb = (struct sk_buff *)bufferList->pUserData; ++ if (NULL == *skb) { ++ EPRINTK("%s():" ++ "Error on converting from a BufferList. " ++ "The BufferList does not contain an sk_buff.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ DPRINTK("%s(): Exit Point\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvPtrAndLenToBufferList ++ * ++ * Description : This function converts a "pointer and length" buffer ++ * structure to Fredericksburg Scatter/Gather Buffer (CpaBufferList) format. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, ++ CpaBufferList * pBufferList) ++{ ++ pBufferList->numBuffers = 1; ++ pBufferList->pBuffers->pData = pDataIn; ++ pBufferList->pBuffers->dataLenInBytes = length; ++} ++ ++/* Name : icp_ocfDrvBufferListToPtrAndLen ++ * ++ * Description : This function converts Fredericksburg Scatter/Gather Buffer ++ * (CpaBufferList) format to a "pointer and length" buffer structure. ++ * ++ * This function assumes that the data passed in are valid. ++ */ ++inline void ++icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, ++ void **ppDataOut, uint32_t * pLength) ++{ ++ *ppDataOut = pBufferList->pBuffers->pData; ++ *pLength = pBufferList->pBuffers->dataLenInBytes; ++} ++ ++/* Name : icp_ocfDrvBufferListMemInfo ++ * ++ * Description : This function will set the number of flat buffers in ++ * bufferlist, the size of memory to allocate for the pPrivateMetaData ++ * member of the CpaBufferList. ++ */ ++int ++icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, ++ struct icp_drvBuffListInfo *buffListInfo) ++{ ++ buffListInfo->numBuffers = numBuffers; ++ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, ++ buffListInfo->numBuffers, ++ &(buffListInfo->metaSize))) { ++ EPRINTK("%s() Failed to get buffer list meta size.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvGetSkBuffFrags ++ * ++ * Description : This function will determine the number of ++ * fragments in a socket buffer(sk_buff). ++ */ ++inline uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff * pSkb) ++{ ++ uint16_t numFrags = 0; ++ struct sk_buff *pCurFrag = NULL; ++ struct skb_shared_info *pShInfo = NULL; ++ ++ if (NULL == pSkb) ++ return 0; ++ ++ numFrags = 1; ++ if (0 == skb_is_nonlinear(pSkb)) { ++ /* Linear buffer - it's a single skbuff */ ++ return numFrags; ++ } ++ ++ pShInfo = skb_shinfo(pSkb); ++ if (NULL != pShInfo->frag_list && 0 != pShInfo->nr_frags) { ++ EPRINTK("%s(): Combination of frag_list " ++ "and frags[] array not supported!\n", __FUNCTION__); ++ return 0; ++ } else if (0 != pShInfo->nr_frags) { ++ numFrags += pShInfo->nr_frags; ++ return numFrags; ++ } else if (NULL != pShInfo->frag_list) { ++ for (pCurFrag = pShInfo->frag_list; ++ pCurFrag != NULL; pCurFrag = pCurFrag->next) { ++ numFrags++; ++ } ++ return numFrags; ++ } else { ++ return 0; ++ } ++} ++ ++/* Name : icp_ocfDrvFreeFlatBuffer ++ * ++ * Description : This function will deallocate flat buffer. ++ */ ++inline void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer) ++{ ++ if (pFlatBuffer != NULL) { ++ memset(pFlatBuffer, 0, sizeof(CpaFlatBuffer)); ++ kmem_cache_free(drvFlatBuffer_zone, pFlatBuffer); ++ } ++} ++ ++/* Name : icp_ocfDrvAllocMetaData ++ * ++ * Description : This function will allocate memory for the ++ * pPrivateMetaData member of CpaBufferList. ++ */ ++inline int ++icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, ++ const struct icp_drvOpData *pOpData) ++{ ++ Cpa32U metaSize = 0; ++ ++ if (pBufferList->numBuffers <= ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS){ ++ void *pOpDataStartAddr = (void *)pOpData; ++ ++ if (0 == defBuffListInfo.metaSize) { ++ pBufferList->pPrivateMetaData = NULL; ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ /* ++ * The meta data allocation has been included as part of the ++ * op data. It has been pre-allocated in memory just after the ++ * icp_drvOpData structure. ++ */ ++ pBufferList->pPrivateMetaData = pOpDataStartAddr + ++ sizeof(struct icp_drvOpData); ++ } else { ++ if (CPA_STATUS_SUCCESS != ++ cpaCyBufferListGetMetaSize(CPA_INSTANCE_HANDLE_SINGLE, ++ pBufferList->numBuffers, ++ &metaSize)) { ++ EPRINTK("%s() Failed to get buffer list meta size.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ if (0 == metaSize) { ++ pBufferList->pPrivateMetaData = NULL; ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++ } ++ ++ pBufferList->pPrivateMetaData = kmalloc(metaSize, GFP_ATOMIC); ++ } ++ if (NULL == pBufferList->pPrivateMetaData) { ++ EPRINTK("%s() Failed to allocate pPrivateMetaData.\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvFreeMetaData ++ * ++ * Description : This function will deallocate pPrivateMetaData memory. ++ */ ++inline void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList) ++{ ++ if (NULL == pBufferList->pPrivateMetaData) { ++ return; ++ } ++ ++ /* ++ * Only free the meta data if the BufferList has more than ++ * ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS number of buffers. ++ * Otherwise, the meta data shall be freed when the icp_drvOpData is ++ * freed. ++ */ ++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < pBufferList->numBuffers){ ++ kfree(pBufferList->pPrivateMetaData); ++ } ++} ++ ++module_init(icp_ocfDrvInit); ++module_exit(icp_ocfDrvExit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Intel"); ++MODULE_DESCRIPTION("OCF Driver for Intel Quick Assist crypto acceleration"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_ocf.h linux-2.6.30/crypto/ocf/ep80579/icp_ocf.h +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_ocf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_ocf.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,363 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++ ++/* ++ * OCF drv driver header file for the Intel ICP processor. ++ */ ++ ++#ifndef ICP_OCF_H ++#define ICP_OCF_H ++ ++#include ++#include ++#include ++ ++#include "cryptodev.h" ++#include "uio.h" ++ ++#include "cpa.h" ++#include "cpa_cy_im.h" ++#include "cpa_cy_sym.h" ++#include "cpa_cy_rand.h" ++#include "cpa_cy_dh.h" ++#include "cpa_cy_rsa.h" ++#include "cpa_cy_ln.h" ++#include "cpa_cy_common.h" ++#include "cpa_cy_dsa.h" ++ ++#define NUM_BITS_IN_BYTE (8) ++#define NUM_BITS_IN_BYTE_MINUS_ONE (NUM_BITS_IN_BYTE -1) ++#define INVALID_DRIVER_ID (-1) ++#define RETURN_RAND_NUM_GEN_FAILED (-1) ++ ++/*This is define means only one operation can be chained to another ++(resulting in one chain of two operations)*/ ++#define MAX_NUM_OF_CHAINED_OPS (1) ++/*This is the max block cipher initialisation vector*/ ++#define MAX_IV_LEN_IN_BYTES (20) ++/*This is used to check whether the OCF to this driver session limit has ++ been disabled*/ ++#define NO_OCF_TO_DRV_MAX_SESSIONS (0) ++ ++/*OCF values mapped here*/ ++#define ICP_SHA1_DIGEST_SIZE_IN_BYTES (SHA1_HASH_LEN) ++#define ICP_SHA256_DIGEST_SIZE_IN_BYTES (SHA2_256_HASH_LEN) ++#define ICP_SHA384_DIGEST_SIZE_IN_BYTES (SHA2_384_HASH_LEN) ++#define ICP_SHA512_DIGEST_SIZE_IN_BYTES (SHA2_512_HASH_LEN) ++#define ICP_MD5_DIGEST_SIZE_IN_BYTES (MD5_HASH_LEN) ++#define ARC4_COUNTER_LEN (ARC4_BLOCK_LEN) ++ ++#define OCF_REGISTRATION_STATUS_SUCCESS (0) ++#define OCF_ZERO_FUNCTIONALITY_REGISTERED (0) ++#define ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR (0) ++#define ICP_OCF_DRV_STATUS_SUCCESS (0) ++#define ICP_OCF_DRV_STATUS_FAIL (1) ++ ++/*Turn on/off debug options*/ ++#define ICP_OCF_PRINT_DEBUG_MESSAGES (0) ++#define ICP_OCF_PRINT_KERN_ALERT (1) ++#define ICP_OCF_PRINT_KERN_ERRS (1) ++ ++/*DSA Prime Q size in bytes (as defined in the standard) */ ++#define DSA_RS_SIGN_PRIMEQ_SIZE_IN_BYTES (20) ++ ++/*MACRO DEFINITIONS*/ ++ ++#define BITS_TO_BYTES(bytes, bits) \ ++ bytes = (bits + NUM_BITS_IN_BYTE_MINUS_ONE) / NUM_BITS_IN_BYTE ++ ++#define ICP_CACHE_CREATE(cache_ID, cache_name) \ ++ kmem_cache_create(cache_ID, sizeof(cache_name),0, \ ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ ++#define ICP_CACHE_NULL_CHECK(slab_zone) \ ++{ \ ++ if(NULL == slab_zone){ \ ++ icp_ocfDrvFreeCaches(); \ ++ EPRINTK("%s() line %d: Not enough memory!\n", \ ++ __FUNCTION__, __LINE__); \ ++ return ENOMEM; \ ++ } \ ++} ++ ++#define ICP_CACHE_DESTROY(slab_zone) \ ++{ \ ++ if(NULL != slab_zone){ \ ++ kmem_cache_destroy(slab_zone); \ ++ slab_zone = NULL; \ ++ } \ ++} ++ ++#define ICP_REGISTER_SYM_FUNCTIONALITY_WITH_OCF(alg) \ ++{ \ ++ if(OCF_REGISTRATION_STATUS_SUCCESS == \ ++ crypto_register(icp_ocfDrvDriverId, \ ++ alg, \ ++ 0, \ ++ 0)) { \ ++ ocfStatus++; \ ++ } \ ++} ++ ++#define ICP_REGISTER_ASYM_FUNCTIONALITY_WITH_OCF(alg) \ ++{ \ ++ if(OCF_REGISTRATION_STATUS_SUCCESS == \ ++ crypto_kregister(icp_ocfDrvDriverId, \ ++ alg, \ ++ 0)){ \ ++ ocfStatus++; \ ++ } \ ++} ++ ++#if ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++#define DPRINTK(args...) \ ++{ \ ++ printk(args); \ ++} ++ ++#else //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++ ++#define DPRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_DEBUG_MESSAGES == 1 ++ ++#if ICP_OCF_PRINT_KERN_ALERT == 1 ++#define APRINTK(args...) \ ++{ \ ++ printk(KERN_ALERT args); \ ++} ++ ++#else //ICP_OCF_PRINT_KERN_ALERT == 1 ++ ++#define APRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_KERN_ALERT == 1 ++ ++#if ICP_OCF_PRINT_KERN_ERRS == 1 ++#define EPRINTK(args...) \ ++{ \ ++ printk(KERN_ERR args); \ ++} ++ ++#else //ICP_OCF_PRINT_KERN_ERRS == 1 ++ ++#define EPRINTK(args...) ++ ++#endif //ICP_OCF_PRINT_KERN_ERRS == 1 ++ ++#define IPRINTK(args...) \ ++{ \ ++ printk(KERN_INFO args); \ ++} ++ ++/*END OF MACRO DEFINITIONS*/ ++ ++typedef enum { ++ ICP_OCF_DRV_ALG_CIPHER = 0, ++ ICP_OCF_DRV_ALG_HASH ++} icp_ocf_drv_alg_type_t; ++ ++/* These are all defined in icp_common.c */ ++extern atomic_t lac_session_failed_dereg_count; ++extern atomic_t icp_ocfDrvIsExiting; ++extern atomic_t num_ocf_to_drv_registered_sessions; ++ ++/*These are use inputs used in icp_sym.c and icp_common.c ++ They are instantiated in icp_common.c*/ ++extern int max_sessions; ++ ++extern int32_t icp_ocfDrvDriverId; ++extern struct list_head icp_ocfDrvGlobalSymListHead; ++extern struct list_head icp_ocfDrvGlobalSymListHead_FreeMemList; ++extern struct workqueue_struct *icp_ocfDrvFreeLacSessionWorkQ; ++extern spinlock_t icp_ocfDrvSymSessInfoListSpinlock; ++extern rwlock_t icp_kmem_cache_destroy_alloc_lock; ++ ++/*Slab zones for symettric functionality, instantiated in icp_common.c*/ ++extern struct kmem_cache *drvSessionData_zone; ++extern struct kmem_cache *drvOpData_zone; ++ ++/*Slabs zones for asymettric functionality, instantiated in icp_common.c*/ ++extern struct kmem_cache *drvDH_zone; ++extern struct kmem_cache *drvLnModExp_zone; ++extern struct kmem_cache *drvRSADecrypt_zone; ++extern struct kmem_cache *drvRSAPrivateKey_zone; ++extern struct kmem_cache *drvDSARSSign_zone; ++extern struct kmem_cache *drvDSARSSignKValue_zone; ++extern struct kmem_cache *drvDSAVerify_zone; ++ ++/*Slab zones for flatbuffers and bufferlist*/ ++extern struct kmem_cache *drvFlatBuffer_zone; ++ ++#define ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS (16) ++ ++struct icp_drvBuffListInfo { ++ Cpa16U numBuffers; ++ Cpa32U metaSize; ++ Cpa32U metaOffset; ++ Cpa32U buffListSize; ++}; ++extern struct icp_drvBuffListInfo defBuffListInfo; ++ ++/* ++* This struct is used to keep a reference to the relevant node in the list ++* of sessionData structs, to the buffer type required by OCF and to the OCF ++* provided crp struct that needs to be returned. All this info is needed in ++* the callback function. ++* ++* IV can sometimes be stored in non-contiguous memory (e.g. skbuff ++* linked/frag list, therefore a contiguous memory space for the IV data must be ++* created and passed to LAC ++* ++*/ ++struct icp_drvOpData { ++ CpaCySymOpData lacOpData; ++ uint32_t digestSizeInBytes; ++ struct cryptop *crp; ++ uint8_t bufferType; ++ uint8_t ivData[MAX_IV_LEN_IN_BYTES]; ++ uint16_t numBufferListArray; ++ CpaBufferList srcBuffer; ++ CpaFlatBuffer bufferListArray[ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS]; ++ CpaBoolean verifyResult; ++}; ++/*Values used to derisk chances of performs being called against ++deregistered sessions (for which the slab page has been reclaimed) ++This is not a fix - since page frames are reclaimed from a slab, one cannot ++rely on that memory not being re-used by another app.*/ ++typedef enum { ++ ICP_SESSION_INITIALISED = 0x5C5C5C, ++ ICP_SESSION_RUNNING = 0x005C00, ++ ICP_SESSION_DEREGISTERED = 0xC5C5C5 ++} usage_derisk; ++ ++/* ++This is the OCF<->OCF_DRV session object: ++ ++1.The first member is a listNode. These session objects are added to a linked ++ list in order to make it easier to remove them all at session exit time. ++2.The second member is used to give the session object state and derisk the ++ possibility of OCF batch calls executing against a deregistered session (as ++ described above). ++3.The third member is a LAC<->OCF_DRV session handle (initialised with the first ++ perform request for that session). ++4.The fourth is the LAC session context. All the parameters for this structure ++ are only known when the first perform request for this session occurs. That is ++ why the OCF Tolapai Driver only registers a new LAC session at perform time ++*/ ++struct icp_drvSessionData { ++ struct list_head listNode; ++ usage_derisk inUse; ++ CpaCySymSessionCtx sessHandle; ++ CpaCySymSessionSetupData lacSessCtx; ++}; ++ ++/* This struct is required for deferred session ++ deregistration as a work queue function can ++ only have one argument*/ ++struct icp_ocfDrvFreeLacSession { ++ CpaCySymSessionCtx sessionToDeregister; ++ struct work_struct work; ++}; ++ ++int icp_ocfDrvNewSession(device_t dev, uint32_t * sild, struct cryptoini *cri); ++ ++int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid); ++ ++int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint); ++ ++int icp_ocfDrvPkeProcess(device_t dev, struct cryptkop *krp, int hint); ++ ++int icp_ocfDrvReadRandom(void *arg, uint32_t * buf, int maxwords); ++ ++int icp_ocfDrvDeregRetry(CpaCySymSessionCtx sessionToDeregister); ++ ++int icp_ocfDrvSkBuffToBufferList(struct sk_buff *skb, ++ CpaBufferList * bufferList); ++ ++int icp_ocfDrvBufferListToSkBuff(CpaBufferList * bufferList, ++ struct sk_buff **skb); ++ ++void icp_ocfDrvPtrAndLenToFlatBuffer(void *pData, uint32_t len, ++ CpaFlatBuffer * pFlatBuffer); ++ ++void icp_ocfDrvPtrAndLenToBufferList(void *pDataIn, uint32_t length, ++ CpaBufferList * pBufferList); ++ ++void icp_ocfDrvBufferListToPtrAndLen(CpaBufferList * pBufferList, ++ void **ppDataOut, uint32_t * pLength); ++ ++int icp_ocfDrvBufferListMemInfo(uint16_t numBuffers, ++ struct icp_drvBuffListInfo *buffListInfo); ++ ++uint16_t icp_ocfDrvGetSkBuffFrags(struct sk_buff *pSkb); ++ ++void icp_ocfDrvFreeFlatBuffer(CpaFlatBuffer * pFlatBuffer); ++ ++int icp_ocfDrvAllocMetaData(CpaBufferList * pBufferList, ++ const struct icp_drvOpData *pOpData); ++ ++void icp_ocfDrvFreeMetaData(CpaBufferList * pBufferList); ++ ++#endif ++/* ICP_OCF_H */ +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/icp_sym.c linux-2.6.30/crypto/ocf/ep80579/icp_sym.c +--- linux-2.6.30.orig/crypto/ocf/ep80579/icp_sym.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/icp_sym.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1382 @@ ++/*************************************************************************** ++ * ++ * This file is provided under a dual BSD/GPLv2 license. When using or ++ * redistributing this file, you may do so under either license. ++ * ++ * GPL LICENSE SUMMARY ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * The full GNU General Public License is included in this distribution ++ * in the file called LICENSE.GPL. ++ * ++ * Contact Information: ++ * Intel Corporation ++ * ++ * BSD LICENSE ++ * ++ * Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Intel Corporation nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * version: Security.L.1.0.130 ++ * ++ ***************************************************************************/ ++/* ++ * An OCF module that uses the API for Intel® QuickAssist Technology to do the ++ * cryptography. ++ * ++ * This driver requires the ICP Access Library that is available from Intel in ++ * order to operate. ++ */ ++ ++#include "icp_ocf.h" ++ ++/*This is the call back function for all symmetric cryptographic processes. ++ Its main functionality is to free driver crypto operation structure and to ++ call back to OCF*/ ++static void ++icp_ocfDrvSymCallBack(void *callbackTag, ++ CpaStatus status, ++ const CpaCySymOp operationType, ++ void *pOpData, ++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult); ++ ++/*This function is used to extract crypto processing information from the OCF ++ inputs, so as that it may be passed onto LAC*/ ++static int ++icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc); ++ ++/*This function checks whether the crp_desc argument pertains to a digest or a ++ cipher operation*/ ++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc); ++ ++/*This function copies all the passed in session context information and stores ++ it in a LAC context structure*/ ++static int ++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, ++ CpaCySymSessionSetupData * lacSessCtx); ++ ++/*This top level function is used to find a pointer to where a digest is ++ stored/needs to be inserted. */ ++static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc); ++ ++/*This function is called when a digest pointer has to be found within a ++ SKBUFF.*/ ++static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData ++ *drvOpData, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*The following two functions are called if the SKBUFF digest pointer is not ++ positioned in the linear portion of the buffer (i.e. it is in a linked SKBUFF ++ or page fragment).*/ ++/*This function takes care of the page fragment case.*/ ++static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*This function takes care of the linked list case.*/ ++static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes); ++ ++/*This function is used to free an OCF->OCF_DRV session object*/ ++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData); ++ ++/*max IOV buffs supported in a UIO structure*/ ++#define NUM_IOV_SUPPORTED (1) ++ ++/* Name : icp_ocfDrvSymCallBack ++ * ++ * Description : When this function returns it signifies that the LAC ++ * component has completed the relevant symmetric operation. ++ * ++ * Notes : The callbackTag is a pointer to an icp_drvOpData. This memory ++ * object was passed to LAC for the cryptographic processing and contains all ++ * the relevant information for cleaning up buffer handles etc. so that the ++ * OCF Tolapai Driver portion of this crypto operation can be fully completed. ++ */ ++static void ++icp_ocfDrvSymCallBack(void *callbackTag, ++ CpaStatus status, ++ const CpaCySymOp operationType, ++ void *pOpData, ++ CpaBufferList * pDstBuffer, CpaBoolean verifyResult) ++{ ++ struct cryptop *crp = NULL; ++ struct icp_drvOpData *temp_drvOpData = ++ (struct icp_drvOpData *)callbackTag; ++ uint64_t *tempBasePtr = NULL; ++ uint32_t tempLen = 0; ++ ++ if (NULL == temp_drvOpData) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null userOpaque data" ++ "(status == %d).\n", __FUNCTION__, status); ++ DPRINTK("%s(): Unable to call OCF back! \n", __FUNCTION__); ++ return; ++ } ++ ++ crp = temp_drvOpData->crp; ++ crp->crp_etype = ICP_OCF_DRV_NO_CRYPTO_PROCESS_ERROR; ++ ++ if (NULL == pOpData) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null Symmetric Op data" ++ "(status == %d).\n", __FUNCTION__, status); ++ crp->crp_etype = ECANCELED; ++ crypto_done(crp); ++ return; ++ } ++ ++ if (NULL == pDstBuffer) { ++ DPRINTK("%s(): The callback from the LAC component" ++ " has failed due to Null Dst Bufferlist data" ++ "(status == %d).\n", __FUNCTION__, status); ++ crp->crp_etype = ECANCELED; ++ crypto_done(crp); ++ return; ++ } ++ ++ if (CPA_STATUS_SUCCESS == status) { ++ ++ if (temp_drvOpData->bufferType == CRYPTO_F_SKBUF) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvBufferListToSkBuff(pDstBuffer, ++ (struct sk_buff **) ++ &(crp->crp_buf))) { ++ EPRINTK("%s(): BufferList to SkBuff " ++ "conversion error.\n", __FUNCTION__); ++ crp->crp_etype = EPERM; ++ } ++ } else { ++ icp_ocfDrvBufferListToPtrAndLen(pDstBuffer, ++ (void **)&tempBasePtr, ++ &tempLen); ++ crp->crp_olen = (int)tempLen; ++ } ++ ++ } else { ++ DPRINTK("%s(): The callback from the LAC component has failed" ++ "(status == %d).\n", __FUNCTION__, status); ++ ++ crp->crp_etype = ECANCELED; ++ } ++ ++ if (temp_drvOpData->numBufferListArray > ++ ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { ++ kfree(pDstBuffer->pBuffers); ++ } ++ icp_ocfDrvFreeMetaData(pDstBuffer); ++ kmem_cache_free(drvOpData_zone, temp_drvOpData); ++ ++ /* Invoke the OCF callback function */ ++ crypto_done(crp); ++ ++ return; ++} ++ ++/* Name : icp_ocfDrvNewSession ++ * ++ * Description : This function will create a new Driver<->OCF session ++ * ++ * Notes : LAC session registration happens during the first perform call. ++ * That is the first time we know all information about a given session. ++ */ ++int icp_ocfDrvNewSession(device_t dev, uint32_t * sid, struct cryptoini *cri) ++{ ++ struct icp_drvSessionData *sessionData = NULL; ++ uint32_t delete_session = 0; ++ ++ /* The SID passed in should be our driver ID. We can return the */ ++ /* local ID (LID) which is a unique identifier which we can use */ ++ /* to differentiate between the encrypt/decrypt LAC session handles */ ++ if (NULL == sid) { ++ EPRINTK("%s(): Invalid input parameters - NULL sid.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (NULL == cri) { ++ EPRINTK("%s(): Invalid input parameters - NULL cryptoini.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (icp_ocfDrvDriverId != *sid) { ++ EPRINTK("%s(): Invalid input parameters - bad driver ID\n", ++ __FUNCTION__); ++ EPRINTK("\t sid = 0x08%p \n \t cri = 0x08%p \n", sid, cri); ++ return EINVAL; ++ } ++ ++ sessionData = kmem_cache_zalloc(drvSessionData_zone, GFP_ATOMIC); ++ if (NULL == sessionData) { ++ DPRINTK("%s():No memory for Session Data\n", __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ /*put this check in the spinlock so no new sessions can be added to the ++ linked list when we are exiting */ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ delete_session++; ++ ++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS != max_sessions) { ++ if (atomic_read(&num_ocf_to_drv_registered_sessions) >= ++ (max_sessions - ++ atomic_read(&lac_session_failed_dereg_count))) { ++ delete_session++; ++ } else { ++ atomic_inc(&num_ocf_to_drv_registered_sessions); ++ /* Add to session data linked list */ ++ list_add(&(sessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead); ++ } ++ ++ } else if (NO_OCF_TO_DRV_MAX_SESSIONS == max_sessions) { ++ list_add(&(sessionData->listNode), ++ &icp_ocfDrvGlobalSymListHead); ++ } ++ ++ sessionData->inUse = ICP_SESSION_INITIALISED; ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (delete_session) { ++ DPRINTK("%s():No Session handles available\n", __FUNCTION__); ++ kmem_cache_free(drvSessionData_zone, sessionData); ++ return EPERM; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAlgorithmSetup(cri, &(sessionData->lacSessCtx))) { ++ DPRINTK("%s():algorithm not supported\n", __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EINVAL; ++ } ++ ++ if (cri->cri_next) { ++ if (cri->cri_next->cri_next != NULL) { ++ DPRINTK("%s():only two chained algorithms supported\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EPERM; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAlgorithmSetup(cri->cri_next, ++ &(sessionData->lacSessCtx))) { ++ DPRINTK("%s():second algorithm not supported\n", ++ __FUNCTION__); ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return EINVAL; ++ } ++ ++ sessionData->lacSessCtx.symOperation = ++ CPA_CY_SYM_OP_ALGORITHM_CHAINING; ++ } ++ ++ *sid = (uint32_t) sessionData; ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvAlgorithmSetup ++ * ++ * Description : This function builds the session context data from the ++ * information supplied through OCF. Algorithm chain order and whether the ++ * session is Encrypt/Decrypt can only be found out at perform time however, so ++ * the session is registered with LAC at that time. ++ */ ++static int ++icp_ocfDrvAlgorithmSetup(struct cryptoini *cri, ++ CpaCySymSessionSetupData * lacSessCtx) ++{ ++ ++ lacSessCtx->sessionPriority = CPA_CY_PRIORITY_NORMAL; ++ ++ switch (cri->cri_alg) { ++ ++ case CRYPTO_NULL_CBC: ++ DPRINTK("%s(): NULL CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_NULL; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_DES_CBC: ++ DPRINTK("%s(): DES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_DES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_3DES_CBC: ++ DPRINTK("%s(): 3DES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_3DES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_AES_CBC: ++ DPRINTK("%s(): AES CBC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_AES_CBC; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_ARC4: ++ DPRINTK("%s(): ARC4\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_CIPHER; ++ lacSessCtx->cipherSetupData.cipherAlgorithm = ++ CPA_CY_SYM_CIPHER_ARC4; ++ lacSessCtx->cipherSetupData.cipherKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->cipherSetupData.pCipherKey = cri->cri_key; ++ break; ++ ++ case CRYPTO_SHA1: ++ DPRINTK("%s(): SHA1\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA1_HMAC: ++ DPRINTK("%s(): SHA1_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_SHA1; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA1_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_256: ++ DPRINTK("%s(): SHA256\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA256; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_256_HMAC: ++ DPRINTK("%s(): SHA256_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA256; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA256_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_384: ++ DPRINTK("%s(): SHA384\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA384; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_384_HMAC: ++ DPRINTK("%s(): SHA384_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA384; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA384_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_SHA2_512: ++ DPRINTK("%s(): SHA512\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA512; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_SHA2_512_HMAC: ++ DPRINTK("%s(): SHA512_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = ++ CPA_CY_SYM_HASH_SHA512; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_SHA512_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ case CRYPTO_MD5: ++ DPRINTK("%s(): MD5\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); ++ ++ break; ++ ++ case CRYPTO_MD5_HMAC: ++ DPRINTK("%s(): MD5_HMAC\n", __FUNCTION__); ++ lacSessCtx->symOperation = CPA_CY_SYM_OP_HASH; ++ lacSessCtx->hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5; ++ lacSessCtx->hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_AUTH; ++ lacSessCtx->hashSetupData.digestResultLenInBytes = ++ (cri->cri_mlen ? ++ cri->cri_mlen : ICP_MD5_DIGEST_SIZE_IN_BYTES); ++ lacSessCtx->hashSetupData.authModeSetupData.authKey = ++ cri->cri_key; ++ lacSessCtx->hashSetupData.authModeSetupData.authKeyLenInBytes = ++ cri->cri_klen / NUM_BITS_IN_BYTE; ++ lacSessCtx->hashSetupData.authModeSetupData.aadLenInBytes = 0; ++ ++ break; ++ ++ default: ++ DPRINTK("%s(): ALG Setup FAIL\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvFreeOCFSession ++ * ++ * Description : This function deletes all existing Session data representing ++ * the Cryptographic session established between OCF and this driver. This ++ * also includes freeing the memory allocated for the session context. The ++ * session object is also removed from the session linked list. ++ */ ++static void icp_ocfDrvFreeOCFSession(struct icp_drvSessionData *sessionData) ++{ ++ ++ sessionData->inUse = ICP_SESSION_DEREGISTERED; ++ ++ /*ENTER CRITICAL SECTION */ ++ spin_lock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ /*If the Driver is exiting, allow that process to ++ handle any deletions */ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ return; ++ } ++ ++ atomic_dec(&num_ocf_to_drv_registered_sessions); ++ ++ list_del(&(sessionData->listNode)); ++ ++ /*EXIT CRITICAL SECTION */ ++ spin_unlock_bh(&icp_ocfDrvSymSessInfoListSpinlock); ++ ++ if (NULL != sessionData->sessHandle) { ++ kfree(sessionData->sessHandle); ++ } ++ kmem_cache_free(drvSessionData_zone, sessionData); ++} ++ ++/* Name : icp_ocfDrvFreeLACSession ++ * ++ * Description : This attempts to deregister a LAC session. If it fails, the ++ * deregistation retry function is called. ++ */ ++int icp_ocfDrvFreeLACSession(device_t dev, uint64_t sid) ++{ ++ CpaCySymSessionCtx sessionToDeregister = NULL; ++ struct icp_drvSessionData *sessionData = NULL; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ int retval = 0; ++ ++ sessionData = (struct icp_drvSessionData *)CRYPTO_SESID2LID(sid); ++ if (NULL == sessionData) { ++ EPRINTK("%s(): OCF Free session called with Null Session ID.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ sessionToDeregister = sessionData->sessHandle; ++ ++ if (ICP_SESSION_INITIALISED == sessionData->inUse) { ++ DPRINTK("%s() Session not registered with LAC\n", __FUNCTION__); ++ } else if (NULL == sessionData->sessHandle) { ++ EPRINTK ++ ("%s(): OCF Free session called with Null Session Handle.\n", ++ __FUNCTION__); ++ return EINVAL; ++ } else { ++ lacStatus = cpaCySymRemoveSession(CPA_INSTANCE_HANDLE_SINGLE, ++ sessionToDeregister); ++ if (CPA_STATUS_RETRY == lacStatus) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvDeregRetry(&sessionToDeregister)) { ++ /* the retry function increments the ++ dereg failed count */ ++ DPRINTK("%s(): LAC failed to deregister the " ++ "session. (localSessionId= %p)\n", ++ __FUNCTION__, sessionToDeregister); ++ retval = EPERM; ++ } ++ ++ } else if (CPA_STATUS_SUCCESS != lacStatus) { ++ DPRINTK("%s(): LAC failed to deregister the session. " ++ "localSessionId= %p, lacStatus = %d\n", ++ __FUNCTION__, sessionToDeregister, lacStatus); ++ atomic_inc(&lac_session_failed_dereg_count); ++ retval = EPERM; ++ } ++ } ++ ++ icp_ocfDrvFreeOCFSession(sessionData); ++ return retval; ++ ++} ++ ++/* Name : icp_ocfDrvAlgCheck ++ * ++ * Description : This function checks whether the cryptodesc argument pertains ++ * to a sym or hash function ++ */ ++static int icp_ocfDrvAlgCheck(struct cryptodesc *crp_desc) ++{ ++ ++ if (crp_desc->crd_alg == CRYPTO_3DES_CBC || ++ crp_desc->crd_alg == CRYPTO_AES_CBC || ++ crp_desc->crd_alg == CRYPTO_DES_CBC || ++ crp_desc->crd_alg == CRYPTO_NULL_CBC || ++ crp_desc->crd_alg == CRYPTO_ARC4) { ++ return ICP_OCF_DRV_ALG_CIPHER; ++ } ++ ++ return ICP_OCF_DRV_ALG_HASH; ++} ++ ++/* Name : icp_ocfDrvSymProcess ++ * ++ * Description : This function will map symmetric functionality calls from OCF ++ * to the LAC API. It will also allocate memory to store the session context. ++ * ++ * Notes: If it is the first perform call for a given session, then a LAC ++ * session is registered. After the session is registered, no checks as ++ * to whether session paramaters have changed (e.g. alg chain order) are ++ * done. ++ */ ++int icp_ocfDrvSymProcess(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct icp_drvSessionData *sessionData = NULL; ++ struct icp_drvOpData *drvOpData = NULL; ++ CpaStatus lacStatus = CPA_STATUS_SUCCESS; ++ Cpa32U sessionCtxSizeInBytes = 0; ++ uint16_t numBufferListArray = 0; ++ ++ if (NULL == crp) { ++ DPRINTK("%s(): Invalid input parameters, cryptop is NULL\n", ++ __FUNCTION__); ++ return EINVAL; ++ } ++ ++ if (NULL == crp->crp_desc) { ++ DPRINTK("%s(): Invalid input parameters, no crp_desc attached " ++ "to crp\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ if (NULL == crp->crp_buf) { ++ DPRINTK("%s(): Invalid input parameters, no buffer attached " ++ "to crp\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ if (CPA_TRUE == atomic_read(&icp_ocfDrvIsExiting)) { ++ crp->crp_etype = EFAULT; ++ return EFAULT; ++ } ++ ++ sessionData = (struct icp_drvSessionData *) ++ (CRYPTO_SESID2LID(crp->crp_sid)); ++ if (NULL == sessionData) { ++ DPRINTK("%s(): Invalid input parameters, Null Session ID \n", ++ __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++/*If we get a request against a deregisted session, cancel operation*/ ++ if (ICP_SESSION_DEREGISTERED == sessionData->inUse) { ++ DPRINTK("%s(): Session ID %d was deregistered \n", ++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); ++ crp->crp_etype = EFAULT; ++ return EFAULT; ++ } ++ ++/*If none of the session states are set, then the session structure was either ++ not initialised properly or we are reading from a freed memory area (possible ++ due to OCF batch mode not removing queued requests against deregistered ++ sessions*/ ++ if (ICP_SESSION_INITIALISED != sessionData->inUse && ++ ICP_SESSION_RUNNING != sessionData->inUse) { ++ DPRINTK("%s(): Session - ID %d - not properly initialised or " ++ "memory freed back to the kernel \n", ++ __FUNCTION__, (int)(CRYPTO_SESID2LID(crp->crp_sid))); ++ crp->crp_etype = EINVAL; ++ return EINVAL; ++ } ++ ++ /*For the below checks, remember error checking is already done in LAC. ++ We're not validating inputs subsequent to registration */ ++ if (sessionData->inUse == ICP_SESSION_INITIALISED) { ++ DPRINTK("%s(): Initialising session\n", __FUNCTION__); ++ ++ if (NULL != crp->crp_desc->crd_next) { ++ if (ICP_OCF_DRV_ALG_CIPHER == ++ icp_ocfDrvAlgCheck(crp->crp_desc)) { ++ ++ sessionData->lacSessCtx.algChainOrder = ++ CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH; ++ ++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ } else { ++ sessionData->lacSessCtx.algChainOrder = ++ CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER; ++ ++ if (crp->crp_desc->crd_next->crd_flags & ++ CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ ++ } ++ ++ } else if (ICP_OCF_DRV_ALG_CIPHER == ++ icp_ocfDrvAlgCheck(crp->crp_desc)) { ++ if (crp->crp_desc->crd_flags & CRD_F_ENCRYPT) { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT; ++ } else { ++ sessionData->lacSessCtx.cipherSetupData. ++ cipherDirection = ++ CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT; ++ } ++ ++ } ++ ++ /*No action required for standalone Auth here */ ++ ++ /* Allocate memory for SymSessionCtx before the Session Registration */ ++ lacStatus = ++ cpaCySymSessionCtxGetSize(CPA_INSTANCE_HANDLE_SINGLE, ++ &(sessionData->lacSessCtx), ++ &sessionCtxSizeInBytes); ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymSessionCtxGetSize failed - %d\n", ++ __FUNCTION__, lacStatus); ++ return EINVAL; ++ } ++ sessionData->sessHandle = ++ kmalloc(sessionCtxSizeInBytes, GFP_ATOMIC); ++ if (NULL == sessionData->sessHandle) { ++ EPRINTK ++ ("%s(): Failed to get memory for SymSessionCtx\n", ++ __FUNCTION__); ++ return ENOMEM; ++ } ++ ++ lacStatus = cpaCySymInitSession(CPA_INSTANCE_HANDLE_SINGLE, ++ icp_ocfDrvSymCallBack, ++ &(sessionData->lacSessCtx), ++ sessionData->sessHandle); ++ ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymInitSession failed -%d \n", ++ __FUNCTION__, lacStatus); ++ return EFAULT; ++ } ++ ++ sessionData->inUse = ICP_SESSION_RUNNING; ++ } ++ ++ drvOpData = kmem_cache_zalloc(drvOpData_zone, GFP_ATOMIC); ++ if (NULL == drvOpData) { ++ EPRINTK("%s():Failed to get memory for drvOpData\n", ++ __FUNCTION__); ++ crp->crp_etype = ENOMEM; ++ return ENOMEM; ++ } ++ ++ drvOpData->lacOpData.pSessionCtx = sessionData->sessHandle; ++ drvOpData->digestSizeInBytes = sessionData->lacSessCtx.hashSetupData. ++ digestResultLenInBytes; ++ drvOpData->crp = crp; ++ ++ /* Set the default buffer list array memory allocation */ ++ drvOpData->srcBuffer.pBuffers = drvOpData->bufferListArray; ++ drvOpData->numBufferListArray = ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS; ++ ++ /* ++ * Allocate buffer list array memory allocation if the ++ * data fragment is more than the default allocation ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ numBufferListArray = icp_ocfDrvGetSkBuffFrags((struct sk_buff *) ++ crp->crp_buf); ++ if (ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS < numBufferListArray) { ++ DPRINTK("%s() numBufferListArray more than default\n", ++ __FUNCTION__); ++ drvOpData->srcBuffer.pBuffers = NULL; ++ drvOpData->srcBuffer.pBuffers = ++ kmalloc(numBufferListArray * ++ sizeof(CpaFlatBuffer), GFP_ATOMIC); ++ if (NULL == drvOpData->srcBuffer.pBuffers) { ++ EPRINTK("%s() Failed to get memory for " ++ "pBuffers\n", __FUNCTION__); ++ kmem_cache_free(drvOpData_zone, drvOpData); ++ crp->crp_etype = ENOMEM; ++ return ENOMEM; ++ } ++ drvOpData->numBufferListArray = numBufferListArray; ++ } ++ } ++ ++ /* ++ * Check the type of buffer structure we got and convert it into ++ * CpaBufferList format. ++ */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvSkBuffToBufferList((struct sk_buff *)crp->crp_buf, ++ &(drvOpData->srcBuffer))) { ++ EPRINTK("%s():Failed to translate from SK_BUF " ++ "to bufferlist\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ drvOpData->bufferType = CRYPTO_F_SKBUF; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* OCF only supports IOV of one entry. */ ++ if (NUM_IOV_SUPPORTED == ++ ((struct uio *)(crp->crp_buf))->uio_iovcnt) { ++ ++ icp_ocfDrvPtrAndLenToBufferList(((struct uio *)(crp-> ++ crp_buf))-> ++ uio_iov[0].iov_base, ++ ((struct uio *)(crp-> ++ crp_buf))-> ++ uio_iov[0].iov_len, ++ &(drvOpData-> ++ srcBuffer)); ++ ++ drvOpData->bufferType = CRYPTO_F_IOV; ++ ++ } else { ++ DPRINTK("%s():Unable to handle IOVs with lengths of " ++ "greater than one!\n", __FUNCTION__); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ } else { ++ icp_ocfDrvPtrAndLenToBufferList(crp->crp_buf, ++ crp->crp_ilen, ++ &(drvOpData->srcBuffer)); ++ ++ drvOpData->bufferType = CRYPTO_BUF_CONTIG; ++ } ++ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp->crp_desc)) { ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ if (drvOpData->crp->crp_desc->crd_next != NULL) { ++ if (icp_ocfDrvProcessDataSetup(drvOpData, drvOpData->crp-> ++ crp_desc->crd_next)) { ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ } ++ ++ /* Allocate srcBuffer's private meta data */ ++ if (ICP_OCF_DRV_STATUS_SUCCESS != ++ icp_ocfDrvAllocMetaData(&(drvOpData->srcBuffer), drvOpData)) { ++ EPRINTK("%s() icp_ocfDrvAllocMetaData failed\n", __FUNCTION__); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ /* Perform "in-place" crypto operation */ ++ lacStatus = cpaCySymPerformOp(CPA_INSTANCE_HANDLE_SINGLE, ++ (void *)drvOpData, ++ &(drvOpData->lacOpData), ++ &(drvOpData->srcBuffer), ++ &(drvOpData->srcBuffer), ++ &(drvOpData->verifyResult)); ++ if (CPA_STATUS_RETRY == lacStatus) { ++ DPRINTK("%s(): cpaCySymPerformOp retry, lacStatus = %d\n", ++ __FUNCTION__, lacStatus); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ if (CPA_STATUS_SUCCESS != lacStatus) { ++ EPRINTK("%s(): cpaCySymPerformOp failed, lacStatus = %d\n", ++ __FUNCTION__, lacStatus); ++ memset(&(drvOpData->lacOpData), 0, sizeof(CpaCySymOpData)); ++ crp->crp_etype = EINVAL; ++ goto err; ++ } ++ ++ return 0; //OCF success status value ++ ++ err: ++ if (drvOpData->numBufferListArray > ICP_OCF_DRV_DEFAULT_BUFFLIST_ARRAYS) { ++ kfree(drvOpData->srcBuffer.pBuffers); ++ } ++ icp_ocfDrvFreeMetaData(&(drvOpData->srcBuffer)); ++ kmem_cache_free(drvOpData_zone, drvOpData); ++ ++ return crp->crp_etype; ++} ++ ++/* Name : icp_ocfDrvProcessDataSetup ++ * ++ * Description : This function will setup all the cryptographic operation data ++ * that is required by LAC to execute the operation. ++ */ ++static int icp_ocfDrvProcessDataSetup(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc) ++{ ++ CpaCyRandGenOpData randGenOpData; ++ CpaFlatBuffer randData; ++ ++ drvOpData->lacOpData.packetType = CPA_CY_SYM_PACKET_TYPE_FULL; ++ ++ /* Convert from the cryptop to the ICP LAC crypto parameters */ ++ switch (crp_desc->crd_alg) { ++ case CRYPTO_NULL_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = NULL_BLOCK_LEN; ++ break; ++ case CRYPTO_DES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = DES_BLOCK_LEN; ++ break; ++ case CRYPTO_3DES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = DES3_BLOCK_LEN; ++ break; ++ case CRYPTO_ARC4: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = ARC4_COUNTER_LEN; ++ break; ++ case CRYPTO_AES_CBC: ++ drvOpData->lacOpData. ++ cryptoStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToCipherInBytes = crp_desc->crd_len; ++ drvOpData->verifyResult = CPA_FALSE; ++ drvOpData->lacOpData.ivLenInBytes = RIJNDAEL128_BLOCK_LEN; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ case CRYPTO_SHA2_256: ++ case CRYPTO_SHA2_256_HMAC: ++ case CRYPTO_SHA2_384: ++ case CRYPTO_SHA2_384_HMAC: ++ case CRYPTO_SHA2_512: ++ case CRYPTO_SHA2_512_HMAC: ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ drvOpData->lacOpData. ++ hashStartSrcOffsetInBytes = crp_desc->crd_skip; ++ drvOpData->lacOpData. ++ messageLenToHashInBytes = crp_desc->crd_len; ++ drvOpData->lacOpData. ++ pDigestResult = ++ icp_ocfDrvDigestPointerFind(drvOpData, crp_desc); ++ ++ if (NULL == drvOpData->lacOpData.pDigestResult) { ++ DPRINTK("%s(): ERROR - could not calculate " ++ "Digest Result memory address\n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ drvOpData->lacOpData.digestVerify = CPA_FALSE; ++ break; ++ default: ++ DPRINTK("%s(): Crypto process error - algorithm not " ++ "found \n", __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ /* Figure out what the IV is supposed to be */ ++ if ((crp_desc->crd_alg == CRYPTO_DES_CBC) || ++ (crp_desc->crd_alg == CRYPTO_3DES_CBC) || ++ (crp_desc->crd_alg == CRYPTO_AES_CBC)) { ++ /*ARC4 doesn't use an IV */ ++ if (crp_desc->crd_flags & CRD_F_IV_EXPLICIT) { ++ /* Explicit IV provided to OCF */ ++ drvOpData->lacOpData.pIv = crp_desc->crd_iv; ++ } else { ++ /* IV is not explicitly provided to OCF */ ++ ++ /* Point the LAC OP Data IV pointer to our allocated ++ storage location for this session. */ ++ drvOpData->lacOpData.pIv = drvOpData->ivData; ++ ++ if ((crp_desc->crd_flags & CRD_F_ENCRYPT) && ++ ((crp_desc->crd_flags & CRD_F_IV_PRESENT) == 0)) { ++ ++ /* Encrypting - need to create IV */ ++ randGenOpData.generateBits = CPA_TRUE; ++ randGenOpData.lenInBytes = MAX_IV_LEN_IN_BYTES; ++ ++ icp_ocfDrvPtrAndLenToFlatBuffer((Cpa8U *) ++ drvOpData-> ++ ivData, ++ MAX_IV_LEN_IN_BYTES, ++ &randData); ++ ++ if (CPA_STATUS_SUCCESS != ++ cpaCyRandGen(CPA_INSTANCE_HANDLE_SINGLE, ++ NULL, NULL, ++ &randGenOpData, &randData)) { ++ DPRINTK("%s(): ERROR - Failed to" ++ " generate" ++ " Initialisation Vector\n", ++ __FUNCTION__); ++ return ICP_OCF_DRV_STATUS_FAIL; ++ } ++ ++ crypto_copyback(drvOpData->crp-> ++ crp_flags, ++ drvOpData->crp->crp_buf, ++ crp_desc->crd_inject, ++ drvOpData->lacOpData. ++ ivLenInBytes, ++ (caddr_t) (drvOpData->lacOpData. ++ pIv)); ++ } else { ++ /* Reading IV from buffer */ ++ crypto_copydata(drvOpData->crp-> ++ crp_flags, ++ drvOpData->crp->crp_buf, ++ crp_desc->crd_inject, ++ drvOpData->lacOpData. ++ ivLenInBytes, ++ (caddr_t) (drvOpData->lacOpData. ++ pIv)); ++ } ++ ++ } ++ ++ } ++ ++ return ICP_OCF_DRV_STATUS_SUCCESS; ++} ++ ++/* Name : icp_ocfDrvDigestPointerFind ++ * ++ * Description : This function is used to find the memory address of where the ++ * digest information shall be stored in. Input buffer types are an skbuff, iov ++ * or flat buffer. The address is found using the buffer data start address and ++ * an offset. ++ * ++ * Note: In the case of a linux skbuff, the digest address may exist within ++ * a memory space linked to from the start buffer. These linked memory spaces ++ * must be traversed by the data length offset in order to find the digest start ++ * address. Whether there is enough space for the digest must also be checked. ++ */ ++ ++static uint8_t *icp_ocfDrvDigestPointerFind(struct icp_drvOpData *drvOpData, ++ struct cryptodesc *crp_desc) ++{ ++ ++ int offsetInBytes = crp_desc->crd_inject; ++ uint32_t digestSizeInBytes = drvOpData->digestSizeInBytes; ++ uint8_t *flat_buffer_base = NULL; ++ int flat_buffer_length = 0; ++ struct sk_buff *skb; ++ ++ if (drvOpData->crp->crp_flags & CRYPTO_F_SKBUF) { ++ /*check if enough overall space to store hash */ ++ skb = (struct sk_buff *)(drvOpData->crp->crp_buf); ++ ++ if (skb->len < (offsetInBytes + digestSizeInBytes)) { ++ DPRINTK("%s() Not enough space for Digest" ++ " payload after the offset (%d), " ++ "digest size (%d) \n", __FUNCTION__, ++ offsetInBytes, digestSizeInBytes); ++ return NULL; ++ } ++ ++ return icp_ocfDrvSkbuffDigestPointerFind(drvOpData, ++ offsetInBytes, ++ digestSizeInBytes); ++ ++ } else { ++ /* IOV or flat buffer */ ++ if (drvOpData->crp->crp_flags & CRYPTO_F_IOV) { ++ /*single IOV check has already been done */ ++ flat_buffer_base = ((struct uio *) ++ (drvOpData->crp->crp_buf))-> ++ uio_iov[0].iov_base; ++ flat_buffer_length = ((struct uio *) ++ (drvOpData->crp->crp_buf))-> ++ uio_iov[0].iov_len; ++ } else { ++ flat_buffer_base = (uint8_t *) drvOpData->crp->crp_buf; ++ flat_buffer_length = drvOpData->crp->crp_ilen; ++ } ++ ++ if (flat_buffer_length < (offsetInBytes + digestSizeInBytes)) { ++ DPRINTK("%s() Not enough space for Digest " ++ "(IOV/Flat Buffer) \n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) (flat_buffer_base + offsetInBytes); ++ } ++ } ++ DPRINTK("%s() Should not reach this point\n", __FUNCTION__); ++ return NULL; ++} ++ ++/* Name : icp_ocfDrvSkbuffDigestPointerFind ++ * ++ * Description : This function is used by icp_ocfDrvDigestPointerFind to process ++ * the non-linear portion of the skbuff if the fragmentation type is a linked ++ * list (frag_list is not NULL in the skb_shared_info structure) ++ */ ++static inline uint8_t *icp_ocfDrvSkbuffDigestPointerFind(struct icp_drvOpData ++ *drvOpData, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ ++ struct sk_buff *skb = NULL; ++ struct skb_shared_info *skb_shared = NULL; ++ ++ uint32_t skbuffisnonlinear = 0; ++ ++ uint32_t skbheadlen = 0; ++ ++ skb = (struct sk_buff *)(drvOpData->crp->crp_buf); ++ skbuffisnonlinear = skb_is_nonlinear(skb); ++ ++ skbheadlen = skb_headlen(skb); ++ ++ /*Linear skb checks */ ++ if (skbheadlen > offsetInBytes) { ++ ++ if (skbheadlen >= (offsetInBytes + digestSizeInBytes)) { ++ return (uint8_t *) (skb->data + offsetInBytes); ++ } else { ++ DPRINTK("%s() Auth payload stretches " ++ "accross contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } ++ } else { ++ if (skbuffisnonlinear) { ++ offsetInBytes -= skbheadlen; ++ } else { ++ DPRINTK("%s() Offset outside of buffer boundaries\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ } ++ ++ /*Non Linear checks */ ++ skb_shared = (struct skb_shared_info *)(skb->end); ++ if (unlikely(NULL == skb_shared)) { ++ DPRINTK("%s() skbuff shared info stucture is NULL! \n", ++ __FUNCTION__); ++ return NULL; ++ } else if ((0 != skb_shared->nr_frags) && ++ (skb_shared->frag_list != NULL)) { ++ DPRINTK("%s() skbuff nr_frags AND " ++ "frag_list not supported \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ /*TCP segmentation more likely than IP fragmentation */ ++ if (likely(0 != skb_shared->nr_frags)) { ++ return icp_ocfDrvDigestSkbNRFragsCheck(skb, skb_shared, ++ offsetInBytes, ++ digestSizeInBytes); ++ } else if (skb_shared->frag_list != NULL) { ++ return icp_ocfDrvDigestSkbFragListCheck(skb, skb_shared, ++ offsetInBytes, ++ digestSizeInBytes); ++ } else { ++ DPRINTK("%s() skbuff is non-linear but does not show any " ++ "linked data\n", __FUNCTION__); ++ return NULL; ++ } ++ ++} ++ ++/* Name : icp_ocfDrvDigestSkbNRFragsCheck ++ * ++ * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to ++ * process the non-linear portion of the skbuff, if the fragmentation type is ++ * page fragments ++ */ ++static inline uint8_t *icp_ocfDrvDigestSkbNRFragsCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ int i = 0; ++ /*nr_frags starts from 1 */ ++ if (MAX_SKB_FRAGS < skb_shared->nr_frags) { ++ DPRINTK("%s error processing skbuff " ++ "page frame -- MAX FRAGS exceeded \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for (i = 0; i < skb_shared->nr_frags; i++) { ++ ++ if (offsetInBytes >= skb_shared->frags[i].size) { ++ /*offset still greater than data position */ ++ offsetInBytes -= skb_shared->frags[i].size; ++ } else { ++ /* found the page containing start of hash */ ++ ++ if (NULL == skb_shared->frags[i].page) { ++ DPRINTK("%s() Linked page is NULL!\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ ++ if (offsetInBytes + digestSizeInBytes > ++ skb_shared->frags[i].size) { ++ DPRINTK("%s() Auth payload stretches accross " ++ "contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) (skb_shared->frags[i].page + ++ skb_shared->frags[i]. ++ page_offset + ++ offsetInBytes); ++ } ++ } ++ /*only possible if internal page sizes are set wrong */ ++ if (offsetInBytes < 0) { ++ DPRINTK("%s error processing skbuff page frame " ++ "-- offset calculation \n", __FUNCTION__); ++ return NULL; ++ } ++ } ++ /*only possible if internal page sizes are set wrong */ ++ DPRINTK("%s error processing skbuff page frame " ++ "-- ran out of page fragments, remaining offset = %d \n", ++ __FUNCTION__, offsetInBytes); ++ return NULL; ++ ++} ++ ++/* Name : icp_ocfDrvDigestSkbFragListCheck ++ * ++ * Description : This function is used by icp_ocfDrvSkbuffDigestPointerFind to ++ * process the non-linear portion of the skbuff, if the fragmentation type is ++ * a linked list ++ * ++ */ ++static inline uint8_t *icp_ocfDrvDigestSkbFragListCheck(struct sk_buff *skb, ++ struct skb_shared_info ++ *skb_shared, ++ int offsetInBytes, ++ uint32_t ++ digestSizeInBytes) ++{ ++ ++ struct sk_buff *skb_list = skb_shared->frag_list; ++ /*check added for readability */ ++ if (NULL == skb_list) { ++ DPRINTK("%s error processing skbuff " ++ "-- no more list! \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for (; skb_list; skb_list = skb_list->next) { ++ if (NULL == skb_list) { ++ DPRINTK("%s error processing skbuff " ++ "-- no more list! \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ if (offsetInBytes >= skb_list->len) { ++ offsetInBytes -= skb_list->len; ++ ++ } else { ++ if (offsetInBytes + digestSizeInBytes > skb_list->len) { ++ DPRINTK("%s() Auth payload stretches accross " ++ "contiguous memory\n", __FUNCTION__); ++ return NULL; ++ } else { ++ return (uint8_t *) ++ (skb_list->data + offsetInBytes); ++ } ++ ++ } ++ ++ /*This check is only needed if internal skb_list length values ++ are set wrong. */ ++ if (0 > offsetInBytes) { ++ DPRINTK("%s() error processing skbuff object -- offset " ++ "calculation \n", __FUNCTION__); ++ return NULL; ++ } ++ ++ } ++ ++ /*catch all for unusual for-loop exit. ++ This code should never be reached */ ++ DPRINTK("%s() Catch-All hit! Process error.\n", __FUNCTION__); ++ return NULL; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/ep80579/Makefile linux-2.6.30/crypto/ocf/ep80579/Makefile +--- linux-2.6.30.orig/crypto/ocf/ep80579/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ep80579/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,107 @@ ++######################################################################### ++# ++# Targets supported ++# all - builds everything and installs ++# install - identical to all ++# depend - build dependencies ++# clean - clears derived objects except the .depend files ++# distclean- clears all derived objects and the .depend file ++# ++# @par ++# This file is provided under a dual BSD/GPLv2 license. When using or ++# redistributing this file, you may do so under either license. ++# ++# GPL LICENSE SUMMARY ++# ++# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# The full GNU General Public License is included in this distribution ++# in the file called LICENSE.GPL. ++# ++# Contact Information: ++# Intel Corporation ++# ++# BSD LICENSE ++# ++# Copyright(c) 2007,2008 Intel Corporation. All rights reserved. ++# All rights reserved. ++# ++# Redistribution and use in source and binary forms, with or without ++# modification, are permitted provided that the following conditions ++# are met: ++# ++# * Redistributions of source code must retain the above copyright ++# notice, this list of conditions and the following disclaimer. ++# * Redistributions in binary form must reproduce the above copyright ++# notice, this list of conditions and the following disclaimer in ++# the documentation and/or other materials provided with the ++# distribution. ++# * Neither the name of Intel Corporation nor the names of its ++# contributors may be used to endorse or promote products derived ++# from this software without specific prior written permission. ++# ++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++# ++# ++# version: Security.L.1.0.130 ++############################################################################ ++ ++ ++####################Common variables and definitions######################## ++ ++# Ensure The ENV_DIR environmental var is defined. ++ifndef ICP_ENV_DIR ++$(error ICP_ENV_DIR is undefined. Please set the path to your environment makefile \ ++ "-> setenv ICP_ENV_DIR ") ++endif ++ ++#Add your project environment Makefile ++include $(ICP_ENV_DIR)/environment.mk ++ ++#include the makefile with all the default and common Make variable definitions ++include $(ICP_BUILDSYSTEM_PATH)/build_files/common.mk ++ ++#Add the name for the executable, Library or Module output definitions ++OUTPUT_NAME= icp_ocf ++ ++# List of Source Files to be compiled ++SOURCES= icp_common.c icp_sym.c icp_asym.c ++ ++#common includes between all supported OSes ++INCLUDES= -I $(ICP_API_DIR) -I$(ICP_LAC_API) \ ++-I$(ICP_OCF_SRC_DIR) ++ ++# The location of the os level makefile needs to be changed. ++include $(ICP_ENV_DIR)/$(ICP_OS)_$(ICP_OS_LEVEL).mk ++ ++# On the line directly below list the outputs you wish to build for, ++# e.g "lib_static lib_shared exe module" as show below ++install: module ++ ++###################Include rules makefiles######################## ++include $(ICP_BUILDSYSTEM_PATH)/build_files/rules.mk ++###################End of Rules inclusion######################### ++ ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751.c linux-2.6.30/crypto/ocf/hifn/hifn7751.c +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,2970 @@ ++/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * Copyright (c) 2003 Hifn Inc. ++ * ++ * This driver is based on a previous driver by Invertex, for which they ++ * requested: Please send any comments, feedback, bug-fixes, or feature ++ * requests to software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ * ++__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.40 2007/03/21 03:42:49 sam Exp $"); ++ */ ++ ++/* ++ * Driver for various Hifn encryption processors. ++ */ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DPRINTF(a...) if (hifn_debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "hifn"); \ ++ printk(a); \ ++ } else ++#else ++#define DPRINTF(a...) ++#endif ++ ++static inline int ++pci_get_revid(struct pci_dev *dev) ++{ ++ u8 rid = 0; ++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid); ++ return rid; ++} ++ ++static struct hifn_stats hifnstats; ++ ++#define debug hifn_debug ++int hifn_debug = 0; ++module_param(hifn_debug, int, 0644); ++MODULE_PARM_DESC(hifn_debug, "Enable debug"); ++ ++int hifn_maxbatch = 1; ++module_param(hifn_maxbatch, int, 0644); ++MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt"); ++ ++#ifdef MODULE_PARM ++char *hifn_pllconfig = NULL; ++MODULE_PARM(hifn_pllconfig, "s"); ++#else ++char hifn_pllconfig[32]; /* This setting is RO after loading */ ++module_param_string(hifn_pllconfig, hifn_pllconfig, 32, 0444); ++#endif ++MODULE_PARM_DESC(hifn_pllconfig, "PLL config, ie., pci66, ext33, ..."); ++ ++#ifdef HIFN_VULCANDEV ++#include ++#include ++ ++static struct cdevsw vulcanpk_cdevsw; /* forward declaration */ ++#endif ++ ++/* ++ * Prototypes and count for the pci_device structure ++ */ ++static int hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent); ++static void hifn_remove(struct pci_dev *dev); ++ ++static int hifn_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int hifn_freesession(device_t, u_int64_t); ++static int hifn_process(device_t, struct cryptop *, int); ++ ++static device_method_t hifn_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, hifn_newsession), ++ DEVMETHOD(cryptodev_freesession,hifn_freesession), ++ DEVMETHOD(cryptodev_process, hifn_process), ++}; ++ ++static void hifn_reset_board(struct hifn_softc *, int); ++static void hifn_reset_puc(struct hifn_softc *); ++static void hifn_puc_wait(struct hifn_softc *); ++static int hifn_enable_crypto(struct hifn_softc *); ++static void hifn_set_retry(struct hifn_softc *sc); ++static void hifn_init_dma(struct hifn_softc *); ++static void hifn_init_pci_registers(struct hifn_softc *); ++static int hifn_sramsize(struct hifn_softc *); ++static int hifn_dramsize(struct hifn_softc *); ++static int hifn_ramtype(struct hifn_softc *); ++static void hifn_sessions(struct hifn_softc *); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hifn_intr(int irq, void *arg); ++#else ++static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs); ++#endif ++static u_int hifn_write_command(struct hifn_command *, u_int8_t *); ++static u_int32_t hifn_next_signature(u_int32_t a, u_int cnt); ++static void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *); ++static int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int); ++static int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *); ++static int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *); ++static int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *); ++static int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *); ++static int hifn_init_pubrng(struct hifn_softc *); ++static void hifn_tick(unsigned long arg); ++static void hifn_abort(struct hifn_softc *); ++static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *); ++ ++static void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t); ++static void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t); ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int hifn_read_random(void *arg, u_int32_t *buf, int len); ++#endif ++ ++#define HIFN_MAX_CHIPS 8 ++static struct hifn_softc *hifn_chip_idx[HIFN_MAX_CHIPS]; ++ ++static __inline u_int32_t ++READ_REG_0(struct hifn_softc *sc, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar0 + reg); ++ sc->sc_bar0_lastreg = (bus_size_t) -1; ++ return (v); ++} ++#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val) ++ ++static __inline u_int32_t ++READ_REG_1(struct hifn_softc *sc, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar1 + reg); ++ sc->sc_bar1_lastreg = (bus_size_t) -1; ++ return (v); ++} ++#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val) ++ ++/* ++ * map in a given buffer (great on some arches :-) ++ */ ++ ++static int ++pci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio) ++{ ++ struct iovec *iov = uio->uio_iov; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) { ++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, ++ iov->iov_base, iov->iov_len, ++ PCI_DMA_BIDIRECTIONAL); ++ buf->segs[buf->nsegs].ds_len = iov->iov_len; ++ buf->mapsize += iov->iov_len; ++ iov++; ++ buf->nsegs++; ++ } ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given sk_buff ++ */ ++ ++static int ++pci_map_skb(struct hifn_softc *sc,struct hifn_operand *buf,struct sk_buff *skb) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ ++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, ++ skb->data, skb_headlen(skb), PCI_DMA_BIDIRECTIONAL); ++ buf->segs[0].ds_len = skb_headlen(skb); ++ buf->mapsize += buf->segs[0].ds_len; ++ ++ buf->nsegs = 1; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; ) { ++ buf->segs[buf->nsegs].ds_len = skb_shinfo(skb)->frags[i].size; ++ buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_pcidev, ++ page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ buf->segs[buf->nsegs].ds_len, PCI_DMA_BIDIRECTIONAL); ++ buf->mapsize += buf->segs[buf->nsegs].ds_len; ++ buf->nsegs++; ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given contiguous buffer ++ */ ++ ++static int ++pci_map_buf(struct hifn_softc *sc,struct hifn_operand *buf, void *b, int len) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf->mapsize = 0; ++ buf->segs[0].ds_addr = pci_map_single(sc->sc_pcidev, ++ b, len, PCI_DMA_BIDIRECTIONAL); ++ buf->segs[0].ds_len = len; ++ buf->mapsize += buf->segs[0].ds_len; ++ buf->nsegs = 1; ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++#if 0 /* not needed at this time */ ++static void ++pci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ for (i = 0; i < buf->nsegs; i++) ++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++} ++#endif ++ ++static void ++pci_unmap_buf(struct hifn_softc *sc, struct hifn_operand *buf) ++{ ++ int i; ++ DPRINTF("%s()\n", __FUNCTION__); ++ for (i = 0; i < buf->nsegs; i++) { ++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++ buf->segs[i].ds_addr = 0; ++ buf->segs[i].ds_len = 0; ++ } ++ buf->nsegs = 0; ++ buf->mapsize = 0; ++ buf->map = 0; ++} ++ ++static const char* ++hifn_partname(struct hifn_softc *sc) ++{ ++ /* XXX sprintf numbers when not decoded */ ++ switch (pci_get_vendor(sc->sc_pcidev)) { ++ case PCI_VENDOR_HIFN: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; ++ case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; ++ case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; ++ case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; ++ case PCI_PRODUCT_HIFN_7955: return "Hifn 7955"; ++ case PCI_PRODUCT_HIFN_7956: return "Hifn 7956"; ++ } ++ return "Hifn unknown-part"; ++ case PCI_VENDOR_INVERTEX: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; ++ } ++ return "Invertex unknown-part"; ++ case PCI_VENDOR_NETSEC: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; ++ } ++ return "NetSec unknown-part"; ++ } ++ return "Unknown-vendor unknown-part"; ++} ++ ++static u_int ++checkmaxmin(struct pci_dev *dev, const char *what, u_int v, u_int min, u_int max) ++{ ++ struct hifn_softc *sc = pci_get_drvdata(dev); ++ if (v > max) { ++ device_printf(sc->sc_dev, "Warning, %s %u out of range, " ++ "using max %u\n", what, v, max); ++ v = max; ++ } else if (v < min) { ++ device_printf(sc->sc_dev, "Warning, %s %u out of range, " ++ "using min %u\n", what, v, min); ++ v = min; ++ } ++ return v; ++} ++ ++/* ++ * Select PLL configuration for 795x parts. This is complicated in ++ * that we cannot determine the optimal parameters without user input. ++ * The reference clock is derived from an external clock through a ++ * multiplier. The external clock is either the host bus (i.e. PCI) ++ * or an external clock generator. When using the PCI bus we assume ++ * the clock is either 33 or 66 MHz; for an external source we cannot ++ * tell the speed. ++ * ++ * PLL configuration is done with a string: "pci" for PCI bus, or "ext" ++ * for an external source, followed by the frequency. We calculate ++ * the appropriate multiplier and PLL register contents accordingly. ++ * When no configuration is given we default to "pci66" since that ++ * always will allow the card to work. If a card is using the PCI ++ * bus clock and in a 33MHz slot then it will be operating at half ++ * speed until the correct information is provided. ++ * ++ * We use a default setting of "ext66" because according to Mike Ham ++ * of HiFn, almost every board in existence has an external crystal ++ * populated at 66Mhz. Using PCI can be a problem on modern motherboards, ++ * because PCI33 can have clocks from 0 to 33Mhz, and some have ++ * non-PCI-compliant spread-spectrum clocks, which can confuse the pll. ++ */ ++static void ++hifn_getpllconfig(struct pci_dev *dev, u_int *pll) ++{ ++ const char *pllspec = hifn_pllconfig; ++ u_int freq, mul, fl, fh; ++ u_int32_t pllconfig; ++ char *nxt; ++ ++ if (pllspec == NULL) ++ pllspec = "ext66"; ++ fl = 33, fh = 66; ++ pllconfig = 0; ++ if (strncmp(pllspec, "ext", 3) == 0) { ++ pllspec += 3; ++ pllconfig |= HIFN_PLL_REF_SEL; ++ switch (pci_get_device(dev)) { ++ case PCI_PRODUCT_HIFN_7955: ++ case PCI_PRODUCT_HIFN_7956: ++ fl = 20, fh = 100; ++ break; ++#ifdef notyet ++ case PCI_PRODUCT_HIFN_7954: ++ fl = 20, fh = 66; ++ break; ++#endif ++ } ++ } else if (strncmp(pllspec, "pci", 3) == 0) ++ pllspec += 3; ++ freq = strtoul(pllspec, &nxt, 10); ++ if (nxt == pllspec) ++ freq = 66; ++ else ++ freq = checkmaxmin(dev, "frequency", freq, fl, fh); ++ /* ++ * Calculate multiplier. We target a Fck of 266 MHz, ++ * allowing only even values, possibly rounded down. ++ * Multipliers > 8 must set the charge pump current. ++ */ ++ mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12); ++ pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT; ++ if (mul > 8) ++ pllconfig |= HIFN_PLL_IS; ++ *pll = pllconfig; ++} ++ ++/* ++ * Attach an interface that successfully probed. ++ */ ++static int ++hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct hifn_softc *sc = NULL; ++ char rbase; ++ u_int16_t ena, rev; ++ int rseg, rc; ++ unsigned long mem_start, mem_len; ++ static int num_chips = 0; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (pci_set_mwi(dev)) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("hifn: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "hifn", num_chips, hifn_methods); ++ ++ sc->sc_pcidev = dev; ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_num = num_chips++; ++ if (sc->sc_num < HIFN_MAX_CHIPS) ++ hifn_chip_idx[sc->sc_num] = sc; ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ spin_lock_init(&sc->sc_mtx); ++ ++ /* XXX handle power management */ ++ ++ /* ++ * The 7951 and 795x have a random number generator and ++ * public key support; note this. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) ++ sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; ++ /* ++ * The 7811 has a random number generator and ++ * we also note it's identity 'cuz of some quirks. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) ++ sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; ++ ++ /* ++ * The 795x parts support AES. ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && ++ (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || ++ pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) { ++ sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES; ++ /* ++ * Select PLL configuration. This depends on the ++ * bus and board design and must be manually configured ++ * if the default setting is unacceptable. ++ */ ++ hifn_getpllconfig(dev, &sc->sc_pllconfig); ++ } ++ ++ /* ++ * Setup PCI resources. Note that we record the bus ++ * tag and handle for each register mapping, this is ++ * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, ++ * and WRITE_REG_1 macros throughout the driver. ++ */ ++ mem_start = pci_resource_start(sc->sc_pcidev, 0); ++ mem_len = pci_resource_len(sc->sc_pcidev, 0); ++ sc->sc_bar0 = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar0) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 0); ++ goto fail; ++ } ++ sc->sc_bar0_lastreg = (bus_size_t) -1; ++ ++ mem_start = pci_resource_start(sc->sc_pcidev, 1); ++ mem_len = pci_resource_len(sc->sc_pcidev, 1); ++ sc->sc_bar1 = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar1) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", 1); ++ goto fail; ++ } ++ sc->sc_bar1_lastreg = (bus_size_t) -1; ++ ++ /* fix up the bus size */ ++ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); ++ goto fail; ++ } ++ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, ++ "No usable consistent DMA configuration, aborting.\n"); ++ goto fail; ++ } ++ ++ hifn_set_retry(sc); ++ ++ /* ++ * Setup the area where the Hifn DMA's descriptors ++ * and associated data structures. ++ */ ++ sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev, ++ sizeof(*sc->sc_dma), ++ &sc->sc_dma_physaddr); ++ if (!sc->sc_dma) { ++ device_printf(sc->sc_dev, "cannot alloc sc_dma\n"); ++ goto fail; ++ } ++ bzero(sc->sc_dma, sizeof(*sc->sc_dma)); ++ ++ /* ++ * Reset the board and do the ``secret handshake'' ++ * to enable the crypto support. Then complete the ++ * initialization procedure by setting up the interrupt ++ * and hooking in to the system crypto support so we'll ++ * get used for system services like the crypto device, ++ * IPsec, RNG device, etc. ++ */ ++ hifn_reset_board(sc, 0); ++ ++ if (hifn_enable_crypto(sc) != 0) { ++ device_printf(sc->sc_dev, "crypto enabling failed\n"); ++ goto fail; ++ } ++ hifn_reset_puc(sc); ++ ++ hifn_init_dma(sc); ++ hifn_init_pci_registers(sc); ++ ++ pci_set_master(sc->sc_pcidev); ++ ++ /* XXX can't dynamically determine ram type for 795x; force dram */ ++ if (sc->sc_flags & HIFN_IS_7956) ++ sc->sc_drammodel = 1; ++ else if (hifn_ramtype(sc)) ++ goto fail; ++ ++ if (sc->sc_drammodel == 0) ++ hifn_sramsize(sc); ++ else ++ hifn_dramsize(sc); ++ ++ /* ++ * Workaround for NetSec 7751 rev A: half ram size because two ++ * of the address lines were left floating ++ */ ++ if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && ++ pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && ++ pci_get_revid(dev) == 0x61) /*XXX???*/ ++ sc->sc_ramsize >>= 1; ++ ++ /* ++ * Arrange the interrupt line. ++ */ ++ rc = request_irq(dev->irq, hifn_intr, IRQF_SHARED, "hifn", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); ++ goto fail; ++ } ++ sc->sc_irq = dev->irq; ++ ++ hifn_sessions(sc); ++ ++ /* ++ * NB: Keep only the low 16 bits; this masks the chip id ++ * from the 7951. ++ */ ++ rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; ++ ++ rseg = sc->sc_ramsize / 1024; ++ rbase = 'K'; ++ if (sc->sc_ramsize >= (1024 * 1024)) { ++ rbase = 'M'; ++ rseg /= 1024; ++ } ++ device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram", ++ hifn_partname(sc), rev, ++ rseg, rbase, sc->sc_drammodel ? 'd' : 's'); ++ if (sc->sc_flags & HIFN_IS_7956) ++ printf(", pll=0x%x<%s clk, %ux mult>", ++ sc->sc_pllconfig, ++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", ++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); ++ printf("\n"); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto fail; ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ++ READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); ++ ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++ switch (ena) { ++ case HIFN_PUSTAT_ENA_2: ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); ++ if (sc->sc_flags & HIFN_HAS_AES) ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ /*FALLTHROUGH*/ ++ case HIFN_PUSTAT_ENA_1: ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ break; ++ } ++ ++ if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) ++ hifn_init_pubrng(sc); ++ ++ init_timer(&sc->sc_tickto); ++ sc->sc_tickto.function = hifn_tick; ++ sc->sc_tickto.data = (unsigned long) sc->sc_num; ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++ ++ return (0); ++ ++fail: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_dma) { ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ pci_free_consistent(sc->sc_pcidev, ++ sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++ } ++ kfree(sc); ++ return (-ENXIO); ++} ++ ++/* ++ * Detach an interface that successfully probed. ++ */ ++static void ++hifn_remove(struct pci_dev *dev) ++{ ++ struct hifn_softc *sc = pci_get_drvdata(dev); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_detach: null software carrier!")); ++ ++ /* disable interrupts */ ++ HIFN_LOCK(sc); ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); ++ HIFN_UNLOCK(sc); ++ ++ /*XXX other resources */ ++ del_timer_sync(&sc->sc_tickto); ++ ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ free_irq(sc->sc_irq, sc); ++ ++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++} ++ ++ ++static int ++hifn_init_pubrng(struct hifn_softc *sc) ++{ ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if ((sc->sc_flags & HIFN_IS_7811) == 0) { ++ /* Reset 7951 public key/rng engine */ ++ WRITE_REG_1(sc, HIFN_1_PUB_RESET, ++ READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET); ++ ++ for (i = 0; i < 100; i++) { ++ DELAY(1000); ++ if ((READ_REG_1(sc, HIFN_1_PUB_RESET) & ++ HIFN_PUBRST_RESET) == 0) ++ break; ++ } ++ ++ if (i == 100) { ++ device_printf(sc->sc_dev, "public key init failed\n"); ++ return (1); ++ } ++ } ++ ++ /* Enable the rng, if available */ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ if (sc->sc_flags & HIFN_HAS_RNG) { ++ if (sc->sc_flags & HIFN_IS_7811) { ++ u_int32_t r; ++ r = READ_REG_1(sc, HIFN_1_7811_RNGENA); ++ if (r & HIFN_7811_RNGENA_ENA) { ++ r &= ~HIFN_7811_RNGENA_ENA; ++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); ++ } ++ WRITE_REG_1(sc, HIFN_1_7811_RNGCFG, ++ HIFN_7811_RNGCFG_DEFL); ++ r |= HIFN_7811_RNGENA_ENA; ++ WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); ++ } else ++ WRITE_REG_1(sc, HIFN_1_RNG_CONFIG, ++ READ_REG_1(sc, HIFN_1_RNG_CONFIG) | ++ HIFN_RNGCFG_ENA); ++ ++ sc->sc_rngfirst = 1; ++ crypto_rregister(sc->sc_cid, hifn_read_random, sc); ++ } ++#endif ++ ++ /* Enable public key engine, if available */ ++ if (sc->sc_flags & HIFN_HAS_PUBLIC) { ++ WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); ++ sc->sc_dmaier |= HIFN_DMAIER_PUBDONE; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++#ifdef HIFN_VULCANDEV ++ sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0, ++ UID_ROOT, GID_WHEEL, 0666, ++ "vulcanpk"); ++ sc->sc_pkdev->si_drv1 = sc; ++#endif ++ } ++ ++ return (0); ++} ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int ++hifn_read_random(void *arg, u_int32_t *buf, int len) ++{ ++ struct hifn_softc *sc = (struct hifn_softc *) arg; ++ u_int32_t sts; ++ int i, rc = 0; ++ ++ if (len <= 0) ++ return rc; ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ /* ONLY VALID ON 7811!!!! */ ++ for (i = 0; i < 5; i++) { ++ sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS); ++ if (sts & HIFN_7811_RNGSTS_UFL) { ++ device_printf(sc->sc_dev, ++ "RNG underflow: disabling\n"); ++ /* DAVIDM perhaps return -1 */ ++ break; ++ } ++ if ((sts & HIFN_7811_RNGSTS_RDY) == 0) ++ break; ++ ++ /* ++ * There are at least two words in the RNG FIFO ++ * at this point. ++ */ ++ if (rc < len) ++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); ++ if (rc < len) ++ buf[rc++] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); ++ } ++ } else ++ buf[rc++] = READ_REG_1(sc, HIFN_1_RNG_DATA); ++ ++ /* NB: discard first data read */ ++ if (sc->sc_rngfirst) { ++ sc->sc_rngfirst = 0; ++ rc = 0; ++ } ++ ++ return(rc); ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++static void ++hifn_puc_wait(struct hifn_softc *sc) ++{ ++ int i; ++ int reg = HIFN_0_PUCTRL; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ reg = HIFN_0_PUCTRL2; ++ } ++ ++ for (i = 5000; i > 0; i--) { ++ DELAY(1); ++ if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET)) ++ break; ++ } ++ if (!i) ++ device_printf(sc->sc_dev, "proc unit did not reset(0x%x)\n", ++ READ_REG_0(sc, HIFN_0_PUCTRL)); ++} ++ ++/* ++ * Reset the processing unit. ++ */ ++static void ++hifn_reset_puc(struct hifn_softc *sc) ++{ ++ /* Reset processing unit */ ++ int reg = HIFN_0_PUCTRL; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ reg = HIFN_0_PUCTRL2; ++ } ++ WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA); ++ ++ hifn_puc_wait(sc); ++} ++ ++/* ++ * Set the Retry and TRDY registers; note that we set them to ++ * zero because the 7811 locks up when forced to retry (section ++ * 3.6 of "Specification Update SU-0014-04". Not clear if we ++ * should do this for all Hifn parts, but it doesn't seem to hurt. ++ */ ++static void ++hifn_set_retry(struct hifn_softc *sc) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* NB: RETRY only responds to 8-bit reads/writes */ ++ pci_write_config_byte(sc->sc_pcidev, HIFN_RETRY_TIMEOUT, 0); ++ pci_write_config_dword(sc->sc_pcidev, HIFN_TRDY_TIMEOUT, 0); ++} ++ ++/* ++ * Resets the board. Values in the regesters are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++hifn_reset_board(struct hifn_softc *sc, int full) ++{ ++ u_int32_t reg; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* ++ * Set polling in the DMA configuration register to zero. 0x7 avoids ++ * resetting the board and zeros out the other fields. ++ */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ /* ++ * Now that polling has been disabled, we have to wait 1 ms ++ * before resetting the board. ++ */ ++ DELAY(1000); ++ ++ /* Reset the DMA unit */ ++ if (full) { ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); ++ DELAY(1000); ++ } else { ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, ++ HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET); ++ hifn_reset_puc(sc); ++ } ++ ++ KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!")); ++ bzero(sc->sc_dma, sizeof(*sc->sc_dma)); ++ ++ /* Bring dma unit out of reset */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ hifn_puc_wait(sc); ++ hifn_set_retry(sc); ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ for (reg = 0; reg < 1000; reg++) { ++ if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) & ++ HIFN_MIPSRST_CRAMINIT) ++ break; ++ DELAY(1000); ++ } ++ if (reg == 1000) ++ device_printf(sc->sc_dev, ": cram init timeout\n"); ++ } else { ++ /* set up DMA configuration register #2 */ ++ /* turn off all PK and BAR0 swaps */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG2, ++ (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)| ++ (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)| ++ (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)| ++ (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT)); ++ } ++} ++ ++static u_int32_t ++hifn_next_signature(u_int32_t a, u_int cnt) ++{ ++ int i; ++ u_int32_t v; ++ ++ for (i = 0; i < cnt; i++) { ++ ++ /* get the parity */ ++ v = a & 0x80080125; ++ v ^= v >> 16; ++ v ^= v >> 8; ++ v ^= v >> 4; ++ v ^= v >> 2; ++ v ^= v >> 1; ++ ++ a = (v & 1) ^ (a << 1); ++ } ++ ++ return a; ++} ++ ++ ++/* ++ * Checks to see if crypto is already enabled. If crypto isn't enable, ++ * "hifn_enable_crypto" is called to enable it. The check is important, ++ * as enabling crypto twice will lock the board. ++ */ ++static int ++hifn_enable_crypto(struct hifn_softc *sc) ++{ ++ u_int32_t dmacfg, ramcfg, encl, addr, i; ++ char offtbl[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00 }; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG); ++ dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG); ++ ++ /* ++ * The RAM config register's encrypt level bit needs to be set before ++ * every read performed on the encryption level register. ++ */ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); ++ ++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++ /* ++ * Make sure we don't re-unlock. Two unlocks kills chip until the ++ * next reboot. ++ */ ++ if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "Strong crypto already enabled!\n"); ++#endif ++ goto report; ++ } ++ ++ if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "Unknown encryption level 0x%x\n", encl); ++#endif ++ return 1; ++ } ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK | ++ HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ DELAY(1000); ++ addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1); ++ DELAY(1000); ++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0); ++ DELAY(1000); ++ ++ for (i = 0; i <= 12; i++) { ++ addr = hifn_next_signature(addr, offtbl[i] + 0x101); ++ WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr); ++ ++ DELAY(1000); ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); ++ encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2) ++ device_printf(sc->sc_dev, "Engine is permanently " ++ "locked until next system reset!\n"); ++ else ++ device_printf(sc->sc_dev, "Engine enabled " ++ "successfully!\n"); ++ } ++#endif ++ ++report: ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg); ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg); ++ ++ switch (encl) { ++ case HIFN_PUSTAT_ENA_1: ++ case HIFN_PUSTAT_ENA_2: ++ break; ++ case HIFN_PUSTAT_ENA_0: ++ default: ++ device_printf(sc->sc_dev, "disabled\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Give initial values to the registers listed in the "Register Space" ++ * section of the HIFN Software Development reference manual. ++ */ ++static void ++hifn_init_pci_registers(struct hifn_softc *sc) ++{ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* write fixed values needed by the Initialization registers */ ++ WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); ++ WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); ++ WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); ++ ++ /* write all 4 ring address registers */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, cmdr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, srcr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, dstr[0])); ++ WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, resr[0])); ++ ++ DELAY(2000); ++ ++ /* write status register */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | ++ HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | ++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | ++ HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | ++ HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | ++ HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | ++ HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | ++ HIFN_DMACSR_S_WAIT | ++ HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | ++ HIFN_DMACSR_C_WAIT | ++ HIFN_DMACSR_ENGINE | ++ ((sc->sc_flags & HIFN_HAS_PUBLIC) ? ++ HIFN_DMACSR_PUBDONE : 0) | ++ ((sc->sc_flags & HIFN_IS_7811) ? ++ HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0)); ++ ++ sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0; ++ sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | ++ HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | ++ HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | ++ ((sc->sc_flags & HIFN_IS_7811) ? ++ HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0); ++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ u_int32_t pll; ++ ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | ++ HIFN_PUCNFG_TCALLPHASES | ++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32); ++ ++ /* turn off the clocks and insure bypass is set */ ++ pll = READ_REG_1(sc, HIFN_1_PLL); ++ pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL)) ++ | HIFN_PLL_BP | HIFN_PLL_MBSET; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ DELAY(10*1000); /* 10ms */ ++ ++ /* change configuration */ ++ pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ DELAY(10*1000); /* 10ms */ ++ ++ /* disable bypass */ ++ pll &= ~HIFN_PLL_BP; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ /* enable clocks with new configuration */ ++ pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL; ++ WRITE_REG_1(sc, HIFN_1_PLL, pll); ++ } else { ++ WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | ++ HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | ++ HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | ++ (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM)); ++ } ++ ++ WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | ++ ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | ++ ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); ++} ++ ++/* ++ * The maximum number of sessions supported by the card ++ * is dependent on the amount of context ram, which ++ * encryption algorithms are enabled, and how compression ++ * is configured. This should be configured before this ++ * routine is called. ++ */ ++static void ++hifn_sessions(struct hifn_softc *sc) ++{ ++ u_int32_t pucnfg; ++ int ctxsize; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG); ++ ++ if (pucnfg & HIFN_PUCNFG_COMPSING) { ++ if (pucnfg & HIFN_PUCNFG_ENCCNFG) ++ ctxsize = 128; ++ else ++ ctxsize = 512; ++ /* ++ * 7955/7956 has internal context memory of 32K ++ */ ++ if (sc->sc_flags & HIFN_IS_7956) ++ sc->sc_maxses = 32768 / ctxsize; ++ else ++ sc->sc_maxses = 1 + ++ ((sc->sc_ramsize - 32768) / ctxsize); ++ } else ++ sc->sc_maxses = sc->sc_ramsize / 16384; ++ ++ if (sc->sc_maxses > 2048) ++ sc->sc_maxses = 2048; ++} ++ ++/* ++ * Determine ram type (sram or dram). Board should be just out of a reset ++ * state when this is called. ++ */ ++static int ++hifn_ramtype(struct hifn_softc *sc) ++{ ++ u_int8_t data[8], dataexpect[8]; ++ int i; ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = 0x55; ++ if (hifn_writeramaddr(sc, 0, data)) ++ return (-1); ++ if (hifn_readramaddr(sc, 0, data)) ++ return (-1); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) { ++ sc->sc_drammodel = 1; ++ return (0); ++ } ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = 0xaa; ++ if (hifn_writeramaddr(sc, 0, data)) ++ return (-1); ++ if (hifn_readramaddr(sc, 0, data)) ++ return (-1); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) { ++ sc->sc_drammodel = 1; ++ return (0); ++ } ++ ++ return (0); ++} ++ ++#define HIFN_SRAM_MAX (32 << 20) ++#define HIFN_SRAM_STEP_SIZE 16384 ++#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE) ++ ++static int ++hifn_sramsize(struct hifn_softc *sc) ++{ ++ u_int32_t a; ++ u_int8_t data[8]; ++ u_int8_t dataexpect[sizeof(data)]; ++ int32_t i; ++ ++ for (i = 0; i < sizeof(data); i++) ++ data[i] = dataexpect[i] = i ^ 0x5a; ++ ++ for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) { ++ a = i * HIFN_SRAM_STEP_SIZE; ++ bcopy(&i, data, sizeof(i)); ++ hifn_writeramaddr(sc, a, data); ++ } ++ ++ for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) { ++ a = i * HIFN_SRAM_STEP_SIZE; ++ bcopy(&i, dataexpect, sizeof(i)); ++ if (hifn_readramaddr(sc, a, data) < 0) ++ return (0); ++ if (bcmp(data, dataexpect, sizeof(data)) != 0) ++ return (0); ++ sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE; ++ } ++ ++ return (0); ++} ++ ++/* ++ * XXX For dram boards, one should really try all of the ++ * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG ++ * is already set up correctly. ++ */ ++static int ++hifn_dramsize(struct hifn_softc *sc) ++{ ++ u_int32_t cnfg; ++ ++ if (sc->sc_flags & HIFN_IS_7956) { ++ /* ++ * 7955/7956 have a fixed internal ram of only 32K. ++ */ ++ sc->sc_ramsize = 32768; ++ } else { ++ cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) & ++ HIFN_PUCNFG_DRAMMASK; ++ sc->sc_ramsize = 1 << ((cnfg >> 13) + 18); ++ } ++ return (0); ++} ++ ++static void ++hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (dma->cmdi == HIFN_D_CMD_RSIZE) { ++ dma->cmdi = 0; ++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *cmdp = dma->cmdi++; ++ dma->cmdk = dma->cmdi; ++ ++ if (dma->srci == HIFN_D_SRC_RSIZE) { ++ dma->srci = 0; ++ dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->srcr[HIFN_D_SRC_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *srcp = dma->srci++; ++ dma->srck = dma->srci; ++ ++ if (dma->dsti == HIFN_D_DST_RSIZE) { ++ dma->dsti = 0; ++ dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->dstr[HIFN_D_DST_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *dstp = dma->dsti++; ++ dma->dstk = dma->dsti; ++ ++ if (dma->resi == HIFN_D_RES_RSIZE) { ++ dma->resi = 0; ++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ *resp = dma->resi++; ++ dma->resk = dma->resi; ++} ++ ++static int ++hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ hifn_base_command_t wc; ++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; ++ int r, cmdi, resi, srci, dsti; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ wc.masks = htole16(3 << 13); ++ wc.session_num = htole16(addr >> 14); ++ wc.total_source_count = htole16(8); ++ wc.total_dest_count = htole16(addr & 0x3fff); ++ ++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | ++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); ++ ++ /* build write command */ ++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); ++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc; ++ bcopy(data, &dma->test_src, sizeof(dma->test_src)); ++ ++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr ++ + offsetof(struct hifn_dma, test_src)); ++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr ++ + offsetof(struct hifn_dma, test_dst)); ++ ++ dma->cmdr[cmdi].l = htole32(16 | masks); ++ dma->srcr[srci].l = htole32(8 | masks); ++ dma->dstr[dsti].l = htole32(4 | masks); ++ dma->resr[resi].l = htole32(4 | masks); ++ ++ for (r = 10000; r >= 0; r--) { ++ DELAY(10); ++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) ++ break; ++ } ++ if (r == 0) { ++ device_printf(sc->sc_dev, "writeramaddr -- " ++ "result[%d](addr %d) still valid\n", resi, addr); ++ r = -1; ++ return (-1); ++ } else ++ r = 0; ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); ++ ++ return (r); ++} ++ ++static int ++hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ hifn_base_command_t rc; ++ const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; ++ int r, cmdi, srci, dsti, resi; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ rc.masks = htole16(2 << 13); ++ rc.session_num = htole16(addr >> 14); ++ rc.total_source_count = htole16(addr & 0x3fff); ++ rc.total_dest_count = htole16(8); ++ ++ hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | ++ HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); ++ ++ bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); ++ *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc; ++ ++ dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, test_src)); ++ dma->test_src = 0; ++ dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, test_dst)); ++ dma->test_dst = 0; ++ dma->cmdr[cmdi].l = htole32(8 | masks); ++ dma->srcr[srci].l = htole32(8 | masks); ++ dma->dstr[dsti].l = htole32(8 | masks); ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks); ++ ++ for (r = 10000; r >= 0; r--) { ++ DELAY(10); ++ if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) ++ break; ++ } ++ if (r == 0) { ++ device_printf(sc->sc_dev, "readramaddr -- " ++ "result[%d](addr %d) still valid\n", resi, addr); ++ r = -1; ++ } else { ++ r = 0; ++ bcopy(&dma->test_dst, data, sizeof(dma->test_dst)); ++ } ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, ++ HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | ++ HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); ++ ++ return (r); ++} ++ ++/* ++ * Initialize the descriptor rings. ++ */ ++static void ++hifn_init_dma(struct hifn_softc *sc) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ hifn_set_retry(sc); ++ ++ /* initialize static pointer values */ ++ for (i = 0; i < HIFN_D_CMD_RSIZE; i++) ++ dma->cmdr[i].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, command_bufs[i][0])); ++ for (i = 0; i < HIFN_D_RES_RSIZE; i++) ++ dma->resr[i].p = htole32(sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, result_bufs[i][0])); ++ ++ dma->cmdr[HIFN_D_CMD_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0])); ++ dma->srcr[HIFN_D_SRC_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0])); ++ dma->dstr[HIFN_D_DST_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0])); ++ dma->resr[HIFN_D_RES_RSIZE].p = ++ htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); ++ ++ dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; ++ dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; ++ dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; ++} ++ ++/* ++ * Writes out the raw command buffer space. Returns the ++ * command buffer size. ++ */ ++static u_int ++hifn_write_command(struct hifn_command *cmd, u_int8_t *buf) ++{ ++ struct hifn_softc *sc = NULL; ++ u_int8_t *buf_pos; ++ hifn_base_command_t *base_cmd; ++ hifn_mac_command_t *mac_cmd; ++ hifn_crypt_command_t *cry_cmd; ++ int using_mac, using_crypt, len, ivlen; ++ u_int32_t dlen, slen; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ buf_pos = buf; ++ using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC; ++ using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT; ++ ++ base_cmd = (hifn_base_command_t *)buf_pos; ++ base_cmd->masks = htole16(cmd->base_masks); ++ slen = cmd->src_mapsize; ++ if (cmd->sloplen) ++ dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t); ++ else ++ dlen = cmd->dst_mapsize; ++ base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO); ++ base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO); ++ dlen >>= 16; ++ slen >>= 16; ++ base_cmd->session_num = htole16( ++ ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | ++ ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); ++ buf_pos += sizeof(hifn_base_command_t); ++ ++ if (using_mac) { ++ mac_cmd = (hifn_mac_command_t *)buf_pos; ++ dlen = cmd->maccrd->crd_len; ++ mac_cmd->source_count = htole16(dlen & 0xffff); ++ dlen >>= 16; ++ mac_cmd->masks = htole16(cmd->mac_masks | ++ ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M)); ++ mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip); ++ mac_cmd->reserved = 0; ++ buf_pos += sizeof(hifn_mac_command_t); ++ } ++ ++ if (using_crypt) { ++ cry_cmd = (hifn_crypt_command_t *)buf_pos; ++ dlen = cmd->enccrd->crd_len; ++ cry_cmd->source_count = htole16(dlen & 0xffff); ++ dlen >>= 16; ++ cry_cmd->masks = htole16(cmd->cry_masks | ++ ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M)); ++ cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip); ++ cry_cmd->reserved = 0; ++ buf_pos += sizeof(hifn_crypt_command_t); ++ } ++ ++ if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) { ++ bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH); ++ buf_pos += HIFN_MAC_KEY_LENGTH; ++ } ++ ++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) { ++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { ++ case HIFN_CRYPT_CMD_ALG_3DES: ++ bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH); ++ buf_pos += HIFN_3DES_KEY_LENGTH; ++ break; ++ case HIFN_CRYPT_CMD_ALG_DES: ++ bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH); ++ buf_pos += HIFN_DES_KEY_LENGTH; ++ break; ++ case HIFN_CRYPT_CMD_ALG_RC4: ++ len = 256; ++ do { ++ int clen; ++ ++ clen = MIN(cmd->cklen, len); ++ bcopy(cmd->ck, buf_pos, clen); ++ len -= clen; ++ buf_pos += clen; ++ } while (len > 0); ++ bzero(buf_pos, 4); ++ buf_pos += 4; ++ break; ++ case HIFN_CRYPT_CMD_ALG_AES: ++ /* ++ * AES keys are variable 128, 192 and ++ * 256 bits (16, 24 and 32 bytes). ++ */ ++ bcopy(cmd->ck, buf_pos, cmd->cklen); ++ buf_pos += cmd->cklen; ++ break; ++ } ++ } ++ ++ if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) { ++ switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { ++ case HIFN_CRYPT_CMD_ALG_AES: ++ ivlen = HIFN_AES_IV_LENGTH; ++ break; ++ default: ++ ivlen = HIFN_IV_LENGTH; ++ break; ++ } ++ bcopy(cmd->iv, buf_pos, ivlen); ++ buf_pos += ivlen; ++ } ++ ++ if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) { ++ bzero(buf_pos, 8); ++ buf_pos += 8; ++ } ++ ++ return (buf_pos - buf); ++} ++ ++static int ++hifn_dmamap_aligned(struct hifn_operand *op) ++{ ++ struct hifn_softc *sc = NULL; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ for (i = 0; i < op->nsegs; i++) { ++ if (op->segs[i].ds_addr & 3) ++ return (0); ++ if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3)) ++ return (0); ++ } ++ return (1); ++} ++ ++static __inline int ++hifn_dmamap_dstwrap(struct hifn_softc *sc, int idx) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ if (++idx == HIFN_D_DST_RSIZE) { ++ dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | ++ HIFN_D_MASKDONEIRQ); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ idx = 0; ++ } ++ return (idx); ++} ++ ++static int ++hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_operand *dst = &cmd->dst; ++ u_int32_t p, l; ++ int idx, used = 0, i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ idx = dma->dsti; ++ for (i = 0; i < dst->nsegs - 1; i++) { ++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); ++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ } ++ ++ if (cmd->sloplen == 0) { ++ p = dst->segs[i].ds_addr; ++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | ++ dst->segs[i].ds_len; ++ } else { ++ p = sc->sc_dma_physaddr + ++ offsetof(struct hifn_dma, slop[cmd->slopidx]); ++ l = HIFN_D_MASKDONEIRQ | HIFN_D_LAST | ++ sizeof(u_int32_t); ++ ++ if ((dst->segs[i].ds_len - cmd->sloplen) != 0) { ++ dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); ++ dma->dstr[idx].l = htole32(HIFN_D_MASKDONEIRQ | ++ (dst->segs[i].ds_len - cmd->sloplen)); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ } ++ } ++ dma->dstr[idx].p = htole32(p); ++ dma->dstr[idx].l = htole32(l); ++ wmb(); ++ dma->dstr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ used++; ++ ++ idx = hifn_dmamap_dstwrap(sc, idx); ++ ++ dma->dsti = idx; ++ dma->dstu += used; ++ return (idx); ++} ++ ++static __inline int ++hifn_dmamap_srcwrap(struct hifn_softc *sc, int idx) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ ++ if (++idx == HIFN_D_SRC_RSIZE) { ++ dma->srcr[idx].l = htole32(HIFN_D_VALID | ++ HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); ++ HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ idx = 0; ++ } ++ return (idx); ++} ++ ++static int ++hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_operand *src = &cmd->src; ++ int idx, i; ++ u_int32_t last = 0; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ idx = dma->srci; ++ for (i = 0; i < src->nsegs; i++) { ++ if (i == src->nsegs - 1) ++ last = HIFN_D_LAST; ++ ++ dma->srcr[idx].p = htole32(src->segs[i].ds_addr); ++ dma->srcr[idx].l = htole32(src->segs[i].ds_len | ++ HIFN_D_MASKDONEIRQ | last); ++ wmb(); ++ dma->srcr[idx].l |= htole32(HIFN_D_VALID); ++ HIFN_SRCR_SYNC(sc, idx, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ ++ idx = hifn_dmamap_srcwrap(sc, idx); ++ } ++ dma->srci = idx; ++ dma->srcu += src->nsegs; ++ return (idx); ++} ++ ++ ++static int ++hifn_crypto( ++ struct hifn_softc *sc, ++ struct hifn_command *cmd, ++ struct cryptop *crp, ++ int hint) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ u_int32_t cmdlen, csr; ++ int cmdi, resi, err = 0; ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* ++ * need 1 cmd, and 1 res ++ * ++ * NB: check this first since it's easy. ++ */ ++ HIFN_LOCK(sc); ++ if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE || ++ (dma->resu + 1) > HIFN_D_RES_RSIZE) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "cmd/result exhaustion, cmdu %u resu %u\n", ++ dma->cmdu, dma->resu); ++ } ++#endif ++ hifnstats.hst_nomem_cr++; ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ HIFN_UNLOCK(sc); ++ return (ERESTART); ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &cmd->src, cmd->src_skb)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &cmd->src, cmd->src_io)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } else { ++ if (pci_map_buf(sc, &cmd->src, cmd->src_buf, crp->crp_ilen)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_srcmap1; ++ } ++ } ++ ++ if (hifn_dmamap_aligned(&cmd->src)) { ++ cmd->sloplen = cmd->src_mapsize & 3; ++ cmd->dst = cmd->src; ++ } else { ++ if (crp->crp_flags & CRYPTO_F_IOV) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto err_srcmap; ++ } else if (crp->crp_flags & CRYPTO_F_SKBUF) { ++#ifdef NOTYET ++ int totlen, len; ++ struct mbuf *m, *m0, *mlast; ++ ++ KASSERT(cmd->dst_m == cmd->src_m, ++ ("hifn_crypto: dst_m initialized improperly")); ++ hifnstats.hst_unaligned++; ++ /* ++ * Source is not aligned on a longword boundary. ++ * Copy the data to insure alignment. If we fail ++ * to allocate mbufs or clusters while doing this ++ * we return ERESTART so the operation is requeued ++ * at the crypto later, but only if there are ++ * ops already posted to the hardware; otherwise we ++ * have no guarantee that we'll be re-entered. ++ */ ++ totlen = cmd->src_mapsize; ++ if (cmd->src_m->m_flags & M_PKTHDR) { ++ len = MHLEN; ++ MGETHDR(m0, M_DONTWAIT, MT_DATA); ++ if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) { ++ m_free(m0); ++ m0 = NULL; ++ } ++ } else { ++ len = MLEN; ++ MGET(m0, M_DONTWAIT, MT_DATA); ++ } ++ if (m0 == NULL) { ++ hifnstats.hst_nomem_mbuf++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ goto err_srcmap; ++ } ++ if (totlen >= MINCLSIZE) { ++ MCLGET(m0, M_DONTWAIT); ++ if ((m0->m_flags & M_EXT) == 0) { ++ hifnstats.hst_nomem_mcl++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MCLBYTES; ++ } ++ totlen -= len; ++ m0->m_pkthdr.len = m0->m_len = len; ++ mlast = m0; ++ ++ while (totlen > 0) { ++ MGET(m, M_DONTWAIT, MT_DATA); ++ if (m == NULL) { ++ hifnstats.hst_nomem_mbuf++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MLEN; ++ if (totlen >= MINCLSIZE) { ++ MCLGET(m, M_DONTWAIT); ++ if ((m->m_flags & M_EXT) == 0) { ++ hifnstats.hst_nomem_mcl++; ++ err = dma->cmdu ? ERESTART : ENOMEM; ++ mlast->m_next = m; ++ m_freem(m0); ++ goto err_srcmap; ++ } ++ len = MCLBYTES; ++ } ++ ++ m->m_len = len; ++ m0->m_pkthdr.len += len; ++ totlen -= len; ++ ++ mlast->m_next = m; ++ mlast = m; ++ } ++ cmd->dst_m = m0; ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF unaligned not implemented\n", ++ __FILE__, __LINE__); ++ err = EINVAL; ++ goto err_srcmap; ++#endif ++ } else { ++ device_printf(sc->sc_dev, ++ "%s,%d: unaligned contig buffers not implemented\n", ++ __FILE__, __LINE__); ++ err = EINVAL; ++ goto err_srcmap; ++ } ++ } ++ ++ if (cmd->dst_map == NULL) { ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &cmd->dst, cmd->dst_skb)) { ++ hifnstats.hst_nomem_map++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &cmd->dst, cmd->dst_io)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } else { ++ if (pci_map_buf(sc, &cmd->dst, cmd->dst_buf, crp->crp_ilen)) { ++ hifnstats.hst_nomem_load++; ++ err = ENOMEM; ++ goto err_dstmap1; ++ } ++ } ++ } ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", ++ READ_REG_1(sc, HIFN_1_DMA_CSR), ++ READ_REG_1(sc, HIFN_1_DMA_IER), ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu, ++ cmd->src_nsegs, cmd->dst_nsegs); ++ } ++#endif ++ ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_PREWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_PREREAD); ++ } ++#endif ++ ++ /* ++ * need N src, and N dst ++ */ ++ if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || ++ (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", ++ dma->srcu, cmd->src_nsegs, ++ dma->dstu, cmd->dst_nsegs); ++ } ++#endif ++ hifnstats.hst_nomem_sd++; ++ err = ERESTART; ++ goto err_dstmap; ++ } ++ ++ if (dma->cmdi == HIFN_D_CMD_RSIZE) { ++ dma->cmdi = 0; ++ dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[HIFN_D_CMD_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ } ++ cmdi = dma->cmdi++; ++ cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); ++ HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); ++ ++ /* .p for command/result already set */ ++ dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_LAST | ++ HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->cmdr[cmdi].l |= htole32(HIFN_D_VALID); ++ HIFN_CMDR_SYNC(sc, cmdi, ++ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); ++ dma->cmdu++; ++ ++ /* ++ * We don't worry about missing an interrupt (which a "command wait" ++ * interrupt salvages us from), unless there is more than one command ++ * in the queue. ++ */ ++ if (dma->cmdu > 1) { ++ sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ } ++ ++ hifnstats.hst_ipackets++; ++ hifnstats.hst_ibytes += cmd->src_mapsize; ++ ++ hifn_dmamap_load_src(sc, cmd); ++ ++ /* ++ * Unlike other descriptors, we don't mask done interrupt from ++ * result descriptor. ++ */ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, "load res\n"); ++#endif ++ if (dma->resi == HIFN_D_RES_RSIZE) { ++ dma->resi = 0; ++ dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_JUMP|HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[HIFN_D_RES_RSIZE].l |= htole32(HIFN_D_VALID); ++ HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ } ++ resi = dma->resi++; ++ KASSERT(dma->hifn_commands[resi] == NULL, ++ ("hifn_crypto: command slot %u busy", resi)); ++ dma->hifn_commands[resi] = cmd; ++ HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); ++ if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | ++ HIFN_D_LAST | HIFN_D_MASKDONEIRQ); ++ wmb(); ++ dma->resr[resi].l |= htole32(HIFN_D_VALID); ++ sc->sc_curbatch++; ++ if (sc->sc_curbatch > hifnstats.hst_maxbatch) ++ hifnstats.hst_maxbatch = sc->sc_curbatch; ++ hifnstats.hst_totbatch++; ++ } else { ++ dma->resr[resi].l = htole32(HIFN_MAX_RESULT | HIFN_D_LAST); ++ wmb(); ++ dma->resr[resi].l |= htole32(HIFN_D_VALID); ++ sc->sc_curbatch = 0; ++ } ++ HIFN_RESR_SYNC(sc, resi, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ dma->resu++; ++ ++ if (cmd->sloplen) ++ cmd->slopidx = resi; ++ ++ hifn_dmamap_load_dst(sc, cmd); ++ ++ csr = 0; ++ if (sc->sc_c_busy == 0) { ++ csr |= HIFN_DMACSR_C_CTRL_ENA; ++ sc->sc_c_busy = 1; ++ } ++ if (sc->sc_s_busy == 0) { ++ csr |= HIFN_DMACSR_S_CTRL_ENA; ++ sc->sc_s_busy = 1; ++ } ++ if (sc->sc_r_busy == 0) { ++ csr |= HIFN_DMACSR_R_CTRL_ENA; ++ sc->sc_r_busy = 1; ++ } ++ if (sc->sc_d_busy == 0) { ++ csr |= HIFN_DMACSR_D_CTRL_ENA; ++ sc->sc_d_busy = 1; ++ } ++ if (csr) ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr); ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, "command: stat %8x ier %8x\n", ++ READ_REG_1(sc, HIFN_1_DMA_CSR), ++ READ_REG_1(sc, HIFN_1_DMA_IER)); ++ } ++#endif ++ ++ sc->sc_active = 5; ++ HIFN_UNLOCK(sc); ++ KASSERT(err == 0, ("hifn_crypto: success with error %u", err)); ++ return (err); /* success */ ++ ++err_dstmap: ++ if (cmd->src_map != cmd->dst_map) ++ pci_unmap_buf(sc, &cmd->dst); ++err_dstmap1: ++err_srcmap: ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (cmd->src_skb != cmd->dst_skb) ++#ifdef NOTYET ++ m_freem(cmd->dst_m); ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ pci_unmap_buf(sc, &cmd->src); ++err_srcmap1: ++ HIFN_UNLOCK(sc); ++ return (err); ++} ++ ++static void ++hifn_tick(unsigned long arg) ++{ ++ struct hifn_softc *sc; ++ unsigned long l_flags; ++ ++ if (arg >= HIFN_MAX_CHIPS) ++ return; ++ sc = hifn_chip_idx[arg]; ++ if (!sc) ++ return; ++ ++ HIFN_LOCK(sc); ++ if (sc->sc_active == 0) { ++ struct hifn_dma *dma = sc->sc_dma; ++ u_int32_t r = 0; ++ ++ if (dma->cmdu == 0 && sc->sc_c_busy) { ++ sc->sc_c_busy = 0; ++ r |= HIFN_DMACSR_C_CTRL_DIS; ++ } ++ if (dma->srcu == 0 && sc->sc_s_busy) { ++ sc->sc_s_busy = 0; ++ r |= HIFN_DMACSR_S_CTRL_DIS; ++ } ++ if (dma->dstu == 0 && sc->sc_d_busy) { ++ sc->sc_d_busy = 0; ++ r |= HIFN_DMACSR_D_CTRL_DIS; ++ } ++ if (dma->resu == 0 && sc->sc_r_busy) { ++ sc->sc_r_busy = 0; ++ r |= HIFN_DMACSR_R_CTRL_DIS; ++ } ++ if (r) ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, r); ++ } else ++ sc->sc_active--; ++ HIFN_UNLOCK(sc); ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++} ++ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++hifn_intr(int irq, void *arg) ++#else ++hifn_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct hifn_softc *sc = arg; ++ struct hifn_dma *dma; ++ u_int32_t dmacsr, restart; ++ int i, u; ++ unsigned long l_flags; ++ ++ dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR); ++ ++ /* Nothing in the DMA unit interrupted */ ++ if ((dmacsr & sc->sc_dmaier) == 0) ++ return IRQ_NONE; ++ ++ HIFN_LOCK(sc); ++ ++ dma = sc->sc_dma; ++ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) { ++ device_printf(sc->sc_dev, ++ "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", ++ dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, ++ dma->cmdi, dma->srci, dma->dsti, dma->resi, ++ dma->cmdk, dma->srck, dma->dstk, dma->resk, ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu); ++ } ++#endif ++ ++ WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier); ++ ++ if ((sc->sc_flags & HIFN_HAS_PUBLIC) && ++ (dmacsr & HIFN_DMACSR_PUBDONE)) ++ WRITE_REG_1(sc, HIFN_1_PUB_STATUS, ++ READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); ++ ++ restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER); ++ if (restart) ++ device_printf(sc->sc_dev, "overrun %x\n", dmacsr); ++ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (dmacsr & HIFN_DMACSR_ILLR) ++ device_printf(sc->sc_dev, "illegal read\n"); ++ if (dmacsr & HIFN_DMACSR_ILLW) ++ device_printf(sc->sc_dev, "illegal write\n"); ++ } ++ ++ restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | ++ HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); ++ if (restart) { ++ device_printf(sc->sc_dev, "abort, resetting.\n"); ++ hifnstats.hst_abort++; ++ hifn_abort(sc); ++ HIFN_UNLOCK(sc); ++ return IRQ_HANDLED; ++ } ++ ++ if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { ++ /* ++ * If no slots to process and we receive a "waiting on ++ * command" interrupt, we disable the "waiting on command" ++ * (by clearing it). ++ */ ++ sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); ++ } ++ ++ /* clear the rings */ ++ i = dma->resk; u = dma->resu; ++ while (u != 0) { ++ HIFN_RESR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->resr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_RESR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ ++ if (i != HIFN_D_RES_RSIZE) { ++ struct hifn_command *cmd; ++ u_int8_t *macbuf = NULL; ++ ++ HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); ++ cmd = dma->hifn_commands[i]; ++ KASSERT(cmd != NULL, ++ ("hifn_intr: null command slot %u", i)); ++ dma->hifn_commands[i] = NULL; ++ ++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) { ++ macbuf = dma->result_bufs[i]; ++ macbuf += 12; ++ } ++ ++ hifn_callback(sc, cmd, macbuf); ++ hifnstats.hst_opackets++; ++ u--; ++ } ++ ++ if (++i == (HIFN_D_RES_RSIZE + 1)) ++ i = 0; ++ } ++ dma->resk = i; dma->resu = u; ++ ++ i = dma->srck; u = dma->srcu; ++ while (u != 0) { ++ if (i == HIFN_D_SRC_RSIZE) ++ i = 0; ++ HIFN_SRCR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->srcr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_SRCR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ i++, u--; ++ } ++ dma->srck = i; dma->srcu = u; ++ ++ i = dma->cmdk; u = dma->cmdu; ++ while (u != 0) { ++ HIFN_CMDR_SYNC(sc, i, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++ if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) { ++ HIFN_CMDR_SYNC(sc, i, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++ break; ++ } ++ if (i != HIFN_D_CMD_RSIZE) { ++ u--; ++ HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE); ++ } ++ if (++i == (HIFN_D_CMD_RSIZE + 1)) ++ i = 0; ++ } ++ dma->cmdk = i; dma->cmdu = u; ++ ++ HIFN_UNLOCK(sc); ++ ++ if (sc->sc_needwakeup) { /* XXX check high watermark */ ++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, ++ "wakeup crypto (%x) u %d/%d/%d/%d\n", ++ sc->sc_needwakeup, ++ dma->cmdu, dma->srcu, dma->dstu, dma->resu); ++#endif ++ sc->sc_needwakeup &= ~wakeup; ++ crypto_unblock(sc->sc_cid, wakeup); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Allocate a new 'session' and return an encoded session id. 'sidp' ++ * contains our registration id, and should contain an encoded session ++ * id on successful allocation. ++ */ ++static int ++hifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ struct cryptoini *c; ++ int mac = 0, cry = 0, sesn; ++ struct hifn_session *ses = NULL; ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_newsession: null softc")); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n", __FILE__, __LINE__, __FUNCTION__); ++ return (EINVAL); ++ } ++ ++ HIFN_LOCK(sc); ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct hifn_session *)kmalloc(sizeof(*ses), ++ SLAB_ATOMIC); ++ if (ses == NULL) { ++ HIFN_UNLOCK(sc); ++ return (ENOMEM); ++ } ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (!sc->sc_sessions[sesn].hs_used) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sesn = sc->sc_nsessions; ++ ses = (struct hifn_session *)kmalloc((sesn + 1) * sizeof(*ses), ++ SLAB_ATOMIC); ++ if (ses == NULL) { ++ HIFN_UNLOCK(sc); ++ return (ENOMEM); ++ } ++ bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); ++ bzero(sc->sc_sessions, sesn * sizeof(*ses)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ HIFN_UNLOCK(sc); ++ ++ bzero(ses, sizeof(*ses)); ++ ses->hs_used = 1; ++ ++ for (c = cri; c != NULL; c = c->cri_next) { ++ switch (c->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_SHA1: ++ case CRYPTO_MD5_HMAC: ++ case CRYPTO_SHA1_HMAC: ++ if (mac) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ mac = 1; ++ ses->hs_mlen = c->cri_mlen; ++ if (ses->hs_mlen == 0) { ++ switch (c->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ ses->hs_mlen = 16; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ ses->hs_mlen = 20; ++ break; ++ } ++ } ++ break; ++ case CRYPTO_DES_CBC: ++ case CRYPTO_3DES_CBC: ++ case CRYPTO_AES_CBC: ++ /* XXX this may read fewer, does it matter? */ ++ read_random(ses->hs_iv, ++ c->cri_alg == CRYPTO_AES_CBC ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ /*FALLTHROUGH*/ ++ case CRYPTO_ARC4: ++ if (cry) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ cry = 1; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ } ++ if (mac == 0 && cry == 0) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ ++ *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn); ++ ++ return (0); ++} ++ ++/* ++ * Deallocate a session. ++ * XXX this routine should run a zero'd mac/encrypt key into context ram. ++ * XXX to blow away any keys already stored there. ++ */ ++static int ++hifn_freesession(device_t dev, u_int64_t tid) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ int session, error; ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ KASSERT(sc != NULL, ("hifn_freesession: null softc")); ++ if (sc == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ ++ HIFN_LOCK(sc); ++ session = HIFN_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ bzero(&sc->sc_sessions[session], sizeof(struct hifn_session)); ++ error = 0; ++ } else { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ error = EINVAL; ++ } ++ HIFN_UNLOCK(sc); ++ ++ return (error); ++} ++ ++static int ++hifn_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct hifn_softc *sc = device_get_softc(dev); ++ struct hifn_command *cmd = NULL; ++ int session, err, ivlen; ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL) { ++ hifnstats.hst_invalid++; ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ return (EINVAL); ++ } ++ session = HIFN_SESSION(crp->crp_sid); ++ ++ if (sc == NULL || session >= sc->sc_nsessions) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ ++ cmd = kmalloc(sizeof(struct hifn_command), SLAB_ATOMIC); ++ if (cmd == NULL) { ++ hifnstats.hst_nomem++; ++ err = ENOMEM; ++ goto errout; ++ } ++ memset(cmd, 0, sizeof(*cmd)); ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ cmd->src_skb = (struct sk_buff *)crp->crp_buf; ++ cmd->dst_skb = (struct sk_buff *)crp->crp_buf; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ cmd->src_io = (struct uio *)crp->crp_buf; ++ cmd->dst_io = (struct uio *)crp->crp_buf; ++ } else { ++ cmd->src_buf = crp->crp_buf; ++ cmd->dst_buf = crp->crp_buf; ++ } ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ if (crd2 == NULL) { ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1 || ++ crd1->crd_alg == CRYPTO_MD5) { ++ maccrd = crd1; ++ enccrd = NULL; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4) { ++ if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0) ++ cmd->base_masks |= HIFN_BASE_CMD_DECODE; ++ maccrd = NULL; ++ enccrd = crd1; ++ } else { ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_MD5 || ++ crd1->crd_alg == CRYPTO_SHA1) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_ARC4) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ cmd->base_masks = HIFN_BASE_CMD_DECODE; ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4 || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_MD5 || ++ crd2->crd_alg == CRYPTO_SHA1) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ /* ++ * We cannot order the 7751 as requested ++ */ ++ DPRINTF("%s,%d: %s %d,%d,%d - EINVAL\n",__FILE__,__LINE__,__FUNCTION__, crd1->crd_alg, crd2->crd_alg, crd1->crd_flags & CRD_F_ENCRYPT); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ ++ if (enccrd) { ++ cmd->enccrd = enccrd; ++ cmd->base_masks |= HIFN_BASE_CMD_CRYPT; ++ switch (enccrd->crd_alg) { ++ case CRYPTO_ARC4: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4; ++ break; ++ case CRYPTO_DES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ case CRYPTO_3DES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ case CRYPTO_AES_CBC: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES | ++ HIFN_CRYPT_CMD_MODE_CBC | ++ HIFN_CRYPT_CMD_NEW_IV; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ if (enccrd->crd_alg != CRYPTO_ARC4) { ++ ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ bcopy(enccrd->crd_iv, cmd->iv, ivlen); ++ else ++ bcopy(sc->sc_sessions[session].hs_iv, ++ cmd->iv, ivlen); ++ ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) ++ == 0) { ++ crypto_copyback(crp->crp_flags, ++ crp->crp_buf, enccrd->crd_inject, ++ ivlen, cmd->iv); ++ } ++ } else { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ bcopy(enccrd->crd_iv, cmd->iv, ivlen); ++ else { ++ crypto_copydata(crp->crp_flags, ++ crp->crp_buf, enccrd->crd_inject, ++ ivlen, cmd->iv); ++ } ++ } ++ } ++ ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) ++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; ++ cmd->ck = enccrd->crd_key; ++ cmd->cklen = enccrd->crd_klen >> 3; ++ cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; ++ ++ /* ++ * Need to specify the size for the AES key in the masks. ++ */ ++ if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) == ++ HIFN_CRYPT_CMD_ALG_AES) { ++ switch (cmd->cklen) { ++ case 16: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128; ++ break; ++ case 24: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192; ++ break; ++ case 32: ++ cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256; ++ break; ++ default: ++ DPRINTF("%s,%d: %s - EINVAL\n",__FILE__,__LINE__,__FUNCTION__); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ } ++ ++ if (maccrd) { ++ cmd->maccrd = maccrd; ++ cmd->base_masks |= HIFN_BASE_CMD_MAC; ++ ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | ++ HIFN_MAC_CMD_POS_IPSEC; ++ break; ++ case CRYPTO_MD5_HMAC: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | ++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; ++ break; ++ case CRYPTO_SHA1: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | ++ HIFN_MAC_CMD_POS_IPSEC; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | ++ HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | ++ HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; ++ break; ++ } ++ ++ if (maccrd->crd_alg == CRYPTO_SHA1_HMAC || ++ maccrd->crd_alg == CRYPTO_MD5_HMAC) { ++ cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY; ++ bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3); ++ bzero(cmd->mac + (maccrd->crd_klen >> 3), ++ HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3)); ++ } ++ } ++ ++ cmd->crp = crp; ++ cmd->session_num = session; ++ cmd->softc = sc; ++ ++ err = hifn_crypto(sc, cmd, crp, hint); ++ if (!err) { ++ return 0; ++ } else if (err == ERESTART) { ++ /* ++ * There weren't enough resources to dispatch the request ++ * to the part. Notify the caller so they'll requeue this ++ * request and resubmit it again soon. ++ */ ++#ifdef HIFN_DEBUG ++ if (hifn_debug) ++ device_printf(sc->sc_dev, "requeue request\n"); ++#endif ++ kfree(cmd); ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ return (err); ++ } ++ ++errout: ++ if (cmd != NULL) ++ kfree(cmd); ++ if (err == EINVAL) ++ hifnstats.hst_invalid++; ++ else ++ hifnstats.hst_nomem++; ++ crp->crp_etype = err; ++ crypto_done(crp); ++ return (err); ++} ++ ++static void ++hifn_abort(struct hifn_softc *sc) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct hifn_command *cmd; ++ struct cryptop *crp; ++ int i, u; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ i = dma->resk; u = dma->resu; ++ while (u != 0) { ++ cmd = dma->hifn_commands[i]; ++ KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); ++ dma->hifn_commands[i] = NULL; ++ crp = cmd->crp; ++ ++ if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { ++ /* Salvage what we can. */ ++ u_int8_t *macbuf; ++ ++ if (cmd->base_masks & HIFN_BASE_CMD_MAC) { ++ macbuf = dma->result_bufs[i]; ++ macbuf += 12; ++ } else ++ macbuf = NULL; ++ hifnstats.hst_opackets++; ++ hifn_callback(sc, cmd, macbuf); ++ } else { ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_POSTREAD); ++ } ++#endif ++ ++ if (cmd->src_skb != cmd->dst_skb) { ++#ifdef NOTYET ++ m_freem(cmd->src_m); ++ crp->crp_buf = (caddr_t)cmd->dst_m; ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ ++ /* non-shared buffers cannot be restarted */ ++ if (cmd->src_map != cmd->dst_map) { ++ /* ++ * XXX should be EAGAIN, delayed until ++ * after the reset. ++ */ ++ crp->crp_etype = ENOMEM; ++ pci_unmap_buf(sc, &cmd->dst); ++ } else ++ crp->crp_etype = ENOMEM; ++ ++ pci_unmap_buf(sc, &cmd->src); ++ ++ kfree(cmd); ++ if (crp->crp_etype != EAGAIN) ++ crypto_done(crp); ++ } ++ ++ if (++i == HIFN_D_RES_RSIZE) ++ i = 0; ++ u--; ++ } ++ dma->resk = i; dma->resu = u; ++ ++ hifn_reset_board(sc, 1); ++ hifn_init_dma(sc); ++ hifn_init_pci_registers(sc); ++} ++ ++static void ++hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) ++{ ++ struct hifn_dma *dma = sc->sc_dma; ++ struct cryptop *crp = cmd->crp; ++ struct cryptodesc *crd; ++ int i, u, ivlen; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++#if 0 ++ if (cmd->src_map == cmd->dst_map) { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); ++ } else { ++ bus_dmamap_sync(sc->sc_dmat, cmd->src_map, ++ BUS_DMASYNC_POSTWRITE); ++ bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, ++ BUS_DMASYNC_POSTREAD); ++ } ++#endif ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (cmd->src_skb != cmd->dst_skb) { ++#ifdef NOTYET ++ crp->crp_buf = (caddr_t)cmd->dst_m; ++ totlen = cmd->src_mapsize; ++ for (m = cmd->dst_m; m != NULL; m = m->m_next) { ++ if (totlen < m->m_len) { ++ m->m_len = totlen; ++ totlen = 0; ++ } else ++ totlen -= m->m_len; ++ } ++ cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len; ++ m_freem(cmd->src_m); ++#else ++ device_printf(sc->sc_dev, ++ "%s,%d: CRYPTO_F_SKBUF src != dst not implemented\n", ++ __FILE__, __LINE__); ++#endif ++ } ++ } ++ ++ if (cmd->sloplen != 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ cmd->src_mapsize - cmd->sloplen, cmd->sloplen, ++ (caddr_t)&dma->slop[cmd->slopidx]); ++ } ++ ++ i = dma->dstk; u = dma->dstu; ++ while (u != 0) { ++ if (i == HIFN_D_DST_RSIZE) ++ i = 0; ++#if 0 ++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, ++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ++#endif ++ if (dma->dstr[i].l & htole32(HIFN_D_VALID)) { ++#if 0 ++ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, ++ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ++#endif ++ break; ++ } ++ i++, u--; ++ } ++ dma->dstk = i; dma->dstu = u; ++ ++ hifnstats.hst_obytes += cmd->dst_mapsize; ++ ++ if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) == ++ HIFN_BASE_CMD_CRYPT) { ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ if (crd->crd_alg != CRYPTO_DES_CBC && ++ crd->crd_alg != CRYPTO_3DES_CBC && ++ crd->crd_alg != CRYPTO_AES_CBC) ++ continue; ++ ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ? ++ HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_skip + crd->crd_len - ivlen, ivlen, ++ cmd->softc->sc_sessions[cmd->session_num].hs_iv); ++ break; ++ } ++ } ++ ++ if (macbuf != NULL) { ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ int len; ++ ++ if (crd->crd_alg != CRYPTO_MD5 && ++ crd->crd_alg != CRYPTO_SHA1 && ++ crd->crd_alg != CRYPTO_MD5_HMAC && ++ crd->crd_alg != CRYPTO_SHA1_HMAC) { ++ continue; ++ } ++ len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen; ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, len, macbuf); ++ break; ++ } ++ } ++ ++ if (cmd->src_map != cmd->dst_map) ++ pci_unmap_buf(sc, &cmd->dst); ++ pci_unmap_buf(sc, &cmd->src); ++ kfree(cmd); ++ crypto_done(crp); ++} ++ ++/* ++ * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0 ++ * and Group 1 registers; avoid conditions that could create ++ * burst writes by doing a read in between the writes. ++ * ++ * NB: The read we interpose is always to the same register; ++ * we do this because reading from an arbitrary (e.g. last) ++ * register may not always work. ++ */ ++static void ++hifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) ++{ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (sc->sc_bar0_lastreg == reg - 4) ++ readl(sc->sc_bar0 + HIFN_0_PUCNFG); ++ sc->sc_bar0_lastreg = reg; ++ } ++ writel(val, sc->sc_bar0 + reg); ++} ++ ++static void ++hifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) ++{ ++ if (sc->sc_flags & HIFN_IS_7811) { ++ if (sc->sc_bar1_lastreg == reg - 4) ++ readl(sc->sc_bar1 + HIFN_1_REVID); ++ sc->sc_bar1_lastreg = reg; ++ } ++ writel(val, sc->sc_bar1 + reg); ++} ++ ++ ++static struct pci_device_id hifn_pci_tbl[] = { ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ /* ++ * Other vendors share this PCI ID as well, such as ++ * http://www.powercrypt.com, and obviously they also ++ * use the same key. ++ */ ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { 0, 0, 0, 0, 0, 0, } ++}; ++MODULE_DEVICE_TABLE(pci, hifn_pci_tbl); ++ ++static struct pci_driver hifn_driver = { ++ .name = "hifn", ++ .id_table = hifn_pci_tbl, ++ .probe = hifn_probe, ++ .remove = hifn_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init hifn_init (void) ++{ ++ struct hifn_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF("%s(%p)\n", __FUNCTION__, hifn_init); ++ ++ rc = pci_register_driver(&hifn_driver); ++ pci_register_driver_compat(&hifn_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit hifn_exit (void) ++{ ++ pci_unregister_driver(&hifn_driver); ++} ++ ++module_init(hifn_init); ++module_exit(hifn_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF driver for hifn PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751reg.h linux-2.6.30/crypto/ocf/hifn/hifn7751reg.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751reg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751reg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,540 @@ ++/* $FreeBSD: src/sys/dev/hifn/hifn7751reg.h,v 1.7 2007/03/21 03:42:49 sam Exp $ */ ++/* $OpenBSD: hifn7751reg.h,v 1.35 2002/04/08 17:49:42 jason Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * ++ * Please send any comments, feedback, bug-fixes, or feature requests to ++ * software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++#ifndef __HIFN_H__ ++#define __HIFN_H__ ++ ++/* ++ * Some PCI configuration space offset defines. The names were made ++ * identical to the names used by the Linux kernel. ++ */ ++#define HIFN_BAR0 PCIR_BAR(0) /* PUC register map */ ++#define HIFN_BAR1 PCIR_BAR(1) /* DMA register map */ ++#define HIFN_TRDY_TIMEOUT 0x40 ++#define HIFN_RETRY_TIMEOUT 0x41 ++ ++/* ++ * PCI vendor and device identifiers ++ * (the names are preserved from their OpenBSD source). ++ */ ++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ ++#define PCI_PRODUCT_HIFN_7751 0x0005 /* 7751 */ ++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ ++#define PCI_PRODUCT_HIFN_7811 0x0007 /* 7811 */ ++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ ++#define PCI_PRODUCT_HIFN_7951 0x0012 /* 7951 */ ++#define PCI_PRODUCT_HIFN_7955 0x0020 /* 7954/7955 */ ++#define PCI_PRODUCT_HIFN_7956 0x001d /* 7956 */ ++ ++#define PCI_VENDOR_INVERTEX 0x14e1 /* Invertex */ ++#define PCI_PRODUCT_INVERTEX_AEON 0x0005 /* AEON */ ++ ++#define PCI_VENDOR_NETSEC 0x1660 /* NetSec */ ++#define PCI_PRODUCT_NETSEC_7751 0x7751 /* 7751 */ ++ ++/* ++ * The values below should multiple of 4 -- and be large enough to handle ++ * any command the driver implements. ++ * ++ * MAX_COMMAND = base command + mac command + encrypt command + ++ * mac-key + rc4-key ++ * MAX_RESULT = base result + mac result + mac + encrypt result ++ * ++ * ++ */ ++#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) ++#define HIFN_MAX_RESULT (8 + 4 + 20 + 4) ++ ++/* ++ * hifn_desc_t ++ * ++ * Holds an individual descriptor for any of the rings. ++ */ ++typedef struct hifn_desc { ++ volatile u_int32_t l; /* length and status bits */ ++ volatile u_int32_t p; ++} hifn_desc_t; ++ ++/* ++ * Masks for the "length" field of struct hifn_desc. ++ */ ++#define HIFN_D_LENGTH 0x0000ffff /* length bit mask */ ++#define HIFN_D_MASKDONEIRQ 0x02000000 /* mask the done interrupt */ ++#define HIFN_D_DESTOVER 0x04000000 /* destination overflow */ ++#define HIFN_D_OVER 0x08000000 /* overflow */ ++#define HIFN_D_LAST 0x20000000 /* last descriptor in chain */ ++#define HIFN_D_JUMP 0x40000000 /* jump descriptor */ ++#define HIFN_D_VALID 0x80000000 /* valid bit */ ++ ++ ++/* ++ * Processing Unit Registers (offset from BASEREG0) ++ */ ++#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ ++#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ ++#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ ++#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ ++#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ ++#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ ++#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ ++#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ ++#define HIFN_0_PUCTRL2 0x28 /* Processing Unit Control (2nd map) */ ++#define HIFN_0_MUTE1 0x80 ++#define HIFN_0_MUTE2 0x90 ++#define HIFN_0_SPACESIZE 0x100 /* Register space size */ ++ ++/* Processing Unit Control Register (HIFN_0_PUCTRL) */ ++#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ ++#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ ++#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ ++#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ ++#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ ++ ++/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ ++#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ ++ ++/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ ++#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ ++#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ ++#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ ++#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ ++#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ ++#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ ++#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ ++#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ ++#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ ++#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ ++#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ ++#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ ++#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ ++#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ ++#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ ++#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ ++#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ ++#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ ++#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ ++#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ ++#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ ++#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ ++#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ ++ ++/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ ++#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ ++ ++/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ ++#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ ++#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ ++#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ ++#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ ++#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ ++#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ ++#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ ++#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ ++#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ ++#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ ++#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ ++#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ ++#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ ++#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ ++#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ ++#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ ++#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ ++ ++/* FIFO Status Register (HIFN_0_FIFOSTAT) */ ++#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ ++#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ ++ ++/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ ++#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as this value */ ++ ++/* ++ * DMA Interface Registers (offset from BASEREG1) ++ */ ++#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ ++#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ ++#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ ++#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ ++#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ ++#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ ++#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ ++#define HIFN_1_PLL 0x4c /* 7955/7956: PLL config */ ++#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ ++#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ ++#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ ++#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ ++#define HIFN_1_DMA_CNFG2 0x6c /* 7955/7956: dma config #2 */ ++#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ ++#define HIFN_1_REVID 0x98 /* Revision ID */ ++ ++#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ ++#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ ++#define HIFN_1_PUB_OPLEN 0x304 /* 7951-compat Public Operand Length */ ++#define HIFN_1_PUB_OP 0x308 /* 7951-compat Public Operand */ ++#define HIFN_1_PUB_STATUS 0x30c /* 7951-compat Public Status */ ++#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ ++#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ ++#define HIFN_1_RNG_DATA 0x318 /* RNG data */ ++#define HIFN_1_PUB_MODE 0x320 /* PK mode */ ++#define HIFN_1_PUB_FIFO_OPLEN 0x380 /* first element of oplen fifo */ ++#define HIFN_1_PUB_FIFO_OP 0x384 /* first element of op fifo */ ++#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ ++#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ ++ ++/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ ++#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ ++#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ ++#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ ++#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ ++#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ ++#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ ++#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ ++#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ ++#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ ++#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ ++#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ ++#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ ++#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ ++#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ ++#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ ++#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ ++#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ ++#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ ++#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ ++#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ ++#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ ++#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ ++#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ ++#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ ++#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ ++#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ ++#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ ++#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ ++#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ ++#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ ++#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ ++#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ ++#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ ++#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ ++#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ ++#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ ++#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ ++#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ ++ ++/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ ++#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ ++#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ ++#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ ++#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ ++#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ ++#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ ++#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ ++#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ ++#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ ++#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ ++#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ ++#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ ++#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ ++#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ ++#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ ++#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ ++#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ ++#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ ++#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ ++#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ ++#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ ++#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ ++ ++/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ ++#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ ++#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ ++#define HIFN_DMACNFG_UNLOCK 0x00000800 ++#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ ++#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ ++#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ ++#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ ++#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ ++ ++/* DMA Configuration Register (HIFN_1_DMA_CNFG2) */ ++#define HIFN_DMACNFG2_PKSWAP32 (1 << 19) /* swap the OPLEN/OP reg */ ++#define HIFN_DMACNFG2_PKSWAP8 (1 << 18) /* swap the bits of OPLEN/OP */ ++#define HIFN_DMACNFG2_BAR0_SWAP32 (1<<17) /* swap the bytes of BAR0 */ ++#define HIFN_DMACNFG2_BAR1_SWAP8 (1<<16) /* swap the bits of BAR0 */ ++#define HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT 12 ++#define HIFN_DMACNFG2_INIT_READ_BURST_SHIFT 8 ++#define HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT 4 ++#define HIFN_DMACNFG2_TGT_READ_BURST_SHIFT 0 ++ ++/* 7811 RNG Enable Register (HIFN_1_7811_RNGENA) */ ++#define HIFN_7811_RNGENA_ENA 0x00000001 /* enable RNG */ ++ ++/* 7811 RNG Config Register (HIFN_1_7811_RNGCFG) */ ++#define HIFN_7811_RNGCFG_PRE1 0x00000f00 /* first prescalar */ ++#define HIFN_7811_RNGCFG_OPRE 0x00000080 /* output prescalar */ ++#define HIFN_7811_RNGCFG_DEFL 0x00000f80 /* 2 words/ 1/100 sec */ ++ ++/* 7811 RNG Status Register (HIFN_1_7811_RNGSTS) */ ++#define HIFN_7811_RNGSTS_RDY 0x00004000 /* two numbers in FIFO */ ++#define HIFN_7811_RNGSTS_UFL 0x00001000 /* rng underflow */ ++ ++/* 7811 MIPS Reset Register (HIFN_1_7811_MIPSRST) */ ++#define HIFN_MIPSRST_BAR2SIZE 0xffff0000 /* sdram size */ ++#define HIFN_MIPSRST_GPRAMINIT 0x00008000 /* gpram can be accessed */ ++#define HIFN_MIPSRST_CRAMINIT 0x00004000 /* ctxram can be accessed */ ++#define HIFN_MIPSRST_LED2 0x00000400 /* external LED2 */ ++#define HIFN_MIPSRST_LED1 0x00000200 /* external LED1 */ ++#define HIFN_MIPSRST_LED0 0x00000100 /* external LED0 */ ++#define HIFN_MIPSRST_MIPSDIS 0x00000004 /* disable MIPS */ ++#define HIFN_MIPSRST_MIPSRST 0x00000002 /* warm reset MIPS */ ++#define HIFN_MIPSRST_MIPSCOLD 0x00000001 /* cold reset MIPS */ ++ ++/* Public key reset register (HIFN_1_PUB_RESET) */ ++#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ ++ ++/* Public operation register (HIFN_1_PUB_OP) */ ++#define HIFN_PUBOP_AOFFSET 0x0000003e /* A offset */ ++#define HIFN_PUBOP_BOFFSET 0x00000fc0 /* B offset */ ++#define HIFN_PUBOP_MOFFSET 0x0003f000 /* M offset */ ++#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ ++#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ ++#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ ++#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ ++#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ ++#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ ++#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ ++#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ ++#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ ++#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ ++#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ ++#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ ++#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular Red */ ++#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular Exp */ ++ ++/* Public operand length register (HIFN_1_PUB_OPLEN) */ ++#define HIFN_PUBOPLEN_MODLEN 0x0000007f ++#define HIFN_PUBOPLEN_EXPLEN 0x0003ff80 ++#define HIFN_PUBOPLEN_REDLEN 0x003c0000 ++ ++/* Public status register (HIFN_1_PUB_STATUS) */ ++#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ ++#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ ++#define HIFN_PUBSTS_FIFO_EMPTY 0x00000100 /* fifo empty */ ++#define HIFN_PUBSTS_FIFO_FULL 0x00000200 /* fifo full */ ++#define HIFN_PUBSTS_FIFO_OVFL 0x00000400 /* fifo overflow */ ++#define HIFN_PUBSTS_FIFO_WRITE 0x000f0000 /* fifo write */ ++#define HIFN_PUBSTS_FIFO_READ 0x0f000000 /* fifo read */ ++ ++/* Public interrupt enable register (HIFN_1_PUB_IEN) */ ++#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ ++ ++/* Random number generator config register (HIFN_1_RNG_CONFIG) */ ++#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ ++ ++/* ++ * Register offsets in register set 1 ++ */ ++ ++#define HIFN_UNLOCK_SECRET1 0xf4 ++#define HIFN_UNLOCK_SECRET2 0xfc ++ ++/* ++ * PLL config register ++ * ++ * This register is present only on 7954/7955/7956 parts. It must be ++ * programmed according to the bus interface method used by the h/w. ++ * Note that the parts require a stable clock. Since the PCI clock ++ * may vary the reference clock must usually be used. To avoid ++ * overclocking the core logic, setup must be done carefully, refer ++ * to the driver for details. The exact multiplier required varies ++ * by part and system configuration; refer to the Hifn documentation. ++ */ ++#define HIFN_PLL_REF_SEL 0x00000001 /* REF/HBI clk selection */ ++#define HIFN_PLL_BP 0x00000002 /* bypass (used during setup) */ ++/* bit 2 reserved */ ++#define HIFN_PLL_PK_CLK_SEL 0x00000008 /* public key clk select */ ++#define HIFN_PLL_PE_CLK_SEL 0x00000010 /* packet engine clk select */ ++/* bits 5-9 reserved */ ++#define HIFN_PLL_MBSET 0x00000400 /* must be set to 1 */ ++#define HIFN_PLL_ND 0x00003800 /* Fpll_ref multiplier select */ ++#define HIFN_PLL_ND_SHIFT 11 ++#define HIFN_PLL_ND_2 0x00000000 /* 2x */ ++#define HIFN_PLL_ND_4 0x00000800 /* 4x */ ++#define HIFN_PLL_ND_6 0x00001000 /* 6x */ ++#define HIFN_PLL_ND_8 0x00001800 /* 8x */ ++#define HIFN_PLL_ND_10 0x00002000 /* 10x */ ++#define HIFN_PLL_ND_12 0x00002800 /* 12x */ ++/* bits 14-15 reserved */ ++#define HIFN_PLL_IS 0x00010000 /* charge pump current select */ ++/* bits 17-31 reserved */ ++ ++/* ++ * Board configuration specifies only these bits. ++ */ ++#define HIFN_PLL_CONFIG (HIFN_PLL_IS|HIFN_PLL_ND|HIFN_PLL_REF_SEL) ++ ++/* ++ * Public Key Engine Mode Register ++ */ ++#define HIFN_PKMODE_HOSTINVERT (1 << 0) /* HOST INVERT */ ++#define HIFN_PKMODE_ENHANCED (1 << 1) /* Enable enhanced mode */ ++ ++ ++/********************************************************************* ++ * Structs for board commands ++ * ++ *********************************************************************/ ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_base_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t session_num; ++ volatile u_int16_t total_source_count; ++ volatile u_int16_t total_dest_count; ++} hifn_base_command_t; ++ ++#define HIFN_BASE_CMD_MAC 0x0400 ++#define HIFN_BASE_CMD_CRYPT 0x0800 ++#define HIFN_BASE_CMD_DECODE 0x2000 ++#define HIFN_BASE_CMD_SRCLEN_M 0xc000 ++#define HIFN_BASE_CMD_SRCLEN_S 14 ++#define HIFN_BASE_CMD_DSTLEN_M 0x3000 ++#define HIFN_BASE_CMD_DSTLEN_S 12 ++#define HIFN_BASE_CMD_LENMASK_HI 0x30000 ++#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_crypt_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t header_skip; ++ volatile u_int16_t source_count; ++ volatile u_int16_t reserved; ++} hifn_crypt_command_t; ++ ++#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ ++#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ ++#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ ++#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ ++#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ ++#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ ++#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ ++#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ ++#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ ++#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ ++#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ ++#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ ++#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ ++ ++#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 ++#define HIFN_CRYPT_CMD_SRCLEN_S 14 ++ ++#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ ++#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ ++#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ ++#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ ++ ++/* ++ * Structure to help build up the command data structure. ++ */ ++typedef struct hifn_mac_command { ++ volatile u_int16_t masks; ++ volatile u_int16_t header_skip; ++ volatile u_int16_t source_count; ++ volatile u_int16_t reserved; ++} hifn_mac_command_t; ++ ++#define HIFN_MAC_CMD_ALG_MASK 0x0001 ++#define HIFN_MAC_CMD_ALG_SHA1 0x0000 ++#define HIFN_MAC_CMD_ALG_MD5 0x0001 ++#define HIFN_MAC_CMD_MODE_MASK 0x000c ++#define HIFN_MAC_CMD_MODE_HMAC 0x0000 ++#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 ++#define HIFN_MAC_CMD_MODE_HASH 0x0008 ++#define HIFN_MAC_CMD_MODE_FULL 0x0004 ++#define HIFN_MAC_CMD_TRUNC 0x0010 ++#define HIFN_MAC_CMD_RESULT 0x0020 ++#define HIFN_MAC_CMD_APPEND 0x0040 ++#define HIFN_MAC_CMD_SRCLEN_M 0xc000 ++#define HIFN_MAC_CMD_SRCLEN_S 14 ++ ++/* ++ * MAC POS IPsec initiates authentication after encryption on encodes ++ * and before decryption on decodes. ++ */ ++#define HIFN_MAC_CMD_POS_IPSEC 0x0200 ++#define HIFN_MAC_CMD_NEW_KEY 0x0800 ++ ++/* ++ * The poll frequency and poll scalar defines are unshifted values used ++ * to set fields in the DMA Configuration Register. ++ */ ++#ifndef HIFN_POLL_FREQUENCY ++#define HIFN_POLL_FREQUENCY 0x1 ++#endif ++ ++#ifndef HIFN_POLL_SCALAR ++#define HIFN_POLL_SCALAR 0x0 ++#endif ++ ++#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ ++#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ ++#endif /* __HIFN_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifn7751var.h linux-2.6.30/crypto/ocf/hifn/hifn7751var.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifn7751var.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifn7751var.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,369 @@ ++/* $FreeBSD: src/sys/dev/hifn/hifn7751var.h,v 1.9 2007/03/21 03:42:49 sam Exp $ */ ++/* $OpenBSD: hifn7751var.h,v 1.42 2002/04/08 17:49:42 jason Exp $ */ ++ ++/*- ++ * Invertex AEON / Hifn 7751 driver ++ * Copyright (c) 1999 Invertex Inc. All rights reserved. ++ * Copyright (c) 1999 Theo de Raadt ++ * Copyright (c) 2000-2001 Network Security Technologies, Inc. ++ * http://www.netsec.net ++ * ++ * Please send any comments, feedback, bug-fixes, or feature requests to ++ * software@invertex.com. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored in part by the Defense Advanced Research Projects ++ * Agency (DARPA) and Air Force Research Laboratory, Air Force ++ * Materiel Command, USAF, under agreement number F30602-01-2-0537. ++ * ++ */ ++ ++#ifndef __HIFN7751VAR_H__ ++#define __HIFN7751VAR_H__ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Some configurable values for the driver. By default command+result ++ * descriptor rings are the same size. The src+dst descriptor rings ++ * are sized at 3.5x the number of potential commands. Slower parts ++ * (e.g. 7951) tend to run out of src descriptors; faster parts (7811) ++ * src+cmd/result descriptors. It's not clear that increasing the size ++ * of the descriptor rings helps performance significantly as other ++ * factors tend to come into play (e.g. copying misaligned packets). ++ */ ++#define HIFN_D_CMD_RSIZE 24 /* command descriptors */ ++#define HIFN_D_SRC_RSIZE ((HIFN_D_CMD_RSIZE * 7) / 2) /* source descriptors */ ++#define HIFN_D_RES_RSIZE HIFN_D_CMD_RSIZE /* result descriptors */ ++#define HIFN_D_DST_RSIZE HIFN_D_SRC_RSIZE /* destination descriptors */ ++ ++/* ++ * Length values for cryptography ++ */ ++#define HIFN_DES_KEY_LENGTH 8 ++#define HIFN_3DES_KEY_LENGTH 24 ++#define HIFN_MAX_CRYPT_KEY_LENGTH HIFN_3DES_KEY_LENGTH ++#define HIFN_IV_LENGTH 8 ++#define HIFN_AES_IV_LENGTH 16 ++#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH ++ ++/* ++ * Length values for authentication ++ */ ++#define HIFN_MAC_KEY_LENGTH 64 ++#define HIFN_MD5_LENGTH 16 ++#define HIFN_SHA1_LENGTH 20 ++#define HIFN_MAC_TRUNC_LENGTH 12 ++ ++#define MAX_SCATTER 64 ++ ++/* ++ * Data structure to hold all 4 rings and any other ring related data. ++ */ ++struct hifn_dma { ++ /* ++ * Descriptor rings. We add +1 to the size to accomidate the ++ * jump descriptor. ++ */ ++ struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1]; ++ struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1]; ++ struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; ++ struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; ++ ++ struct hifn_command *hifn_commands[HIFN_D_RES_RSIZE]; ++ ++ u_char command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; ++ u_char result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; ++ u_int32_t slop[HIFN_D_CMD_RSIZE]; ++ ++ u_int64_t test_src, test_dst; ++ ++ /* ++ * Our current positions for insertion and removal from the desriptor ++ * rings. ++ */ ++ int cmdi, srci, dsti, resi; ++ volatile int cmdu, srcu, dstu, resu; ++ int cmdk, srck, dstk, resk; ++}; ++ ++struct hifn_session { ++ int hs_used; ++ int hs_mlen; ++ u_int8_t hs_iv[HIFN_MAX_IV_LENGTH]; ++}; ++ ++#define HIFN_RING_SYNC(sc, r, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++#define HIFN_CMDR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), cmdr, (i), (f)) ++#define HIFN_RESR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), resr, (i), (f)) ++#define HIFN_SRCR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), srcr, (i), (f)) ++#define HIFN_DSTR_SYNC(sc, i, f) HIFN_RING_SYNC((sc), dstr, (i), (f)) ++ ++#define HIFN_CMD_SYNC(sc, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++#define HIFN_RES_SYNC(sc, i, f) \ ++ /* DAVIDM bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, (f)) */ ++ ++typedef int bus_size_t; ++ ++/* ++ * Holds data specific to a single HIFN board. ++ */ ++struct hifn_softc { ++ softc_device_decl sc_dev; ++ ++ struct pci_dev *sc_pcidev; /* PCI device pointer */ ++ spinlock_t sc_mtx; /* per-instance lock */ ++ ++ int sc_num; /* for multiple devs */ ++ ++ ocf_iomem_t sc_bar0; ++ bus_size_t sc_bar0_lastreg;/* bar0 last reg written */ ++ ocf_iomem_t sc_bar1; ++ bus_size_t sc_bar1_lastreg;/* bar1 last reg written */ ++ ++ int sc_irq; ++ ++ u_int32_t sc_dmaier; ++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */ ++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ ++ ++ struct hifn_dma *sc_dma; ++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ ++ ++ int sc_dmansegs; ++ int32_t sc_cid; ++ int sc_maxses; ++ int sc_nsessions; ++ struct hifn_session *sc_sessions; ++ int sc_ramsize; ++ int sc_flags; ++#define HIFN_HAS_RNG 0x1 /* includes random number generator */ ++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ ++#define HIFN_HAS_AES 0x4 /* includes AES support */ ++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ ++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ ++ ++ struct timer_list sc_tickto; /* for managing DMA */ ++ ++ int sc_rngfirst; ++ int sc_rnghz; /* RNG polling frequency */ ++ ++ int sc_c_busy; /* command ring busy */ ++ int sc_s_busy; /* source data ring busy */ ++ int sc_d_busy; /* destination data ring busy */ ++ int sc_r_busy; /* result ring busy */ ++ int sc_active; /* for initial countdown */ ++ int sc_needwakeup; /* ops q'd wating on resources */ ++ int sc_curbatch; /* # ops submitted w/o int */ ++ int sc_suspended; ++#ifdef HIFN_VULCANDEV ++ struct cdev *sc_pkdev; ++#endif ++}; ++ ++#define HIFN_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) ++#define HIFN_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) ++ ++/* ++ * hifn_command_t ++ * ++ * This is the control structure used to pass commands to hifn_encrypt(). ++ * ++ * flags ++ * ----- ++ * Flags is the bitwise "or" values for command configuration. A single ++ * encrypt direction needs to be set: ++ * ++ * HIFN_ENCODE or HIFN_DECODE ++ * ++ * To use cryptography, a single crypto algorithm must be included: ++ * ++ * HIFN_CRYPT_3DES or HIFN_CRYPT_DES ++ * ++ * To use authentication is used, a single MAC algorithm must be included: ++ * ++ * HIFN_MAC_MD5 or HIFN_MAC_SHA1 ++ * ++ * By default MD5 uses a 16 byte hash and SHA-1 uses a 20 byte hash. ++ * If the value below is set, hash values are truncated or assumed ++ * truncated to 12 bytes: ++ * ++ * HIFN_MAC_TRUNC ++ * ++ * Keys for encryption and authentication can be sent as part of a command, ++ * or the last key value used with a particular session can be retrieved ++ * and used again if either of these flags are not specified. ++ * ++ * HIFN_CRYPT_NEW_KEY, HIFN_MAC_NEW_KEY ++ * ++ * session_num ++ * ----------- ++ * A number between 0 and 2048 (for DRAM models) or a number between ++ * 0 and 768 (for SRAM models). Those who don't want to use session ++ * numbers should leave value at zero and send a new crypt key and/or ++ * new MAC key on every command. If you use session numbers and ++ * don't send a key with a command, the last key sent for that same ++ * session number will be used. ++ * ++ * Warning: Using session numbers and multiboard at the same time ++ * is currently broken. ++ * ++ * mbuf ++ * ---- ++ * Either fill in the mbuf pointer and npa=0 or ++ * fill packp[] and packl[] and set npa to > 0 ++ * ++ * mac_header_skip ++ * --------------- ++ * The number of bytes of the source_buf that are skipped over before ++ * authentication begins. This must be a number between 0 and 2^16-1 ++ * and can be used by IPsec implementers to skip over IP headers. ++ * *** Value ignored if authentication not used *** ++ * ++ * crypt_header_skip ++ * ----------------- ++ * The number of bytes of the source_buf that are skipped over before ++ * the cryptographic operation begins. This must be a number between 0 ++ * and 2^16-1. For IPsec, this number will always be 8 bytes larger ++ * than the auth_header_skip (to skip over the ESP header). ++ * *** Value ignored if cryptography not used *** ++ * ++ */ ++struct hifn_operand { ++ union { ++ struct sk_buff *skb; ++ struct uio *io; ++ unsigned char *buf; ++ } u; ++ void *map; ++ bus_size_t mapsize; ++ int nsegs; ++ struct { ++ dma_addr_t ds_addr; ++ int ds_len; ++ } segs[MAX_SCATTER]; ++}; ++ ++struct hifn_command { ++ u_int16_t session_num; ++ u_int16_t base_masks, cry_masks, mac_masks; ++ u_int8_t iv[HIFN_MAX_IV_LENGTH], *ck, mac[HIFN_MAC_KEY_LENGTH]; ++ int cklen; ++ int sloplen, slopidx; ++ ++ struct hifn_operand src; ++ struct hifn_operand dst; ++ ++ struct hifn_softc *softc; ++ struct cryptop *crp; ++ struct cryptodesc *enccrd, *maccrd; ++}; ++ ++#define src_skb src.u.skb ++#define src_io src.u.io ++#define src_map src.map ++#define src_mapsize src.mapsize ++#define src_segs src.segs ++#define src_nsegs src.nsegs ++#define src_buf src.u.buf ++ ++#define dst_skb dst.u.skb ++#define dst_io dst.u.io ++#define dst_map dst.map ++#define dst_mapsize dst.mapsize ++#define dst_segs dst.segs ++#define dst_nsegs dst.nsegs ++#define dst_buf dst.u.buf ++ ++/* ++ * Return values for hifn_crypto() ++ */ ++#define HIFN_CRYPTO_SUCCESS 0 ++#define HIFN_CRYPTO_BAD_INPUT (-1) ++#define HIFN_CRYPTO_RINGS_FULL (-2) ++ ++/************************************************************************** ++ * ++ * Function: hifn_crypto ++ * ++ * Purpose: Called by external drivers to begin an encryption on the ++ * HIFN board. ++ * ++ * Blocking/Non-blocking Issues ++ * ============================ ++ * The driver cannot block in hifn_crypto (no calls to tsleep) currently. ++ * hifn_crypto() returns HIFN_CRYPTO_RINGS_FULL if there is not enough ++ * room in any of the rings for the request to proceed. ++ * ++ * Return Values ++ * ============= ++ * 0 for success, negative values on error ++ * ++ * Defines for negative error codes are: ++ * ++ * HIFN_CRYPTO_BAD_INPUT : The passed in command had invalid settings. ++ * HIFN_CRYPTO_RINGS_FULL : All DMA rings were full and non-blocking ++ * behaviour was requested. ++ * ++ *************************************************************************/ ++ ++/* ++ * Convert back and forth from 'sid' to 'card' and 'session' ++ */ ++#define HIFN_CARD(sid) (((sid) & 0xf0000000) >> 28) ++#define HIFN_SESSION(sid) ((sid) & 0x000007ff) ++#define HIFN_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff)) ++ ++#endif /* _KERNEL */ ++ ++struct hifn_stats { ++ u_int64_t hst_ibytes; ++ u_int64_t hst_obytes; ++ u_int32_t hst_ipackets; ++ u_int32_t hst_opackets; ++ u_int32_t hst_invalid; ++ u_int32_t hst_nomem; /* malloc or one of hst_nomem_* */ ++ u_int32_t hst_abort; ++ u_int32_t hst_noirq; /* IRQ for no reason */ ++ u_int32_t hst_totbatch; /* ops submitted w/o interrupt */ ++ u_int32_t hst_maxbatch; /* max ops submitted together */ ++ u_int32_t hst_unaligned; /* unaligned src caused copy */ ++ /* ++ * The following divides hst_nomem into more specific buckets. ++ */ ++ u_int32_t hst_nomem_map; /* bus_dmamap_create failed */ ++ u_int32_t hst_nomem_load; /* bus_dmamap_load_* failed */ ++ u_int32_t hst_nomem_mbuf; /* MGET* failed */ ++ u_int32_t hst_nomem_mcl; /* MCLGET* failed */ ++ u_int32_t hst_nomem_cr; /* out of command/result descriptor */ ++ u_int32_t hst_nomem_sd; /* out of src/dst descriptors */ ++}; ++ ++#endif /* __HIFN7751VAR_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPP.c linux-2.6.30/crypto/ocf/hifn/hifnHIPP.c +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPP.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPP.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,420 @@ ++/*- ++ * Driver for Hifn HIPP-I/II chipset ++ * Copyright (c) 2006 Michael Richardson ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn Inc. ++ * ++ */ ++ ++/* ++ * Driver for various Hifn encryption processors. ++ */ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "hifnHIPPreg.h" ++#include "hifnHIPPvar.h" ++ ++#if 1 ++#define DPRINTF(a...) if (hipp_debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "hifn"); \ ++ printk(a); \ ++ } else ++#else ++#define DPRINTF(a...) ++#endif ++ ++typedef int bus_size_t; ++ ++static inline int ++pci_get_revid(struct pci_dev *dev) ++{ ++ u8 rid = 0; ++ pci_read_config_byte(dev, PCI_REVISION_ID, &rid); ++ return rid; ++} ++ ++#define debug hipp_debug ++int hipp_debug = 0; ++module_param(hipp_debug, int, 0644); ++MODULE_PARM_DESC(hipp_debug, "Enable debug"); ++ ++int hipp_maxbatch = 1; ++module_param(hipp_maxbatch, int, 0644); ++MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt"); ++ ++static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent); ++static void hipp_remove(struct pci_dev *dev); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hipp_intr(int irq, void *arg); ++#else ++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs); ++#endif ++ ++static int hipp_num_chips = 0; ++static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS]; ++ ++static int hipp_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int hipp_freesession(device_t, u_int64_t); ++static int hipp_process(device_t, struct cryptop *, int); ++ ++static device_method_t hipp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, hipp_newsession), ++ DEVMETHOD(cryptodev_freesession,hipp_freesession), ++ DEVMETHOD(cryptodev_process, hipp_process), ++}; ++ ++static __inline u_int32_t ++READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg) ++{ ++ u_int32_t v = readl(sc->sc_bar[barno] + reg); ++ //sc->sc_bar0_lastreg = (bus_size_t) -1; ++ return (v); ++} ++static __inline void ++WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val) ++{ ++ writel(val, sc->sc_bar[barno] + reg); ++} ++ ++#define READ_REG_0(sc, reg) READ_REG(sc, 0, reg) ++#define WRITE_REG_0(sc, reg, val) WRITE_REG(sc,0, reg, val) ++#define READ_REG_1(sc, reg) READ_REG(sc, 1, reg) ++#define WRITE_REG_1(sc, reg, val) WRITE_REG(sc,1, reg, val) ++ ++static int ++hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ return EINVAL; ++} ++ ++static int ++hipp_freesession(device_t dev, u_int64_t tid) ++{ ++ return EINVAL; ++} ++ ++static int ++hipp_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ return EINVAL; ++} ++ ++static const char* ++hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen) ++{ ++ char *n = NULL; ++ ++ switch (pci_get_vendor(sc->sc_pcidev)) { ++ case PCI_VENDOR_HIFN: ++ switch (pci_get_device(sc->sc_pcidev)) { ++ case PCI_PRODUCT_HIFN_7855: n = "Hifn 7855"; ++ case PCI_PRODUCT_HIFN_8155: n = "Hifn 8155"; ++ case PCI_PRODUCT_HIFN_6500: n = "Hifn 6500"; ++ } ++ } ++ ++ if(n==NULL) { ++ snprintf(buf, blen, "VID=%02x,PID=%02x", ++ pci_get_vendor(sc->sc_pcidev), ++ pci_get_device(sc->sc_pcidev)); ++ } else { ++ buf[0]='\0'; ++ strncat(buf, n, blen); ++ } ++ return buf; ++} ++ ++struct hipp_fs_entry { ++ struct attribute attr; ++ /* other stuff */ ++}; ++ ++ ++static ssize_t ++cryptoid_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct hipp_softc *sc; ++ ++ sc = pci_get_drvdata(to_pci_dev (dev)); ++ return sprintf (buf, "%d\n", sc->sc_cid); ++} ++ ++struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid); ++ ++/* ++ * Attach an interface that successfully probed. ++ */ ++static int ++hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct hipp_softc *sc = NULL; ++ int i; ++ //char rbase; ++ //u_int16_t ena; ++ int rev; ++ //int rseg; ++ int rc; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (pci_set_mwi(dev)) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("hifn: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods); ++ ++ sc->sc_pcidev = dev; ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_num = hipp_num_chips++; ++ ++ if (sc->sc_num < HIPP_MAX_CHIPS) ++ hipp_chip_idx[sc->sc_num] = sc; ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ spin_lock_init(&sc->sc_mtx); ++ ++ /* ++ * Setup PCI resources. ++ * The READ_REG_0, WRITE_REG_0, READ_REG_1, ++ * and WRITE_REG_1 macros throughout the driver are used ++ * to permit better debugging. ++ */ ++ for(i=0; i<4; i++) { ++ unsigned long mem_start, mem_len; ++ mem_start = pci_resource_start(sc->sc_pcidev, i); ++ mem_len = pci_resource_len(sc->sc_pcidev, i); ++ sc->sc_barphy[i] = (caddr_t)mem_start; ++ sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_bar[i]) { ++ device_printf(sc->sc_dev, "cannot map bar%d register space\n", i); ++ goto fail; ++ } ++ } ++ ++ //hipp_reset_board(sc, 0); ++ pci_set_master(sc->sc_pcidev); ++ ++ /* ++ * Arrange the interrupt line. ++ */ ++ rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); ++ goto fail; ++ } ++ sc->sc_irq = dev->irq; ++ ++ rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff; ++ ++ { ++ char b[32]; ++ device_printf(sc->sc_dev, "%s, rev %u", ++ hipp_partname(sc, b, sizeof(b)), rev); ++ } ++ ++#if 0 ++ if (sc->sc_flags & HIFN_IS_7956) ++ printf(", pll=0x%x<%s clk, %ux mult>", ++ sc->sc_pllconfig, ++ sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", ++ 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); ++#endif ++ printf("\n"); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto fail; ++ } ++ ++#if 0 /* cannot work with a non-GPL module */ ++ /* make a sysfs entry to let the world know what entry we got */ ++ sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr); ++#endif ++ ++#if 0 ++ init_timer(&sc->sc_tickto); ++ sc->sc_tickto.function = hifn_tick; ++ sc->sc_tickto.data = (unsigned long) sc->sc_num; ++ mod_timer(&sc->sc_tickto, jiffies + HZ); ++#endif ++ ++#if 0 /* no code here yet ?? */ ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++#endif ++ ++ return (0); ++ ++fail: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ ++#if 0 ++ if (sc->sc_dma) { ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++ ++ pci_free_consistent(sc->sc_pcidev, ++ sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++ } ++#endif ++ kfree(sc); ++ return (-ENXIO); ++} ++ ++/* ++ * Detach an interface that successfully probed. ++ */ ++static void ++hipp_remove(struct pci_dev *dev) ++{ ++ struct hipp_softc *sc = pci_get_drvdata(dev); ++ unsigned long l_flags; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* disable interrupts */ ++ HIPP_LOCK(sc); ++ ++#if 0 ++ WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); ++ HIFN_UNLOCK(sc); ++ ++ /*XXX other resources */ ++ del_timer_sync(&sc->sc_tickto); ++ ++ /* Turn off DMA polling */ ++ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | ++ HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); ++#endif ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ free_irq(sc->sc_irq, sc); ++ ++#if 0 ++ pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), ++ sc->sc_dma, sc->sc_dma_physaddr); ++#endif ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static irqreturn_t hipp_intr(int irq, void *arg) ++#else ++static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct hipp_softc *sc = arg; ++ ++ sc = sc; /* shut up compiler */ ++ ++ return IRQ_HANDLED; ++} ++ ++static struct pci_device_id hipp_pci_tbl[] = { ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++}; ++MODULE_DEVICE_TABLE(pci, hipp_pci_tbl); ++ ++static struct pci_driver hipp_driver = { ++ .name = "hipp", ++ .id_table = hipp_pci_tbl, ++ .probe = hipp_probe, ++ .remove = hipp_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init hipp_init (void) ++{ ++ struct hipp_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init); ++ ++ rc = pci_register_driver(&hipp_driver); ++ pci_register_driver_compat(&hipp_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit hipp_exit (void) ++{ ++ pci_unregister_driver(&hipp_driver); ++} ++ ++module_init(hipp_init); ++module_exit(hipp_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("Michael Richardson "); ++MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPreg.h linux-2.6.30/crypto/ocf/hifn/hifnHIPPreg.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPreg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPPreg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,46 @@ ++/*- ++ * Hifn HIPP-I/HIPP-II (7855/8155) driver. ++ * Copyright (c) 2006 Michael Richardson ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn inc. ++ * ++ */ ++ ++#ifndef __HIFNHIPP_H__ ++#define __HIFNHIPP_H__ ++ ++/* ++ * PCI vendor and device identifiers ++ */ ++#define PCI_VENDOR_HIFN 0x13a3 /* Hifn */ ++#define PCI_PRODUCT_HIFN_6500 0x0006 /* 6500 */ ++#define PCI_PRODUCT_HIFN_7855 0x001f /* 7855 */ ++#define PCI_PRODUCT_HIFN_8155 0x999 /* XXX 8155 */ ++ ++#define HIPP_1_REVID 0x01 /* BOGUS */ ++ ++#endif /* __HIPP_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPvar.h linux-2.6.30/crypto/ocf/hifn/hifnHIPPvar.h +--- linux-2.6.30.orig/crypto/ocf/hifn/hifnHIPPvar.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/hifnHIPPvar.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,93 @@ ++/* ++ * Hifn HIPP-I/HIPP-II (7855/8155) driver. ++ * Copyright (c) 2006 Michael Richardson * ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * Effort sponsored by Hifn inc. ++ * ++ */ ++ ++#ifndef __HIFNHIPPVAR_H__ ++#define __HIFNHIPPVAR_H__ ++ ++#define HIPP_MAX_CHIPS 8 ++ ++/* ++ * Holds data specific to a single Hifn HIPP-I board. ++ */ ++struct hipp_softc { ++ softc_device_decl sc_dev; ++ ++ struct pci_dev *sc_pcidev; /* device backpointer */ ++ ocf_iomem_t sc_bar[5]; ++ caddr_t sc_barphy[5]; /* physical address */ ++ int sc_num; /* for multiple devs */ ++ spinlock_t sc_mtx; /* per-instance lock */ ++ int32_t sc_cid; ++ int sc_irq; ++ ++#if 0 ++ ++ u_int32_t sc_dmaier; ++ u_int32_t sc_drammodel; /* 1=dram, 0=sram */ ++ u_int32_t sc_pllconfig; /* 7954/7955/7956 PLL config */ ++ ++ struct hifn_dma *sc_dma; ++ dma_addr_t sc_dma_physaddr;/* physical address of sc_dma */ ++ ++ int sc_dmansegs; ++ int sc_maxses; ++ int sc_nsessions; ++ struct hifn_session *sc_sessions; ++ int sc_ramsize; ++ int sc_flags; ++#define HIFN_HAS_RNG 0x1 /* includes random number generator */ ++#define HIFN_HAS_PUBLIC 0x2 /* includes public key support */ ++#define HIFN_HAS_AES 0x4 /* includes AES support */ ++#define HIFN_IS_7811 0x8 /* Hifn 7811 part */ ++#define HIFN_IS_7956 0x10 /* Hifn 7956/7955 don't have SDRAM */ ++ ++ struct timer_list sc_tickto; /* for managing DMA */ ++ ++ int sc_rngfirst; ++ int sc_rnghz; /* RNG polling frequency */ ++ ++ int sc_c_busy; /* command ring busy */ ++ int sc_s_busy; /* source data ring busy */ ++ int sc_d_busy; /* destination data ring busy */ ++ int sc_r_busy; /* result ring busy */ ++ int sc_active; /* for initial countdown */ ++ int sc_needwakeup; /* ops q'd wating on resources */ ++ int sc_curbatch; /* # ops submitted w/o int */ ++ int sc_suspended; ++ struct miscdevice sc_miscdev; ++#endif ++}; ++ ++#define HIPP_LOCK(_sc) spin_lock_irqsave(&(_sc)->sc_mtx, l_flags) ++#define HIPP_UNLOCK(_sc) spin_unlock_irqrestore(&(_sc)->sc_mtx, l_flags) ++ ++#endif /* __HIFNHIPPVAR_H__ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/hifn/Makefile linux-2.6.30/crypto/ocf/hifn/Makefile +--- linux-2.6.30.orig/crypto/ocf/hifn/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/hifn/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,13 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_HIFN) += hifn7751.o ++obj-$(CONFIG_OCF_HIFNHIPP) += hifnHIPP.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ixp4xx/ixp4xx.c linux-2.6.30/crypto/ocf/ixp4xx/ixp4xx.c +--- linux-2.6.30.orig/crypto/ocf/ixp4xx/ixp4xx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ixp4xx/ixp4xx.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1328 @@ ++/* ++ * An OCF module that uses Intels IXP CryptACC API to do the crypto. ++ * This driver requires the IXP400 Access Library that is available ++ * from Intel in order to operate (or compile). ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifndef IX_MBUF_PRIV ++#define IX_MBUF_PRIV(x) ((x)->priv) ++#endif ++ ++struct ixp_data; ++ ++struct ixp_q { ++ struct list_head ixp_q_list; ++ struct ixp_data *ixp_q_data; ++ struct cryptop *ixp_q_crp; ++ struct cryptodesc *ixp_q_ccrd; ++ struct cryptodesc *ixp_q_acrd; ++ IX_MBUF ixp_q_mbuf; ++ UINT8 *ixp_hash_dest; /* Location for hash in client buffer */ ++ UINT8 *ixp_hash_src; /* Location of hash in internal buffer */ ++ unsigned char ixp_q_iv_data[IX_CRYPTO_ACC_MAX_CIPHER_IV_LENGTH]; ++ unsigned char *ixp_q_iv; ++}; ++ ++struct ixp_data { ++ int ixp_registered; /* is the context registered */ ++ int ixp_crd_flags; /* detect direction changes */ ++ ++ int ixp_cipher_alg; ++ int ixp_auth_alg; ++ ++ UINT32 ixp_ctx_id; ++ UINT32 ixp_hash_key_id; /* used when hashing */ ++ IxCryptoAccCtx ixp_ctx; ++ IX_MBUF ixp_pri_mbuf; ++ IX_MBUF ixp_sec_mbuf; ++ ++ struct work_struct ixp_pending_work; ++ struct work_struct ixp_registration_work; ++ struct list_head ixp_q; /* unprocessed requests */ ++}; ++ ++#ifdef __ixp46X ++ ++#define MAX_IOP_SIZE 64 /* words */ ++#define MAX_OOP_SIZE 128 ++ ++#define MAX_PARAMS 3 ++ ++struct ixp_pkq { ++ struct list_head pkq_list; ++ struct cryptkop *pkq_krp; ++ ++ IxCryptoAccPkeEauInOperands pkq_op; ++ IxCryptoAccPkeEauOpResult pkq_result; ++ ++ UINT32 pkq_ibuf0[MAX_IOP_SIZE]; ++ UINT32 pkq_ibuf1[MAX_IOP_SIZE]; ++ UINT32 pkq_ibuf2[MAX_IOP_SIZE]; ++ UINT32 pkq_obuf[MAX_OOP_SIZE]; ++}; ++ ++static LIST_HEAD(ixp_pkq); /* current PK wait list */ ++static struct ixp_pkq *ixp_pk_cur; ++static spinlock_t ixp_pkq_lock; ++ ++#endif /* __ixp46X */ ++ ++static int ixp_blocked = 0; ++ ++static int32_t ixp_id = -1; ++static struct ixp_data **ixp_sessions = NULL; ++static u_int32_t ixp_sesnum = 0; ++ ++static int ixp_process(device_t, struct cryptop *, int); ++static int ixp_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int ixp_freesession(device_t, u_int64_t); ++#ifdef __ixp46X ++static int ixp_kprocess(device_t, struct cryptkop *krp, int hint); ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static kmem_cache_t *qcache; ++#else ++static struct kmem_cache *qcache; ++#endif ++ ++#define debug ixp_debug ++static int ixp_debug = 0; ++module_param(ixp_debug, int, 0644); ++MODULE_PARM_DESC(ixp_debug, "Enable debug"); ++ ++static int ixp_init_crypto = 1; ++module_param(ixp_init_crypto, int, 0444); /* RO after load/boot */ ++MODULE_PARM_DESC(ixp_init_crypto, "Call ixCryptoAccInit (default is 1)"); ++ ++static void ixp_process_pending(void *arg); ++static void ixp_registration(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ixp_process_pending_wq(struct work_struct *work); ++static void ixp_registration_wq(struct work_struct *work); ++#endif ++ ++/* ++ * dummy device structure ++ */ ++ ++static struct { ++ softc_device_decl sc_dev; ++} ixpdev; ++ ++static device_method_t ixp_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, ixp_newsession), ++ DEVMETHOD(cryptodev_freesession,ixp_freesession), ++ DEVMETHOD(cryptodev_process, ixp_process), ++#ifdef __ixp46X ++ DEVMETHOD(cryptodev_kprocess, ixp_kprocess), ++#endif ++}; ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++ixp_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) ++{ ++ struct ixp_data *ixp; ++ u_int32_t i; ++#define AUTH_LEN(cri, def) \ ++ (cri->cri_mlen ? cri->cri_mlen : (def)) ++ ++ dprintk("%s():alg %d\n", __FUNCTION__,cri->cri_alg); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (ixp_sessions) { ++ for (i = 1; i < ixp_sesnum; i++) ++ if (ixp_sessions[i] == NULL) ++ break; ++ } else ++ i = 1; /* NB: to silence compiler warning */ ++ ++ if (ixp_sessions == NULL || i == ixp_sesnum) { ++ struct ixp_data **ixpd; ++ ++ if (ixp_sessions == NULL) { ++ i = 1; /* We leave ixp_sessions[0] empty */ ++ ixp_sesnum = CRYPTO_SW_SESSIONS; ++ } else ++ ixp_sesnum *= 2; ++ ++ ixpd = kmalloc(ixp_sesnum * sizeof(struct ixp_data *), SLAB_ATOMIC); ++ if (ixpd == NULL) { ++ /* Reset session number */ ++ if (ixp_sesnum == CRYPTO_SW_SESSIONS) ++ ixp_sesnum = 0; ++ else ++ ixp_sesnum /= 2; ++ dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ memset(ixpd, 0, ixp_sesnum * sizeof(struct ixp_data *)); ++ ++ /* Copy existing sessions */ ++ if (ixp_sessions) { ++ memcpy(ixpd, ixp_sessions, ++ (ixp_sesnum / 2) * sizeof(struct ixp_data *)); ++ kfree(ixp_sessions); ++ } ++ ++ ixp_sessions = ixpd; ++ } ++ ++ ixp_sessions[i] = (struct ixp_data *) kmalloc(sizeof(struct ixp_data), ++ SLAB_ATOMIC); ++ if (ixp_sessions[i] == NULL) { ++ ixp_freesession(NULL, i); ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return ENOBUFS; ++ } ++ ++ *sid = i; ++ ++ ixp = ixp_sessions[i]; ++ memset(ixp, 0, sizeof(*ixp)); ++ ++ ixp->ixp_cipher_alg = -1; ++ ixp->ixp_auth_alg = -1; ++ ixp->ixp_ctx_id = -1; ++ INIT_LIST_HEAD(&ixp->ixp_q); ++ ++ ixp->ixp_ctx.useDifferentSrcAndDestMbufs = 0; ++ ++ while (cri) { ++ switch (cri->cri_alg) { ++ case CRYPTO_DES_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_DES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = ++ IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_3DES_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = ++ IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_RIJNDAEL128_CBC: ++ ixp->ixp_cipher_alg = cri->cri_alg; ++ ixp->ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_AES; ++ ixp->ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp->ixp_ctx.cipherCtx.cipherKeyLen = (cri->cri_klen + 7) / 8; ++ ixp->ixp_ctx.cipherCtx.cipherBlockLen = 16; ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen = 16; ++ memcpy(ixp->ixp_ctx.cipherCtx.key.cipherKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ break; ++ ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ ixp->ixp_auth_alg = cri->cri_alg; ++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_MD5; ++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, MD5_HASH_LEN); ++ ixp->ixp_ctx.authCtx.aadLen = 0; ++ /* Only MD5_HMAC needs a key */ ++ if (cri->cri_alg == CRYPTO_MD5_HMAC) { ++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; ++ if (ixp->ixp_ctx.authCtx.authKeyLen > ++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { ++ printk( ++ "ixp4xx: Invalid key length for MD5_HMAC - %d bits\n", ++ cri->cri_klen); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ memcpy(ixp->ixp_ctx.authCtx.key.authKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ } ++ break; ++ ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ ixp->ixp_auth_alg = cri->cri_alg; ++ ixp->ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; ++ ixp->ixp_ctx.authCtx.authDigestLen = AUTH_LEN(cri, SHA1_HASH_LEN); ++ ixp->ixp_ctx.authCtx.aadLen = 0; ++ /* Only SHA1_HMAC needs a key */ ++ if (cri->cri_alg == CRYPTO_SHA1_HMAC) { ++ ixp->ixp_ctx.authCtx.authKeyLen = (cri->cri_klen + 7) / 8; ++ if (ixp->ixp_ctx.authCtx.authKeyLen > ++ sizeof(ixp->ixp_ctx.authCtx.key.authKey)) { ++ printk( ++ "ixp4xx: Invalid key length for SHA1_HMAC - %d bits\n", ++ cri->cri_klen); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ memcpy(ixp->ixp_ctx.authCtx.key.authKey, ++ cri->cri_key, (cri->cri_klen + 7) / 8); ++ } ++ break; ++ ++ default: ++ printk("ixp: unknown algo 0x%x\n", cri->cri_alg); ++ ixp_freesession(NULL, i); ++ return EINVAL; ++ } ++ cri = cri->cri_next; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending_wq); ++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration_wq); ++#else ++ INIT_WORK(&ixp->ixp_pending_work, ixp_process_pending, ixp); ++ INIT_WORK(&ixp->ixp_registration_work, ixp_registration, ixp); ++#endif ++ ++ return 0; ++} ++ ++ ++/* ++ * Free a session. ++ */ ++static int ++ixp_freesession(device_t dev, u_int64_t tid) ++{ ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > ixp_sesnum || ixp_sessions == NULL || ++ ixp_sessions[sid] == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return 0; ++ ++ if (ixp_sessions[sid]) { ++ if (ixp_sessions[sid]->ixp_ctx_id != -1) { ++ ixCryptoAccCtxUnregister(ixp_sessions[sid]->ixp_ctx_id); ++ ixp_sessions[sid]->ixp_ctx_id = -1; ++ } ++ ++ flush_scheduled_work(); ++ ++ kfree(ixp_sessions[sid]); ++ } ++ ixp_sessions[sid] = NULL; ++ if (ixp_blocked) { ++ ixp_blocked = 0; ++ crypto_unblock(ixp_id, CRYPTO_SYMQ); ++ } ++ return 0; ++} ++ ++ ++/* ++ * callback for when hash processing is complete ++ */ ++ ++static void ++ixp_hash_perform_cb( ++ UINT32 hash_key_id, ++ IX_MBUF *bufp, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_q *q; ++ ++ dprintk("%s(%u, %p, 0x%x)\n", __FUNCTION__, hash_key_id, bufp, status); ++ ++ if (bufp == NULL) { ++ printk("ixp: NULL buf in %s\n", __FUNCTION__); ++ return; ++ } ++ ++ q = IX_MBUF_PRIV(bufp); ++ if (q == NULL) { ++ printk("ixp: NULL priv in %s\n", __FUNCTION__); ++ return; ++ } ++ ++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ /* On success, need to copy hash back into original client buffer */ ++ memcpy(q->ixp_hash_dest, q->ixp_hash_src, ++ (q->ixp_q_data->ixp_auth_alg == CRYPTO_SHA1) ? ++ SHA1_HASH_LEN : MD5_HASH_LEN); ++ } ++ else { ++ printk("ixp: hash perform failed status=%d\n", status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ } ++ ++ /* Free internal buffer used for hashing */ ++ kfree(IX_MBUF_MDATA(&q->ixp_q_mbuf)); ++ ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++/* ++ * setup a request and perform it ++ */ ++static void ++ixp_q_process(struct ixp_q *q) ++{ ++ IxCryptoAccStatus status; ++ struct ixp_data *ixp = q->ixp_q_data; ++ int auth_off = 0; ++ int auth_len = 0; ++ int crypt_off = 0; ++ int crypt_len = 0; ++ int icv_off = 0; ++ char *crypt_func; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, q); ++ ++ if (q->ixp_q_ccrd) { ++ if (q->ixp_q_ccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ q->ixp_q_iv = q->ixp_q_ccrd->crd_iv; ++ } else { ++ q->ixp_q_iv = q->ixp_q_iv_data; ++ crypto_copydata(q->ixp_q_crp->crp_flags, q->ixp_q_crp->crp_buf, ++ q->ixp_q_ccrd->crd_inject, ++ ixp->ixp_ctx.cipherCtx.cipherInitialVectorLen, ++ (caddr_t) q->ixp_q_iv); ++ } ++ ++ if (q->ixp_q_acrd) { ++ auth_off = q->ixp_q_acrd->crd_skip; ++ auth_len = q->ixp_q_acrd->crd_len; ++ icv_off = q->ixp_q_acrd->crd_inject; ++ } ++ ++ crypt_off = q->ixp_q_ccrd->crd_skip; ++ crypt_len = q->ixp_q_ccrd->crd_len; ++ } else { /* if (q->ixp_q_acrd) */ ++ auth_off = q->ixp_q_acrd->crd_skip; ++ auth_len = q->ixp_q_acrd->crd_len; ++ icv_off = q->ixp_q_acrd->crd_inject; ++ } ++ ++ if (q->ixp_q_crp->crp_flags & CRYPTO_F_SKBUF) { ++ struct sk_buff *skb = (struct sk_buff *) q->ixp_q_crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ /* ++ * DAVIDM fix this limitation one day by using ++ * a buffer pool and chaining, it is not currently ++ * needed for current user/kernel space acceleration ++ */ ++ printk("ixp: Cannot handle fragmented skb's yet !\n"); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ goto done; ++ } ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = skb->len; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = skb->data; ++ } else if (q->ixp_q_crp->crp_flags & CRYPTO_F_IOV) { ++ struct uio *uiop = (struct uio *) q->ixp_q_crp->crp_buf; ++ if (uiop->uio_iovcnt != 1) { ++ /* ++ * DAVIDM fix this limitation one day by using ++ * a buffer pool and chaining, it is not currently ++ * needed for current user/kernel space acceleration ++ */ ++ printk("ixp: Cannot handle more than 1 iovec yet !\n"); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ goto done; ++ } ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_len; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = uiop->uio_iov[0].iov_base; ++ } else /* contig buffer */ { ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = ++ IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_ilen; ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = q->ixp_q_crp->crp_buf; ++ } ++ ++ IX_MBUF_PRIV(&q->ixp_q_mbuf) = q; ++ ++ if (ixp->ixp_auth_alg == CRYPTO_SHA1 || ixp->ixp_auth_alg == CRYPTO_MD5) { ++ /* ++ * For SHA1 and MD5 hash, need to create an internal buffer that is big ++ * enough to hold the original data + the appropriate padding for the ++ * hash algorithm. ++ */ ++ UINT8 *tbuf = NULL; ++ ++ IX_MBUF_MLEN(&q->ixp_q_mbuf) = IX_MBUF_PKT_LEN(&q->ixp_q_mbuf) = ++ ((IX_MBUF_MLEN(&q->ixp_q_mbuf) * 8) + 72 + 511) / 8; ++ tbuf = kmalloc(IX_MBUF_MLEN(&q->ixp_q_mbuf), SLAB_ATOMIC); ++ ++ if (IX_MBUF_MDATA(&q->ixp_q_mbuf) == NULL) { ++ printk("ixp: kmalloc(%u, SLAB_ATOMIC) failed\n", ++ IX_MBUF_MLEN(&q->ixp_q_mbuf)); ++ q->ixp_q_crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ memcpy(tbuf, &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off], auth_len); ++ ++ /* Set location in client buffer to copy hash into */ ++ q->ixp_hash_dest = ++ &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_off + auth_len]; ++ ++ IX_MBUF_MDATA(&q->ixp_q_mbuf) = tbuf; ++ ++ /* Set location in internal buffer for where hash starts */ ++ q->ixp_hash_src = &(IX_MBUF_MDATA(&q->ixp_q_mbuf))[auth_len]; ++ ++ crypt_func = "ixCryptoAccHashPerform"; ++ status = ixCryptoAccHashPerform(ixp->ixp_ctx.authCtx.authAlgo, ++ &q->ixp_q_mbuf, ixp_hash_perform_cb, 0, auth_len, auth_len, ++ &ixp->ixp_hash_key_id); ++ } ++ else { ++ crypt_func = "ixCryptoAccAuthCryptPerform"; ++ status = ixCryptoAccAuthCryptPerform(ixp->ixp_ctx_id, &q->ixp_q_mbuf, ++ NULL, auth_off, auth_len, crypt_off, crypt_len, icv_off, ++ q->ixp_q_iv); ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ return; ++ ++ if (IX_CRYPTO_ACC_STATUS_QUEUE_FULL == status) { ++ q->ixp_q_crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ ++ printk("ixp: %s failed %u\n", crypt_func, status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ ++done: ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++ ++/* ++ * because we cannot process the Q from the Register callback ++ * we do it here on a task Q. ++ */ ++ ++static void ++ixp_process_pending(void *arg) ++{ ++ struct ixp_data *ixp = arg; ++ struct ixp_q *q = NULL; ++ ++ dprintk("%s(%p)\n", __FUNCTION__, arg); ++ ++ if (!ixp) ++ return; ++ ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ ixp_q_process(q); ++ } ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_process_pending_wq(struct work_struct *work) ++{ ++ struct ixp_data *ixp = container_of(work, struct ixp_data, ++ ixp_pending_work); ++ ixp_process_pending(ixp); ++} ++#endif ++ ++/* ++ * callback for when context registration is complete ++ */ ++ ++static void ++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) ++{ ++ int i; ++ struct ixp_data *ixp; ++ struct ixp_q *q; ++ ++ dprintk("%s(%d, %p, %d)\n", __FUNCTION__, ctx_id, bufp, status); ++ ++ /* ++ * free any buffer passed in to this routine ++ */ ++ if (bufp) { ++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; ++ kfree(IX_MBUF_MDATA(bufp)); ++ IX_MBUF_MDATA(bufp) = NULL; ++ } ++ ++ for (i = 0; i < ixp_sesnum; i++) { ++ ixp = ixp_sessions[i]; ++ if (ixp && ixp->ixp_ctx_id == ctx_id) ++ break; ++ } ++ if (i >= ixp_sesnum) { ++ printk("ixp: invalid context id %d\n", ctx_id); ++ return; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_WAIT == status) { ++ /* this is normal to free the first of two buffers */ ++ dprintk("ixp: register not finished yet.\n"); ++ return; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { ++ printk("ixp: register failed 0x%x\n", status); ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++ } ++ return; ++ } ++ ++ /* ++ * we are now registered, we cannot start processing the Q here ++ * or we get strange errors with AES (DES/3DES seem to be ok). ++ */ ++ ixp->ixp_registered = 1; ++ schedule_work(&ixp->ixp_pending_work); ++} ++ ++ ++/* ++ * callback for when data processing is complete ++ */ ++ ++static void ++ixp_perform_cb( ++ UINT32 ctx_id, ++ IX_MBUF *sbufp, ++ IX_MBUF *dbufp, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_q *q; ++ ++ dprintk("%s(%d, %p, %p, 0x%x)\n", __FUNCTION__, ctx_id, sbufp, ++ dbufp, status); ++ ++ if (sbufp == NULL) { ++ printk("ixp: NULL sbuf in ixp_perform_cb\n"); ++ return; ++ } ++ ++ q = IX_MBUF_PRIV(sbufp); ++ if (q == NULL) { ++ printk("ixp: NULL priv in ixp_perform_cb\n"); ++ return; ++ } ++ ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ printk("ixp: perform failed status=%d\n", status); ++ q->ixp_q_crp->crp_etype = EINVAL; ++ } ++ ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++} ++ ++ ++/* ++ * registration is not callable at IRQ time, so we defer ++ * to a task queue, this routines completes the registration for us ++ * when the task queue runs ++ * ++ * Unfortunately this means we cannot tell OCF that the driver is blocked, ++ * we do that on the next request. ++ */ ++ ++static void ++ixp_registration(void *arg) ++{ ++ struct ixp_data *ixp = arg; ++ struct ixp_q *q = NULL; ++ IX_MBUF *pri = NULL, *sec = NULL; ++ int status = IX_CRYPTO_ACC_STATUS_SUCCESS; ++ ++ if (!ixp) { ++ printk("ixp: ixp_registration with no arg\n"); ++ return; ++ } ++ ++ if (ixp->ixp_ctx_id != -1) { ++ ixCryptoAccCtxUnregister(ixp->ixp_ctx_id); ++ ixp->ixp_ctx_id = -1; ++ } ++ ++ if (list_empty(&ixp->ixp_q)) { ++ printk("ixp: ixp_registration with no Q\n"); ++ return; ++ } ++ ++ /* ++ * setup the primary and secondary buffers ++ */ ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ if (q->ixp_q_acrd) { ++ pri = &ixp->ixp_pri_mbuf; ++ sec = &ixp->ixp_sec_mbuf; ++ IX_MBUF_MLEN(pri) = IX_MBUF_PKT_LEN(pri) = 128; ++ IX_MBUF_MDATA(pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ IX_MBUF_MLEN(sec) = IX_MBUF_PKT_LEN(sec) = 128; ++ IX_MBUF_MDATA(sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ } ++ ++ /* Only need to register if a crypt op or HMAC op */ ++ if (!(ixp->ixp_auth_alg == CRYPTO_SHA1 || ++ ixp->ixp_auth_alg == CRYPTO_MD5)) { ++ status = ixCryptoAccCtxRegister( ++ &ixp->ixp_ctx, ++ pri, sec, ++ ixp_register_cb, ++ ixp_perform_cb, ++ &ixp->ixp_ctx_id); ++ } ++ else { ++ /* Otherwise we start processing pending q */ ++ schedule_work(&ixp->ixp_pending_work); ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ return; ++ ++ if (IX_CRYPTO_ACC_STATUS_EXCEED_MAX_TUNNELS == status) { ++ printk("ixp: ixCryptoAccCtxRegister failed (out of tunnels)\n"); ++ ixp_blocked = 1; ++ /* perhaps we should return EGAIN on queued ops ? */ ++ return; ++ } ++ ++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); ++ ixp->ixp_ctx_id = -1; ++ ++ /* ++ * everything waiting is toasted ++ */ ++ while (!list_empty(&ixp->ixp_q)) { ++ q = list_entry(ixp->ixp_q.next, struct ixp_q, ixp_q_list); ++ list_del(&q->ixp_q_list); ++ q->ixp_q_crp->crp_etype = ENOENT; ++ crypto_done(q->ixp_q_crp); ++ kmem_cache_free(qcache, q); ++ } ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_registration_wq(struct work_struct *work) ++{ ++ struct ixp_data *ixp = container_of(work, struct ixp_data, ++ ixp_registration_work); ++ ixp_registration(ixp); ++} ++#endif ++ ++/* ++ * Process a request. ++ */ ++static int ++ixp_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct ixp_data *ixp; ++ unsigned int lid; ++ struct ixp_q *q = NULL; ++ int status; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (ixp_blocked) ++ return ERESTART; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ /* ++ * find the session we are using ++ */ ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= ixp_sesnum || lid == 0 || ixp_sessions == NULL || ++ ixp_sessions[lid] == NULL) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ixp = ixp_sessions[lid]; ++ ++ /* ++ * setup a new request ready for queuing ++ */ ++ q = kmem_cache_alloc(qcache, SLAB_ATOMIC); ++ if (q == NULL) { ++ dprintk("%s,%d: ENOMEM\n", __FILE__, __LINE__); ++ crp->crp_etype = ENOMEM; ++ goto done; ++ } ++ /* ++ * save some cycles by only zeroing the important bits ++ */ ++ memset(&q->ixp_q_mbuf, 0, sizeof(q->ixp_q_mbuf)); ++ q->ixp_q_ccrd = NULL; ++ q->ixp_q_acrd = NULL; ++ q->ixp_q_crp = crp; ++ q->ixp_q_data = ixp; ++ ++ /* ++ * point the cipher and auth descriptors appropriately ++ * check that we have something to do ++ */ ++ if (crp->crp_desc->crd_alg == ixp->ixp_cipher_alg) ++ q->ixp_q_ccrd = crp->crp_desc; ++ else if (crp->crp_desc->crd_alg == ixp->ixp_auth_alg) ++ q->ixp_q_acrd = crp->crp_desc; ++ else { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ if (crp->crp_desc->crd_next) { ++ if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_cipher_alg) ++ q->ixp_q_ccrd = crp->crp_desc->crd_next; ++ else if (crp->crp_desc->crd_next->crd_alg == ixp->ixp_auth_alg) ++ q->ixp_q_acrd = crp->crp_desc->crd_next; ++ else { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: bad desc match: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ } ++ ++ /* ++ * If there is a direction change for this context then we mark it as ++ * unregistered and re-register is for the new direction. This is not ++ * a very expensive operation and currently only tends to happen when ++ * user-space application are doing benchmarks ++ * ++ * DM - we should be checking for pending requests before unregistering. ++ */ ++ if (q->ixp_q_ccrd && ixp->ixp_registered && ++ ixp->ixp_crd_flags != (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT)) { ++ dprintk("%s - detected direction change on session\n", __FUNCTION__); ++ ixp->ixp_registered = 0; ++ } ++ ++ /* ++ * if we are registered, call straight into the perform code ++ */ ++ if (ixp->ixp_registered) { ++ ixp_q_process(q); ++ return 0; ++ } ++ ++ /* ++ * the only part of the context not set in newsession is the direction ++ * dependent parts ++ */ ++ if (q->ixp_q_ccrd) { ++ ixp->ixp_crd_flags = (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT); ++ if (q->ixp_q_ccrd->crd_flags & CRD_F_ENCRYPT) { ++ ixp->ixp_ctx.operation = q->ixp_q_acrd ? ++ IX_CRYPTO_ACC_OP_ENCRYPT_AUTH : IX_CRYPTO_ACC_OP_ENCRYPT; ++ } else { ++ ixp->ixp_ctx.operation = q->ixp_q_acrd ? ++ IX_CRYPTO_ACC_OP_AUTH_DECRYPT : IX_CRYPTO_ACC_OP_DECRYPT; ++ } ++ } else { ++ /* q->ixp_q_acrd must be set if we are here */ ++ ixp->ixp_ctx.operation = IX_CRYPTO_ACC_OP_AUTH_CALC; ++ } ++ ++ status = list_empty(&ixp->ixp_q); ++ list_add_tail(&q->ixp_q_list, &ixp->ixp_q); ++ if (status) ++ schedule_work(&ixp->ixp_registration_work); ++ return 0; ++ ++done: ++ if (q) ++ kmem_cache_free(qcache, q); ++ crypto_done(crp); ++ return 0; ++} ++ ++ ++#ifdef __ixp46X ++/* ++ * key processing support for the ixp465 ++ */ ++ ++ ++/* ++ * copy a BN (LE) into a buffer (BE) an fill out the op appropriately ++ * assume zeroed and only copy bits that are significant ++ */ ++ ++static int ++ixp_copy_ibuf(struct crparam *p, IxCryptoAccPkeEauOperand *op, UINT32 *buf) ++{ ++ unsigned char *src = (unsigned char *) p->crp_p; ++ unsigned char *dst; ++ int len, bits = p->crp_nbits; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ if (bits > MAX_IOP_SIZE * sizeof(UINT32) * 8) { ++ dprintk("%s - ibuf too big (%d > %d)\n", __FUNCTION__, ++ bits, MAX_IOP_SIZE * sizeof(UINT32) * 8); ++ return -1; ++ } ++ ++ len = (bits + 31) / 32; /* the number UINT32's needed */ ++ ++ dst = (unsigned char *) &buf[len]; ++ dst--; ++ ++ while (bits > 0) { ++ *dst-- = *src++; ++ bits -= 8; ++ } ++ ++#if 0 /* no need to zero remaining bits as it is done during request alloc */ ++ while (dst > (unsigned char *) buf) ++ *dst-- = '\0'; ++#endif ++ ++ op->pData = buf; ++ op->dataLen = len; ++ return 0; ++} ++ ++/* ++ * copy out the result, be as forgiving as we can about small output buffers ++ */ ++ ++static int ++ixp_copy_obuf(struct crparam *p, IxCryptoAccPkeEauOpResult *op, UINT32 *buf) ++{ ++ unsigned char *dst = (unsigned char *) p->crp_p; ++ unsigned char *src = (unsigned char *) buf; ++ int len, z, bits = p->crp_nbits; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ len = op->dataLen * sizeof(UINT32); ++ ++ /* skip leading zeroes to be small buffer friendly */ ++ z = 0; ++ while (z < len && src[z] == '\0') ++ z++; ++ ++ src += len; ++ src--; ++ len -= z; ++ ++ while (len > 0 && bits > 0) { ++ *dst++ = *src--; ++ len--; ++ bits -= 8; ++ } ++ ++ while (bits > 0) { ++ *dst++ = '\0'; ++ bits -= 8; ++ } ++ ++ if (len > 0) { ++ dprintk("%s - obuf is %d (z=%d, ob=%d) bytes too small\n", ++ __FUNCTION__, len, z, p->crp_nbits / 8); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * the parameter offsets for exp_mod ++ */ ++ ++#define IXP_PARAM_BASE 0 ++#define IXP_PARAM_EXP 1 ++#define IXP_PARAM_MOD 2 ++#define IXP_PARAM_RES 3 ++ ++/* ++ * key processing complete callback, is also used to start processing ++ * by passing a NULL for pResult ++ */ ++ ++static void ++ixp_kperform_cb( ++ IxCryptoAccPkeEauOperation operation, ++ IxCryptoAccPkeEauOpResult *pResult, ++ BOOL carryOrBorrow, ++ IxCryptoAccStatus status) ++{ ++ struct ixp_pkq *q, *tmp; ++ unsigned long flags; ++ ++ dprintk("%s(0x%x, %p, %d, 0x%x)\n", __FUNCTION__, operation, pResult, ++ carryOrBorrow, status); ++ ++ /* handle a completed request */ ++ if (pResult) { ++ if (ixp_pk_cur && &ixp_pk_cur->pkq_result == pResult) { ++ q = ixp_pk_cur; ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s() - op failed 0x%x\n", __FUNCTION__, status); ++ q->pkq_krp->krp_status = ERANGE; /* could do better */ ++ } else { ++ /* copy out the result */ ++ if (ixp_copy_obuf(&q->pkq_krp->krp_param[IXP_PARAM_RES], ++ &q->pkq_result, q->pkq_obuf)) ++ q->pkq_krp->krp_status = ERANGE; ++ } ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ ixp_pk_cur = NULL; ++ } else ++ printk("%s - callback with invalid result pointer\n", __FUNCTION__); ++ } ++ ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ if (ixp_pk_cur || list_empty(&ixp_pkq)) { ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ return; ++ } ++ ++ list_for_each_entry_safe(q, tmp, &ixp_pkq, pkq_list) { ++ ++ list_del(&q->pkq_list); ++ ixp_pk_cur = q; ++ ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ ++ status = ixCryptoAccPkeEauPerform( ++ IX_CRYPTO_ACC_OP_EAU_MOD_EXP, ++ &q->pkq_op, ++ ixp_kperform_cb, ++ &q->pkq_result); ++ ++ if (status == IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s() - ixCryptoAccPkeEauPerform SUCCESS\n", __FUNCTION__); ++ return; /* callback will return here for callback */ ++ } else if (status == IX_CRYPTO_ACC_STATUS_RETRY) { ++ printk("%s() - ixCryptoAccPkeEauPerform RETRY\n", __FUNCTION__); ++ } else { ++ printk("%s() - ixCryptoAccPkeEauPerform failed %d\n", ++ __FUNCTION__, status); ++ } ++ q->pkq_krp->krp_status = ERANGE; /* could do better */ ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ } ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++} ++ ++ ++static int ++ixp_kprocess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ struct ixp_pkq *q; ++ int rc = 0; ++ unsigned long flags; ++ ++ dprintk("%s l1=%d l2=%d l3=%d l4=%d\n", __FUNCTION__, ++ krp->krp_param[IXP_PARAM_BASE].crp_nbits, ++ krp->krp_param[IXP_PARAM_EXP].crp_nbits, ++ krp->krp_param[IXP_PARAM_MOD].crp_nbits, ++ krp->krp_param[IXP_PARAM_RES].crp_nbits); ++ ++ ++ if (krp->krp_op != CRK_MOD_EXP) { ++ krp->krp_status = EOPNOTSUPP; ++ goto err; ++ } ++ ++ q = (struct ixp_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); ++ if (q == NULL) { ++ krp->krp_status = ENOMEM; ++ goto err; ++ } ++ ++ /* ++ * The PKE engine does not appear to zero the output buffer ++ * appropriately, so we need to do it all here. ++ */ ++ memset(q, 0, sizeof(*q)); ++ ++ q->pkq_krp = krp; ++ INIT_LIST_HEAD(&q->pkq_list); ++ ++ if (ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_BASE], &q->pkq_op.modExpOpr.M, ++ q->pkq_ibuf0)) ++ rc = 1; ++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_EXP], ++ &q->pkq_op.modExpOpr.e, q->pkq_ibuf1)) ++ rc = 2; ++ if (!rc && ixp_copy_ibuf(&krp->krp_param[IXP_PARAM_MOD], ++ &q->pkq_op.modExpOpr.N, q->pkq_ibuf2)) ++ rc = 3; ++ ++ if (rc) { ++ kfree(q); ++ krp->krp_status = ERANGE; ++ goto err; ++ } ++ ++ q->pkq_result.pData = q->pkq_obuf; ++ q->pkq_result.dataLen = ++ (krp->krp_param[IXP_PARAM_RES].crp_nbits + 31) / 32; ++ ++ spin_lock_irqsave(&ixp_pkq_lock, flags); ++ list_add_tail(&q->pkq_list, &ixp_pkq); ++ spin_unlock_irqrestore(&ixp_pkq_lock, flags); ++ ++ if (!ixp_pk_cur) ++ ixp_kperform_cb(0, NULL, 0, 0); ++ return (0); ++ ++err: ++ crypto_kdone(krp); ++ return (0); ++} ++ ++ ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++/* ++ * We run the random number generator output through SHA so that it ++ * is FIPS compliant. ++ */ ++ ++static volatile int sha_done = 0; ++static unsigned char sha_digest[20]; ++ ++static void ++ixp_hash_cb(UINT8 *digest, IxCryptoAccStatus status) ++{ ++ dprintk("%s(%p, %d)\n", __FUNCTION__, digest, status); ++ if (sha_digest != digest) ++ printk("digest error\n"); ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ sha_done = 1; ++ else ++ sha_done = -status; ++} ++ ++static int ++ixp_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ IxCryptoAccStatus status; ++ int i, n, rc; ++ ++ dprintk("%s(%p, %d)\n", __FUNCTION__, buf, maxwords); ++ memset(buf, 0, maxwords * sizeof(*buf)); ++ status = ixCryptoAccPkePseudoRandomNumberGet(maxwords, buf); ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("%s: ixCryptoAccPkePseudoRandomNumberGet failed %d\n", ++ __FUNCTION__, status); ++ return 0; ++ } ++ ++ /* ++ * run the random data through SHA to make it look more random ++ */ ++ ++ n = sizeof(sha_digest); /* process digest bytes at a time */ ++ ++ rc = 0; ++ for (i = 0; i < maxwords; i += n / sizeof(*buf)) { ++ if ((maxwords - i) * sizeof(*buf) < n) ++ n = (maxwords - i) * sizeof(*buf); ++ sha_done = 0; ++ status = ixCryptoAccPkeHashPerform(IX_CRYPTO_ACC_AUTH_SHA1, ++ (UINT8 *) &buf[i], n, ixp_hash_cb, sha_digest); ++ if (status != IX_CRYPTO_ACC_STATUS_SUCCESS) { ++ dprintk("ixCryptoAccPkeHashPerform failed %d\n", status); ++ return -EIO; ++ } ++ while (!sha_done) ++ schedule(); ++ if (sha_done < 0) { ++ dprintk("ixCryptoAccPkeHashPerform failed CB %d\n", -sha_done); ++ return 0; ++ } ++ memcpy(&buf[i], sha_digest, n); ++ rc += n / sizeof(*buf);; ++ } ++ ++ return rc; ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++#endif /* __ixp46X */ ++ ++ ++ ++/* ++ * our driver startup and shutdown routines ++ */ ++ ++static int ++ixp_init(void) ++{ ++ dprintk("%s(%p)\n", __FUNCTION__, ixp_init); ++ ++ if (ixp_init_crypto && ixCryptoAccInit() != IX_CRYPTO_ACC_STATUS_SUCCESS) ++ printk("ixCryptoAccInit failed, assuming already initialised!\n"); ++ ++ qcache = kmem_cache_create("ixp4xx_q", sizeof(struct ixp_q), 0, ++ SLAB_HWCACHE_ALIGN, NULL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ++ , NULL ++#endif ++ ); ++ if (!qcache) { ++ printk("failed to create Qcache\n"); ++ return -ENOENT; ++ } ++ ++ memset(&ixpdev, 0, sizeof(ixpdev)); ++ softc_device_init(&ixpdev, "ixp4xx", 0, ixp_methods); ++ ++ ixp_id = crypto_get_driverid(softc_get_device(&ixpdev), ++ CRYPTOCAP_F_HARDWARE); ++ if (ixp_id < 0) ++ panic("IXP/OCF crypto device cannot initialize!"); ++ ++#define REGISTER(alg) \ ++ crypto_register(ixp_id,alg,0,0) ++ ++ REGISTER(CRYPTO_DES_CBC); ++ REGISTER(CRYPTO_3DES_CBC); ++ REGISTER(CRYPTO_RIJNDAEL128_CBC); ++#ifdef CONFIG_OCF_IXP4XX_SHA1_MD5 ++ REGISTER(CRYPTO_MD5); ++ REGISTER(CRYPTO_SHA1); ++#endif ++ REGISTER(CRYPTO_MD5_HMAC); ++ REGISTER(CRYPTO_SHA1_HMAC); ++#undef REGISTER ++ ++#ifdef __ixp46X ++ spin_lock_init(&ixp_pkq_lock); ++ /* ++ * we do not enable the go fast options here as they can potentially ++ * allow timing based attacks ++ * ++ * http://www.openssl.org/news/secadv_20030219.txt ++ */ ++ ixCryptoAccPkeEauExpConfig(0, 0); ++ crypto_kregister(ixp_id, CRK_MOD_EXP, 0); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ crypto_rregister(ixp_id, ixp_read_random, NULL); ++#endif ++#endif ++ ++ return 0; ++} ++ ++static void ++ixp_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(ixp_id); ++ ixp_id = -1; ++ kmem_cache_destroy(qcache); ++ qcache = NULL; ++} ++ ++module_init(ixp_init); ++module_exit(ixp_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("ixp (OCF module for IXP4xx crypto)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ixp4xx/Makefile linux-2.6.30/crypto/ocf/ixp4xx/Makefile +--- linux-2.6.30.orig/crypto/ocf/ixp4xx/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ixp4xx/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,104 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++# ++# You will need to point this at your Intel ixp425 includes, this portion ++# of the Makefile only really works under SGLinux with the appropriate libs ++# installed. They can be downloaded from http://www.snapgear.org/ ++# ++ifeq ($(CONFIG_CPU_IXP46X),y) ++IXPLATFORM = ixp46X ++else ++ifeq ($(CONFIG_CPU_IXP43X),y) ++IXPLATFORM = ixp43X ++else ++IXPLATFORM = ixp42X ++endif ++endif ++ ++ifdef CONFIG_IXP400_LIB_2_4 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.4/ixp_osal ++endif ++ifdef CONFIG_IXP400_LIB_2_1 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.1/ixp_osal ++endif ++ifdef CONFIG_IXP400_LIB_2_0 ++IX_XSCALE_SW = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp400_xscale_sw ++OSAL_DIR = $(ROOTDIR)/modules/ixp425/ixp400-2.0/ixp_osal ++endif ++ifdef IX_XSCALE_SW ++ifdef CONFIG_IXP400_LIB_2_4 ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(IX_XSCALE_SW)/src/include \ ++ -I$(OSAL_DIR)/common/include/ \ ++ -I$(OSAL_DIR)/common/include/modules/ \ ++ -I$(OSAL_DIR)/common/include/modules/ddk/ \ ++ -I$(OSAL_DIR)/common/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/common/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ddk/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/common/os/linux/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/include/ \ ++ -I$(OSAL_DIR)/platforms/$(IXPLATFORM)/os/linux/include/ \ ++ -DENABLE_IOMEM -DENABLE_BUFFERMGT -DENABLE_DDK \ ++ -DUSE_IXP4XX_CRYPTO ++else ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(IX_XSCALE_SW)/src/include \ ++ -I$(OSAL_DIR)/ \ ++ -I$(OSAL_DIR)/os/linux/include/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/os/linux/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp425 \ ++ -I$(OSAL_DIR)/os/linux/include/platforms/ixp400/ixp465 \ ++ -I$(OSAL_DIR)/os/linux/include/core/ \ ++ -I$(OSAL_DIR)/include/ \ ++ -I$(OSAL_DIR)/include/modules/ \ ++ -I$(OSAL_DIR)/include/modules/bufferMgt/ \ ++ -I$(OSAL_DIR)/include/modules/ioMem/ \ ++ -I$(OSAL_DIR)/include/platforms/ \ ++ -I$(OSAL_DIR)/include/platforms/ixp400/ \ ++ -DUSE_IXP4XX_CRYPTO ++endif ++endif ++ifdef CONFIG_IXP400_LIB_1_4 ++IXP_CFLAGS = \ ++ -I$(ROOTDIR)/. \ ++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/include \ ++ -I$(ROOTDIR)/modules/ixp425/ixp400-1.4/ixp400_xscale_sw/src/linux \ ++ -DUSE_IXP4XX_CRYPTO ++endif ++ifndef IXPDIR ++IXPDIR = ixp-version-is-not-supported ++endif ++ ++ifeq ($(CONFIG_CPU_IXP46X),y) ++IXP_CFLAGS += -D__ixp46X ++else ++ifeq ($(CONFIG_CPU_IXP43X),y) ++IXP_CFLAGS += -D__ixp43X ++else ++IXP_CFLAGS += -D__ixp42X ++endif ++endif ++ ++obj-$(CONFIG_OCF_IXP4XX) += ixp4xx.o ++ ++obj ?= . ++EXTRA_CFLAGS += $(IXP_CFLAGS) -I$(obj)/.. -I$(obj)/. ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/Kconfig linux-2.6.30/crypto/ocf/Kconfig +--- linux-2.6.30.orig/crypto/ocf/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Kconfig 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,101 @@ ++menu "OCF Configuration" ++ ++config OCF_OCF ++ tristate "OCF (Open Cryptograhic Framework)" ++ help ++ A linux port of the OpenBSD/FreeBSD crypto framework. ++ ++config OCF_RANDOMHARVEST ++ bool "crypto random --- harvest entropy for /dev/random" ++ depends on OCF_OCF ++ help ++ Includes code to harvest random numbers from devices that support it. ++ ++config OCF_FIPS ++ bool "enable fips RNG checks" ++ depends on OCF_OCF && OCF_RANDOMHARVEST ++ help ++ Run all RNG provided data through a fips check before ++ adding it /dev/random's entropy pool. ++ ++config OCF_CRYPTODEV ++ tristate "cryptodev (user space support)" ++ depends on OCF_OCF ++ help ++ The user space API to access crypto hardware. ++ ++config OCF_CRYPTOSOFT ++ tristate "cryptosoft (software crypto engine)" ++ depends on OCF_OCF ++ help ++ A software driver for the OCF framework that uses ++ the kernel CryptoAPI. ++ ++config OCF_SAFE ++ tristate "safenet (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ A driver for a number of the safenet Excel crypto accelerators. ++ Currently tested and working on the 1141 and 1741. ++ ++config OCF_IXP4XX ++ tristate "IXP4xx (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ XScale IXP4xx crypto accelerator driver. Requires the ++ Intel Access library. ++ ++config OCF_IXP4XX_SHA1_MD5 ++ bool "IXP4xx SHA1 and MD5 Hashing" ++ depends on OCF_IXP4XX ++ help ++ Allows the IXP4xx crypto accelerator to perform SHA1 and MD5 hashing. ++ Note: this is MUCH slower than using cryptosoft (software crypto engine). ++ ++config OCF_HIFN ++ tristate "hifn (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for various HIFN based crypto accelerators. ++ (7951, 7955, 7956, 7751, 7811) ++ ++config OCF_HIFNHIPP ++ tristate "Hifn HIPP (HW packet crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for various HIFN (HIPP) based crypto accelerators ++ (7855) ++ ++config OCF_TALITOS ++ tristate "talitos (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for Freescale's security engine (SEC/talitos). ++ ++config OCF_PASEMI ++ tristate "pasemi (HW crypto engine)" ++ depends on OCF_OCF && PPC_PASEMI ++ help ++ OCF driver for the PA Semi PWRficient DMA Engine ++ ++config OCF_EP80579 ++ tristate "ep80579 (HW crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for the Intel EP80579 Integrated Processor Product Line. ++ ++config OCF_OCFNULL ++ tristate "ocfnull (fake crypto engine)" ++ depends on OCF_OCF ++ help ++ OCF driver for measuring ipsec overheads (does no crypto) ++ ++config OCF_BENCH ++ tristate "ocf-bench (HW crypto in-kernel benchmark)" ++ depends on OCF_OCF ++ help ++ A very simple encryption test for the in-kernel interface ++ of OCF. Also includes code to benchmark the IXP Access library ++ for comparison. ++ ++endmenu +diff -Nur linux-2.6.30.orig/crypto/ocf/Makefile linux-2.6.30/crypto/ocf/Makefile +--- linux-2.6.30.orig/crypto/ocf/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,121 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++OCF_OBJS = crypto.o criov.o ++ ++ifdef CONFIG_OCF_RANDOMHARVEST ++ OCF_OBJS += random.o ++endif ++ ++ifdef CONFIG_OCF_FIPS ++ OCF_OBJS += rndtest.o ++endif ++ ++# Add in autoconf.h to get #defines for CONFIG_xxx ++AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h ++ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H))) ++ EXTRA_CFLAGS += -include $(AUTOCONF_H) ++ export EXTRA_CFLAGS ++endif ++ ++ifndef obj ++ obj ?= . ++ _obj = subdir ++ mod-subdirs := safe hifn ixp4xx talitos ocfnull ++ export-objs += crypto.o criov.o random.o ++ list-multi += ocf.o ++ _slash := ++else ++ _obj = obj ++ _slash := / ++endif ++ ++EXTRA_CFLAGS += -I$(obj)/. ++ ++obj-$(CONFIG_OCF_OCF) += ocf.o ++obj-$(CONFIG_OCF_CRYPTODEV) += cryptodev.o ++obj-$(CONFIG_OCF_CRYPTOSOFT) += cryptosoft.o ++obj-$(CONFIG_OCF_BENCH) += ocf-bench.o ++ ++$(_obj)-$(CONFIG_OCF_SAFE) += safe$(_slash) ++$(_obj)-$(CONFIG_OCF_HIFN) += hifn$(_slash) ++$(_obj)-$(CONFIG_OCF_IXP4XX) += ixp4xx$(_slash) ++$(_obj)-$(CONFIG_OCF_TALITOS) += talitos$(_slash) ++$(_obj)-$(CONFIG_OCF_PASEMI) += pasemi$(_slash) ++$(_obj)-$(CONFIG_OCF_EP80579) += ep80579$(_slash) ++$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash) ++ ++ocf-objs := $(OCF_OBJS) ++ ++$(list-multi) dummy1: $(ocf-objs) ++ $(LD) -r -o $@ $(ocf-objs) ++ ++.PHONY: ++clean: ++ rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c ++ rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ ++# ++# release gen targets ++# ++ ++.PHONY: patch ++patch: ++ REL=`date +%Y%m%d`; \ ++ patch=ocf-linux-$$REL.patch; \ ++ patch24=ocf-linux-24-$$REL.patch; \ ++ patch26=ocf-linux-26-$$REL.patch; \ ++ ( \ ++ find . -name Makefile; \ ++ find . -name Config.in; \ ++ find . -name Kconfig; \ ++ find . -name README; \ ++ find . -name '*.[ch]' | grep -v '.mod.c'; \ ++ ) | while read t; do \ ++ diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \ ++ done > $$patch; \ ++ cat patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \ ++ cat patches/linux-2.6.26-ocf.patch $$patch > $$patch26 ++ ++.PHONY: tarball ++tarball: ++ REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \ ++ CURDIR=`pwd`; \ ++ rm -rf /tmp/ocf-linux-$$REL*; \ ++ mkdir -p $$RELDIR/tools; \ ++ cp README* $$RELDIR; \ ++ cp patches/openss*.patch $$RELDIR; \ ++ cp patches/crypto-tools.patch $$RELDIR; \ ++ cp tools/[!C]* $$RELDIR/tools; \ ++ cd ..; \ ++ tar cvf $$RELDIR/ocf-linux.tar \ ++ --exclude=CVS \ ++ --exclude=.* \ ++ --exclude=*.o \ ++ --exclude=*.ko \ ++ --exclude=*.mod.* \ ++ --exclude=README* \ ++ --exclude=ocf-*.patch \ ++ --exclude=ocf/patches/openss*.patch \ ++ --exclude=ocf/patches/crypto-tools.patch \ ++ --exclude=ocf/tools \ ++ ocf; \ ++ gzip -9 $$RELDIR/ocf-linux.tar; \ ++ cd /tmp; \ ++ tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \ ++ gzip -9 ocf-linux-$$REL.tar; \ ++ cd $$CURDIR/../../user; \ ++ rm -rf /tmp/crypto-tools-$$REL*; \ ++ tar cvf /tmp/crypto-tools-$$REL.tar \ ++ --exclude=CVS \ ++ --exclude=.* \ ++ --exclude=*.o \ ++ --exclude=cryptotest \ ++ --exclude=cryptokeytest \ ++ crypto-tools; \ ++ gzip -9 /tmp/crypto-tools-$$REL.tar ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocf-bench.c linux-2.6.30/crypto/ocf/ocf-bench.c +--- linux-2.6.30.orig/crypto/ocf/ocf-bench.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocf-bench.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,436 @@ ++/* ++ * A loadable module that benchmarks the OCF crypto speed from kernel space. ++ * ++ * Copyright (C) 2004-2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef I_HAVE_AN_XSCALE_WITH_INTEL_SDK ++#define BENCH_IXP_ACCESS_LIB 1 ++#endif ++#ifdef BENCH_IXP_ACCESS_LIB ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* ++ * support for access lib version 1.4 ++ */ ++#ifndef IX_MBUF_PRIV ++#define IX_MBUF_PRIV(x) ((x)->priv) ++#endif ++ ++/* ++ * the number of simultaneously active requests ++ */ ++static int request_q_len = 20; ++module_param(request_q_len, int, 0); ++MODULE_PARM_DESC(request_q_len, "Number of outstanding requests"); ++/* ++ * how many requests we want to have processed ++ */ ++static int request_num = 1024; ++module_param(request_num, int, 0); ++MODULE_PARM_DESC(request_num, "run for at least this many requests"); ++/* ++ * the size of each request ++ */ ++static int request_size = 1500; ++module_param(request_size, int, 0); ++MODULE_PARM_DESC(request_size, "size of each request"); ++ ++/* ++ * a structure for each request ++ */ ++typedef struct { ++ struct work_struct work; ++#ifdef BENCH_IXP_ACCESS_LIB ++ IX_MBUF mbuf; ++#endif ++ unsigned char *buffer; ++} request_t; ++ ++static request_t *requests; ++ ++static int outstanding; ++static int total; ++ ++/*************************************************************************/ ++/* ++ * OCF benchmark routines ++ */ ++ ++static uint64_t ocf_cryptoid; ++static int ocf_init(void); ++static int ocf_cb(struct cryptop *crp); ++static void ocf_request(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ocf_request_wq(struct work_struct *work); ++#endif ++ ++static int ++ocf_init(void) ++{ ++ int error; ++ struct cryptoini crie, cria; ++ struct cryptodesc crda, crde; ++ ++ memset(&crie, 0, sizeof(crie)); ++ memset(&cria, 0, sizeof(cria)); ++ memset(&crde, 0, sizeof(crde)); ++ memset(&crda, 0, sizeof(crda)); ++ ++ cria.cri_alg = CRYPTO_SHA1_HMAC; ++ cria.cri_klen = 20 * 8; ++ cria.cri_key = "0123456789abcdefghij"; ++ ++ crie.cri_alg = CRYPTO_3DES_CBC; ++ crie.cri_klen = 24 * 8; ++ crie.cri_key = "0123456789abcdefghijklmn"; ++ ++ crie.cri_next = &cria; ++ ++ error = crypto_newsession(&ocf_cryptoid, &crie, 0); ++ if (error) { ++ printk("crypto_newsession failed %d\n", error); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++ocf_cb(struct cryptop *crp) ++{ ++ request_t *r = (request_t *) crp->crp_opaque; ++ ++ if (crp->crp_etype) ++ printk("Error in OCF processing: %d\n", crp->crp_etype); ++ total++; ++ crypto_freereq(crp); ++ crp = NULL; ++ ++ if (total > request_num) { ++ outstanding--; ++ return 0; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&r->work, ocf_request_wq); ++#else ++ INIT_WORK(&r->work, ocf_request, r); ++#endif ++ schedule_work(&r->work); ++ return 0; ++} ++ ++ ++static void ++ocf_request(void *arg) ++{ ++ request_t *r = arg; ++ struct cryptop *crp = crypto_getreq(2); ++ struct cryptodesc *crde, *crda; ++ ++ if (!crp) { ++ outstanding--; ++ return; ++ } ++ ++ crde = crp->crp_desc; ++ crda = crde->crd_next; ++ ++ crda->crd_skip = 0; ++ crda->crd_flags = 0; ++ crda->crd_len = request_size; ++ crda->crd_inject = request_size; ++ crda->crd_alg = CRYPTO_SHA1_HMAC; ++ crda->crd_key = "0123456789abcdefghij"; ++ crda->crd_klen = 20 * 8; ++ ++ crde->crd_skip = 0; ++ crde->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_ENCRYPT; ++ crde->crd_len = request_size; ++ crde->crd_inject = request_size; ++ crde->crd_alg = CRYPTO_3DES_CBC; ++ crde->crd_key = "0123456789abcdefghijklmn"; ++ crde->crd_klen = 24 * 8; ++ ++ crp->crp_ilen = request_size + 64; ++ crp->crp_flags = CRYPTO_F_CBIMM; ++ crp->crp_buf = (caddr_t) r->buffer; ++ crp->crp_callback = ocf_cb; ++ crp->crp_sid = ocf_cryptoid; ++ crp->crp_opaque = (caddr_t) r; ++ crypto_dispatch(crp); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ocf_request_wq(struct work_struct *work) ++{ ++ request_t *r = container_of(work, request_t, work); ++ ocf_request(r); ++} ++#endif ++ ++/*************************************************************************/ ++#ifdef BENCH_IXP_ACCESS_LIB ++/*************************************************************************/ ++/* ++ * CryptoAcc benchmark routines ++ */ ++ ++static IxCryptoAccCtx ixp_ctx; ++static UINT32 ixp_ctx_id; ++static IX_MBUF ixp_pri; ++static IX_MBUF ixp_sec; ++static int ixp_registered = 0; ++ ++static void ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, ++ IxCryptoAccStatus status); ++static void ixp_perform_cb(UINT32 ctx_id, IX_MBUF *sbufp, IX_MBUF *dbufp, ++ IxCryptoAccStatus status); ++static void ixp_request(void *arg); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ixp_request_wq(struct work_struct *work); ++#endif ++ ++static int ++ixp_init(void) ++{ ++ IxCryptoAccStatus status; ++ ++ ixp_ctx.cipherCtx.cipherAlgo = IX_CRYPTO_ACC_CIPHER_3DES; ++ ixp_ctx.cipherCtx.cipherMode = IX_CRYPTO_ACC_MODE_CBC; ++ ixp_ctx.cipherCtx.cipherKeyLen = 24; ++ ixp_ctx.cipherCtx.cipherBlockLen = IX_CRYPTO_ACC_DES_BLOCK_64; ++ ixp_ctx.cipherCtx.cipherInitialVectorLen = IX_CRYPTO_ACC_DES_IV_64; ++ memcpy(ixp_ctx.cipherCtx.key.cipherKey, "0123456789abcdefghijklmn", 24); ++ ++ ixp_ctx.authCtx.authAlgo = IX_CRYPTO_ACC_AUTH_SHA1; ++ ixp_ctx.authCtx.authDigestLen = 12; ++ ixp_ctx.authCtx.aadLen = 0; ++ ixp_ctx.authCtx.authKeyLen = 20; ++ memcpy(ixp_ctx.authCtx.key.authKey, "0123456789abcdefghij", 20); ++ ++ ixp_ctx.useDifferentSrcAndDestMbufs = 0; ++ ixp_ctx.operation = IX_CRYPTO_ACC_OP_ENCRYPT_AUTH ; ++ ++ IX_MBUF_MLEN(&ixp_pri) = IX_MBUF_PKT_LEN(&ixp_pri) = 128; ++ IX_MBUF_MDATA(&ixp_pri) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ IX_MBUF_MLEN(&ixp_sec) = IX_MBUF_PKT_LEN(&ixp_sec) = 128; ++ IX_MBUF_MDATA(&ixp_sec) = (unsigned char *) kmalloc(128, SLAB_ATOMIC); ++ ++ status = ixCryptoAccCtxRegister(&ixp_ctx, &ixp_pri, &ixp_sec, ++ ixp_register_cb, ixp_perform_cb, &ixp_ctx_id); ++ ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) { ++ while (!ixp_registered) ++ schedule(); ++ return ixp_registered < 0 ? -1 : 0; ++ } ++ ++ printk("ixp: ixCryptoAccCtxRegister failed %d\n", status); ++ return -1; ++} ++ ++static void ++ixp_register_cb(UINT32 ctx_id, IX_MBUF *bufp, IxCryptoAccStatus status) ++{ ++ if (bufp) { ++ IX_MBUF_MLEN(bufp) = IX_MBUF_PKT_LEN(bufp) = 0; ++ kfree(IX_MBUF_MDATA(bufp)); ++ IX_MBUF_MDATA(bufp) = NULL; ++ } ++ ++ if (IX_CRYPTO_ACC_STATUS_WAIT == status) ++ return; ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS == status) ++ ixp_registered = 1; ++ else ++ ixp_registered = -1; ++} ++ ++static void ++ixp_perform_cb( ++ UINT32 ctx_id, ++ IX_MBUF *sbufp, ++ IX_MBUF *dbufp, ++ IxCryptoAccStatus status) ++{ ++ request_t *r = NULL; ++ ++ total++; ++ if (total > request_num) { ++ outstanding--; ++ return; ++ } ++ ++ if (!sbufp || !(r = IX_MBUF_PRIV(sbufp))) { ++ printk("crappo %p %p\n", sbufp, r); ++ outstanding--; ++ return; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_WORK(&r->work, ixp_request_wq); ++#else ++ INIT_WORK(&r->work, ixp_request, r); ++#endif ++ schedule_work(&r->work); ++} ++ ++static void ++ixp_request(void *arg) ++{ ++ request_t *r = arg; ++ IxCryptoAccStatus status; ++ ++ memset(&r->mbuf, 0, sizeof(r->mbuf)); ++ IX_MBUF_MLEN(&r->mbuf) = IX_MBUF_PKT_LEN(&r->mbuf) = request_size + 64; ++ IX_MBUF_MDATA(&r->mbuf) = r->buffer; ++ IX_MBUF_PRIV(&r->mbuf) = r; ++ status = ixCryptoAccAuthCryptPerform(ixp_ctx_id, &r->mbuf, NULL, ++ 0, request_size, 0, request_size, request_size, r->buffer); ++ if (IX_CRYPTO_ACC_STATUS_SUCCESS != status) { ++ printk("status1 = %d\n", status); ++ outstanding--; ++ return; ++ } ++ return; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++static void ++ixp_request_wq(struct work_struct *work) ++{ ++ request_t *r = container_of(work, request_t, work); ++ ixp_request(r); ++} ++#endif ++ ++/*************************************************************************/ ++#endif /* BENCH_IXP_ACCESS_LIB */ ++/*************************************************************************/ ++ ++int ++ocfbench_init(void) ++{ ++ int i, jstart, jstop; ++ ++ printk("Crypto Speed tests\n"); ++ ++ requests = kmalloc(sizeof(request_t) * request_q_len, GFP_KERNEL); ++ if (!requests) { ++ printk("malloc failed\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < request_q_len; i++) { ++ /* +64 for return data */ ++ requests[i].buffer = kmalloc(request_size + 128, GFP_DMA); ++ if (!requests[i].buffer) { ++ printk("malloc failed\n"); ++ return -EINVAL; ++ } ++ memset(requests[i].buffer, '0' + i, request_size + 128); ++ } ++ ++ /* ++ * OCF benchmark ++ */ ++ printk("OCF: testing ...\n"); ++ ocf_init(); ++ total = outstanding = 0; ++ jstart = jiffies; ++ for (i = 0; i < request_q_len; i++) { ++ outstanding++; ++ ocf_request(&requests[i]); ++ } ++ while (outstanding > 0) ++ schedule(); ++ jstop = jiffies; ++ ++ printk("OCF: %d requests of %d bytes in %d jiffies\n", total, request_size, ++ jstop - jstart); ++ ++#ifdef BENCH_IXP_ACCESS_LIB ++ /* ++ * IXP benchmark ++ */ ++ printk("IXP: testing ...\n"); ++ ixp_init(); ++ total = outstanding = 0; ++ jstart = jiffies; ++ for (i = 0; i < request_q_len; i++) { ++ outstanding++; ++ ixp_request(&requests[i]); ++ } ++ while (outstanding > 0) ++ schedule(); ++ jstop = jiffies; ++ ++ printk("IXP: %d requests of %d bytes in %d jiffies\n", total, request_size, ++ jstop - jstart); ++#endif /* BENCH_IXP_ACCESS_LIB */ ++ ++ for (i = 0; i < request_q_len; i++) ++ kfree(requests[i].buffer); ++ kfree(requests); ++ return -EINVAL; /* always fail to load so it can be re-run quickly ;-) */ ++} ++ ++static void __exit ocfbench_exit(void) ++{ ++} ++ ++module_init(ocfbench_init); ++module_exit(ocfbench_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("Benchmark various in-kernel crypto speeds"); +diff -Nur linux-2.6.30.orig/crypto/ocf/ocf-compat.h linux-2.6.30/crypto/ocf/ocf-compat.h +--- linux-2.6.30.orig/crypto/ocf/ocf-compat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocf-compat.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,270 @@ ++#ifndef _BSD_COMPAT_H_ ++#define _BSD_COMPAT_H_ 1 ++/****************************************************************************/ ++/* ++ * Provide compat routines for older linux kernels and BSD kernels ++ * ++ * Written by David McCullough ++ * Copyright (C) 2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this file ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++/****************************************************************************/ ++#ifdef __KERNEL__ ++/* ++ * fake some BSD driver interface stuff specifically for OCF use ++ */ ++ ++typedef struct ocf_device *device_t; ++ ++typedef struct { ++ int (*cryptodev_newsession)(device_t dev, u_int32_t *sidp, struct cryptoini *cri); ++ int (*cryptodev_freesession)(device_t dev, u_int64_t tid); ++ int (*cryptodev_process)(device_t dev, struct cryptop *crp, int hint); ++ int (*cryptodev_kprocess)(device_t dev, struct cryptkop *krp, int hint); ++} device_method_t; ++#define DEVMETHOD(id, func) id: func ++ ++struct ocf_device { ++ char name[32]; /* the driver name */ ++ char nameunit[32]; /* the driver name + HW instance */ ++ int unit; ++ device_method_t methods; ++ void *softc; ++}; ++ ++#define CRYPTODEV_NEWSESSION(dev, sid, cri) \ ++ ((*(dev)->methods.cryptodev_newsession)(dev,sid,cri)) ++#define CRYPTODEV_FREESESSION(dev, sid) \ ++ ((*(dev)->methods.cryptodev_freesession)(dev, sid)) ++#define CRYPTODEV_PROCESS(dev, crp, hint) \ ++ ((*(dev)->methods.cryptodev_process)(dev, crp, hint)) ++#define CRYPTODEV_KPROCESS(dev, krp, hint) \ ++ ((*(dev)->methods.cryptodev_kprocess)(dev, krp, hint)) ++ ++#define device_get_name(dev) ((dev)->name) ++#define device_get_nameunit(dev) ((dev)->nameunit) ++#define device_get_unit(dev) ((dev)->unit) ++#define device_get_softc(dev) ((dev)->softc) ++ ++#define softc_device_decl \ ++ struct ocf_device _device; \ ++ device_t ++ ++#define softc_device_init(_sc, _name, _unit, _methods) \ ++ if (1) {\ ++ strncpy((_sc)->_device.name, _name, sizeof((_sc)->_device.name) - 1); \ ++ snprintf((_sc)->_device.nameunit, sizeof((_sc)->_device.name), "%s%d", _name, _unit); \ ++ (_sc)->_device.unit = _unit; \ ++ (_sc)->_device.methods = _methods; \ ++ (_sc)->_device.softc = (void *) _sc; \ ++ *(device_t *)((softc_get_device(_sc))+1) = &(_sc)->_device; \ ++ } else ++ ++#define softc_get_device(_sc) (&(_sc)->_device) ++ ++/* ++ * iomem support for 2.4 and 2.6 kernels ++ */ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define ocf_iomem_t unsigned long ++ ++/* ++ * implement simple workqueue like support for older kernels ++ */ ++ ++#include ++ ++#define work_struct tq_struct ++ ++#define INIT_WORK(wp, fp, ap) \ ++ do { \ ++ (wp)->sync = 0; \ ++ (wp)->routine = (fp); \ ++ (wp)->data = (ap); \ ++ } while (0) ++ ++#define schedule_work(wp) \ ++ do { \ ++ queue_task((wp), &tq_immediate); \ ++ mark_bh(IMMEDIATE_BH); \ ++ } while (0) ++ ++#define flush_scheduled_work() run_task_queue(&tq_immediate) ++ ++#else ++#define ocf_iomem_t void __iomem * ++ ++#include ++ ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ++#define files_fdtable(files) (files) ++#endif ++ ++#ifdef MODULE_PARM ++#undef module_param /* just in case */ ++#define module_param(a,b,c) MODULE_PARM(a,"i") ++#endif ++ ++#define bzero(s,l) memset(s,0,l) ++#define bcopy(s,d,l) memcpy(d,s,l) ++#define bcmp(x, y, l) memcmp(x,y,l) ++ ++#define MIN(x,y) ((x) < (y) ? (x) : (y)) ++ ++#define device_printf(dev, a...) ({ \ ++ printk("%s: ", device_get_nameunit(dev)); printk(a); \ ++ }) ++ ++#undef printf ++#define printf(fmt...) printk(fmt) ++ ++#define KASSERT(c,p) if (!(c)) { printk p ; } else ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define ocf_daemonize(str) \ ++ daemonize(); \ ++ spin_lock_irq(¤t->sigmask_lock); \ ++ sigemptyset(¤t->blocked); \ ++ recalc_sigpending(current); \ ++ spin_unlock_irq(¤t->sigmask_lock); \ ++ sprintf(current->comm, str); ++#else ++#define ocf_daemonize(str) daemonize(str); ++#endif ++ ++#define TAILQ_INSERT_TAIL(q,d,m) list_add_tail(&(d)->m, (q)) ++#define TAILQ_EMPTY(q) list_empty(q) ++#define TAILQ_FOREACH(v, q, m) list_for_each_entry(v, q, m) ++ ++#define read_random(p,l) get_random_bytes(p,l) ++ ++#define DELAY(x) ((x) > 2000 ? mdelay((x)/1000) : udelay(x)) ++#define strtoul simple_strtoul ++ ++#define pci_get_vendor(dev) ((dev)->vendor) ++#define pci_get_device(dev) ((dev)->device) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#define pci_set_consistent_dma_mask(dev, mask) (0) ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ++#define pci_dma_sync_single_for_cpu pci_dma_sync_single ++#endif ++ ++#ifndef DMA_32BIT_MASK ++#define DMA_32BIT_MASK 0x00000000ffffffffULL ++#endif ++ ++#define htole32(x) cpu_to_le32(x) ++#define htobe32(x) cpu_to_be32(x) ++#define htole16(x) cpu_to_le16(x) ++#define htobe16(x) cpu_to_be16(x) ++ ++/* older kernels don't have these */ ++ ++#ifndef IRQ_NONE ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define irqreturn_t void ++#endif ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++# define strlcpy(dest,src,len) \ ++ ({strncpy(dest,src,(len)-1); ((char *)dest)[(len)-1] = '\0'; }) ++#endif ++ ++#ifndef MAX_ERRNO ++#define MAX_ERRNO 4095 ++#endif ++#ifndef IS_ERR_VALUE ++#define IS_ERR_VALUE(x) ((unsigned long)(x) >= (unsigned long)-MAX_ERRNO) ++#endif ++ ++/* ++ * common debug for all ++ */ ++#if 1 ++#define dprintk(a...) do { if (debug) printk(a); } while(0) ++#else ++#define dprintk(a...) ++#endif ++ ++#ifndef SLAB_ATOMIC ++/* Changed in 2.6.20, must use GFP_ATOMIC now */ ++#define SLAB_ATOMIC GFP_ATOMIC ++#endif ++ ++/* ++ * need some additional support for older kernels */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,2) ++#define pci_register_driver_compat(driver, rc) \ ++ do { \ ++ if ((rc) > 0) { \ ++ (rc) = 0; \ ++ } else if (rc == 0) { \ ++ (rc) = -ENODEV; \ ++ } else { \ ++ pci_unregister_driver(driver); \ ++ } \ ++ } while (0) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ++#define pci_register_driver_compat(driver,rc) ((rc) = (rc) < 0 ? (rc) : 0) ++#else ++#define pci_register_driver_compat(driver,rc) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ ++#include ++ ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, ++ unsigned int len, unsigned int offset) ++{ ++ sg->page = page; ++ sg->offset = offset; ++ sg->length = len; ++} ++ ++static inline void *sg_virt(struct scatterlist *sg) ++{ ++ return page_address(sg->page) + sg->offset; ++} ++ ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++/****************************************************************************/ ++#endif /* _BSD_COMPAT_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocfnull/Makefile linux-2.6.30/crypto/ocf/ocfnull/Makefile +--- linux-2.6.30.orig/crypto/ocf/ocfnull/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocfnull/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_OCFNULL) += ocfnull.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/ocfnull/ocfnull.c linux-2.6.30/crypto/ocf/ocfnull/ocfnull.c +--- linux-2.6.30.orig/crypto/ocf/ocfnull/ocfnull.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/ocfnull/ocfnull.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ * An OCF module for determining the cost of crypto versus the cost of ++ * IPSec processing outside of OCF. This modules gives us the effect of ++ * zero cost encryption, of course you will need to run it at both ends ++ * since it does no crypto at all. ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static int32_t null_id = -1; ++static u_int32_t null_sesnum = 0; ++ ++static int null_process(device_t, struct cryptop *, int); ++static int null_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int null_freesession(device_t, u_int64_t); ++ ++#define debug ocfnull_debug ++int ocfnull_debug = 0; ++module_param(ocfnull_debug, int, 0644); ++MODULE_PARM_DESC(ocfnull_debug, "Enable debug"); ++ ++/* ++ * dummy device structure ++ */ ++ ++static struct { ++ softc_device_decl sc_dev; ++} nulldev; ++ ++static device_method_t null_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, null_newsession), ++ DEVMETHOD(cryptodev_freesession,null_freesession), ++ DEVMETHOD(cryptodev_process, null_process), ++}; ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++null_newsession(device_t arg, u_int32_t *sid, struct cryptoini *cri) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid == NULL || cri == NULL) { ++ dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ if (null_sesnum == 0) ++ null_sesnum++; ++ *sid = null_sesnum++; ++ return 0; ++} ++ ++ ++/* ++ * Free a session. ++ */ ++static int ++null_freesession(device_t arg, u_int64_t tid) ++{ ++ u_int32_t sid = CRYPTO_SESID2LID(tid); ++ ++ dprintk("%s()\n", __FUNCTION__); ++ if (sid > null_sesnum) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ /* Silently accept and return */ ++ if (sid == 0) ++ return 0; ++ return 0; ++} ++ ++ ++/* ++ * Process a request. ++ */ ++static int ++null_process(device_t arg, struct cryptop *crp, int hint) ++{ ++ unsigned int lid; ++ ++ dprintk("%s()\n", __FUNCTION__); ++ ++ /* Sanity check */ ++ if (crp == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ ++ crp->crp_etype = 0; ++ ++ if (crp->crp_desc == NULL || crp->crp_buf == NULL) { ++ dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__); ++ crp->crp_etype = EINVAL; ++ goto done; ++ } ++ ++ /* ++ * find the session we are using ++ */ ++ ++ lid = crp->crp_sid & 0xffffffff; ++ if (lid >= null_sesnum || lid == 0) { ++ crp->crp_etype = ENOENT; ++ dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__); ++ goto done; ++ } ++ ++done: ++ crypto_done(crp); ++ return 0; ++} ++ ++ ++/* ++ * our driver startup and shutdown routines ++ */ ++ ++static int ++null_init(void) ++{ ++ dprintk("%s(%p)\n", __FUNCTION__, null_init); ++ ++ memset(&nulldev, 0, sizeof(nulldev)); ++ softc_device_init(&nulldev, "ocfnull", 0, null_methods); ++ ++ null_id = crypto_get_driverid(softc_get_device(&nulldev), ++ CRYPTOCAP_F_HARDWARE); ++ if (null_id < 0) ++ panic("ocfnull: crypto device cannot initialize!"); ++ ++#define REGISTER(alg) \ ++ crypto_register(null_id,alg,0,0) ++ REGISTER(CRYPTO_DES_CBC); ++ REGISTER(CRYPTO_3DES_CBC); ++ REGISTER(CRYPTO_RIJNDAEL128_CBC); ++ REGISTER(CRYPTO_MD5); ++ REGISTER(CRYPTO_SHA1); ++ REGISTER(CRYPTO_MD5_HMAC); ++ REGISTER(CRYPTO_SHA1_HMAC); ++#undef REGISTER ++ ++ return 0; ++} ++ ++static void ++null_exit(void) ++{ ++ dprintk("%s()\n", __FUNCTION__); ++ crypto_unregister_all(null_id); ++ null_id = -1; ++} ++ ++module_init(null_init); ++module_exit(null_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("ocfnull - claims a lot but does nothing"); +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/Makefile linux-2.6.30/crypto/ocf/pasemi/Makefile +--- linux-2.6.30.orig/crypto/ocf/pasemi/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_PASEMI) += pasemi.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/pasemi.c linux-2.6.30/crypto/ocf/pasemi/pasemi.c +--- linux-2.6.30.orig/crypto/ocf/pasemi/pasemi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/pasemi.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1009 @@ ++/* ++ * Copyright (C) 2007 PA Semi, Inc ++ * ++ * Driver for the PA Semi PWRficient DMA Crypto Engine ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * 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 AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pasemi_fnu.h" ++ ++#define DRV_NAME "pasemi" ++ ++#define TIMER_INTERVAL 1000 ++ ++static void __devexit pasemi_dma_remove(struct pci_dev *pdev); ++static struct pasdma_status volatile * dma_status; ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Enable debug"); ++ ++static void pasemi_desc_start(struct pasemi_desc *desc, u64 hdr) ++{ ++ desc->postop = 0; ++ desc->quad[0] = hdr; ++ desc->quad_cnt = 1; ++ desc->size = 1; ++} ++ ++static void pasemi_desc_build(struct pasemi_desc *desc, u64 val) ++{ ++ desc->quad[desc->quad_cnt++] = val; ++ desc->size = (desc->quad_cnt + 1) / 2; ++} ++ ++static void pasemi_desc_hdr(struct pasemi_desc *desc, u64 hdr) ++{ ++ desc->quad[0] |= hdr; ++} ++ ++static int pasemi_desc_size(struct pasemi_desc *desc) ++{ ++ return desc->size; ++} ++ ++static void pasemi_ring_add_desc( ++ struct pasemi_fnu_txring *ring, ++ struct pasemi_desc *desc, ++ struct cryptop *crp) { ++ int i; ++ int ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); ++ ++ TX_DESC_INFO(ring, ring->next_to_fill).desc_size = desc->size; ++ TX_DESC_INFO(ring, ring->next_to_fill).desc_postop = desc->postop; ++ TX_DESC_INFO(ring, ring->next_to_fill).cf_crp = crp; ++ ++ for (i = 0; i < desc->quad_cnt; i += 2) { ++ ring_index = 2 * (ring->next_to_fill & (TX_RING_SIZE-1)); ++ ring->desc[ring_index] = desc->quad[i]; ++ ring->desc[ring_index + 1] = desc->quad[i + 1]; ++ ring->next_to_fill++; ++ } ++ ++ if (desc->quad_cnt & 1) ++ ring->desc[ring_index + 1] = 0; ++} ++ ++static void pasemi_ring_incr(struct pasemi_softc *sc, int chan_index, int incr) ++{ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_INCR(sc->base_chan + chan_index), ++ incr); ++} ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++pasemi_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct pasemi_softc *sc = device_get_softc(dev); ++ struct pasemi_session *ses = NULL, **sespp; ++ int sesn, blksz = 0; ++ u64 ccmd = 0; ++ unsigned long flags; ++ struct pasemi_desc init_desc; ++ struct pasemi_fnu_txring *txring; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return -EINVAL; ++ } ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (ALG_IS_SIG(c->cri_alg)) { ++ if (macini) ++ return -EINVAL; ++ macini = c; ++ } else if (ALG_IS_CIPHER(c->cri_alg)) { ++ if (encini) ++ return -EINVAL; ++ encini = c; ++ } else { ++ DPRINTF("UNKNOWN c->cri_alg %d\n", c->cri_alg); ++ return -EINVAL; ++ } ++ } ++ if (encini == NULL && macini == NULL) ++ return -EINVAL; ++ if (encini) { ++ /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return -EINVAL; ++ ccmd = DMA_CALGO_DES; ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) ++ return -EINVAL; ++ ccmd = DMA_CALGO_3DES; ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return -EINVAL; ++ ccmd = DMA_CALGO_AES; ++ break; ++ case CRYPTO_ARC4: ++ if (encini->cri_klen != 128) ++ return -EINVAL; ++ ccmd = DMA_CALGO_ARC; ++ break; ++ default: ++ DPRINTF("UNKNOWN encini->cri_alg %d\n", ++ encini->cri_alg); ++ return -EINVAL; ++ } ++ } ++ ++ if (macini) { ++ switch (macini->cri_alg) { ++ case CRYPTO_MD5: ++ case CRYPTO_MD5_HMAC: ++ blksz = 16; ++ break; ++ case CRYPTO_SHA1: ++ case CRYPTO_SHA1_HMAC: ++ blksz = 20; ++ break; ++ default: ++ DPRINTF("UNKNOWN macini->cri_alg %d\n", ++ macini->cri_alg); ++ return -EINVAL; ++ } ++ if (((macini->cri_klen + 7) / 8) > blksz) { ++ DPRINTF("key length %d bigger than blksize %d not supported\n", ++ ((macini->cri_klen + 7) / 8), blksz); ++ return -EINVAL; ++ } ++ } ++ ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn] == NULL) { ++ sc->sc_sessions[sesn] = (struct pasemi_session *) ++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); ++ ses = sc->sc_sessions[sesn]; ++ break; ++ } else if (sc->sc_sessions[sesn]->used == 0) { ++ ses = sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sespp = (struct pasemi_session **) ++ kzalloc(sc->sc_nsessions * 2 * ++ sizeof(struct pasemi_session *), GFP_ATOMIC); ++ if (sespp == NULL) ++ return -ENOMEM; ++ memcpy(sespp, sc->sc_sessions, ++ sc->sc_nsessions * sizeof(struct pasemi_session *)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = sespp; ++ sesn = sc->sc_nsessions; ++ ses = sc->sc_sessions[sesn] = (struct pasemi_session *) ++ kzalloc(sizeof(struct pasemi_session), GFP_ATOMIC); ++ if (ses == NULL) ++ return -ENOMEM; ++ sc->sc_nsessions *= 2; ++ } ++ ++ ses->used = 1; ++ ++ ses->dma_addr = pci_map_single(sc->dma_pdev, (void *) ses->civ, ++ sizeof(struct pasemi_session), DMA_TO_DEVICE); ++ ++ /* enter the channel scheduler */ ++ spin_lock_irqsave(&sc->sc_chnlock, flags); ++ ++ /* ARC4 has to be processed by the even channel */ ++ if (encini && (encini->cri_alg == CRYPTO_ARC4)) ++ ses->chan = sc->sc_lastchn & ~1; ++ else ++ ses->chan = sc->sc_lastchn; ++ sc->sc_lastchn = (sc->sc_lastchn + 1) % sc->sc_num_channels; ++ ++ spin_unlock_irqrestore(&sc->sc_chnlock, flags); ++ ++ txring = &sc->tx[ses->chan]; ++ ++ if (encini) { ++ ses->ccmd = ccmd; ++ ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ get_random_bytes(ses->civ, sizeof(ses->civ)); ++ ++ ses->keysz = (encini->cri_klen - 63) / 64; ++ memcpy(ses->key, encini->cri_key, (ses->keysz + 1) * 8); ++ ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(ses->chan, (encini && macini) ? 0x68 : 0x40, DMA_FN_CIV0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR((encini && macini) ? 0x68 : 0x40, ses->dma_addr)); ++ } ++ if (macini) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC || ++ macini->cri_alg == CRYPTO_SHA1_HMAC) ++ memcpy(ses->hkey, macini->cri_key, blksz); ++ else { ++ /* Load initialization constants(RFC 1321, 3174) */ ++ ses->hiv[0] = 0x67452301efcdab89ULL; ++ ses->hiv[1] = 0x98badcfe10325476ULL; ++ ses->hiv[2] = 0xc3d2e1f000000000ULL; ++ } ++ ses->hseq = 0ULL; ++ } ++ ++ spin_lock_irqsave(&txring->fill_lock, flags); ++ ++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc)) - ++ txring->next_to_clean) > TX_RING_SIZE) { ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ return ERESTART; ++ } ++ ++ if (encini) { ++ pasemi_ring_add_desc(txring, &init_desc, NULL); ++ pasemi_ring_incr(sc, ses->chan, ++ pasemi_desc_size(&init_desc)); ++ } ++ ++ txring->sesn = sesn; ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ ++ *sidp = PASEMI_SID(sesn); ++ return 0; ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++pasemi_freesession(device_t dev, u_int64_t tid) ++{ ++ struct pasemi_softc *sc = device_get_softc(dev); ++ int session; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (sc == NULL) ++ return -EINVAL; ++ session = PASEMI_SESSION(sid); ++ if (session >= sc->sc_nsessions || !sc->sc_sessions[session]) ++ return -EINVAL; ++ ++ pci_unmap_single(sc->dma_pdev, ++ sc->sc_sessions[session]->dma_addr, ++ sizeof(struct pasemi_session), DMA_TO_DEVICE); ++ memset(sc->sc_sessions[session], 0, ++ sizeof(struct pasemi_session)); ++ ++ return 0; ++} ++ ++static int ++pasemi_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ ++ int err = 0, ivsize, srclen = 0, reinit = 0, reinit_size = 0, chsel; ++ struct pasemi_softc *sc = device_get_softc(dev); ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ caddr_t ivp; ++ struct pasemi_desc init_desc, work_desc; ++ struct pasemi_session *ses; ++ struct sk_buff *skb; ++ struct uio *uiop; ++ unsigned long flags; ++ struct pasemi_fnu_txring *txring; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) ++ return -EINVAL; ++ ++ crp->crp_etype = 0; ++ if (PASEMI_SESSION(crp->crp_sid) >= sc->sc_nsessions) ++ return -EINVAL; ++ ++ ses = sc->sc_sessions[PASEMI_SESSION(crp->crp_sid)]; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ err = -EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ if (ALG_IS_SIG(crd1->crd_alg)) { ++ maccrd = crd1; ++ if (crd2 == NULL) ++ enccrd = NULL; ++ else if (ALG_IS_CIPHER(crd2->crd_alg) && ++ (crd2->crd_flags & CRD_F_ENCRYPT) == 0) ++ enccrd = crd2; ++ else ++ goto erralg; ++ } else if (ALG_IS_CIPHER(crd1->crd_alg)) { ++ enccrd = crd1; ++ if (crd2 == NULL) ++ maccrd = NULL; ++ else if (ALG_IS_SIG(crd2->crd_alg) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) ++ maccrd = crd2; ++ else ++ goto erralg; ++ } else ++ goto erralg; ++ ++ chsel = ses->chan; ++ ++ txring = &sc->tx[chsel]; ++ ++ if (enccrd && !maccrd) { ++ if (enccrd->crd_alg == CRYPTO_ARC4) ++ reinit = 1; ++ reinit_size = 0x40; ++ srclen = crp->crp_ilen; ++ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I ++ | XCT_FUN_FUN(chsel)); ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_ENC); ++ else ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CRM_DEC); ++ } else if (enccrd && maccrd) { ++ if (enccrd->crd_alg == CRYPTO_ARC4) ++ reinit = 1; ++ reinit_size = 0x68; ++ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ /* Encrypt -> Authenticate */ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_ENC_SIG ++ | XCT_FUN_A | XCT_FUN_FUN(chsel)); ++ srclen = maccrd->crd_skip + maccrd->crd_len; ++ } else { ++ /* Authenticate -> Decrypt */ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG_DEC ++ | XCT_FUN_24BRES | XCT_FUN_FUN(chsel)); ++ pasemi_desc_build(&work_desc, 0); ++ pasemi_desc_build(&work_desc, 0); ++ pasemi_desc_build(&work_desc, 0); ++ work_desc.postop = PASEMI_CHECK_SIG; ++ srclen = crp->crp_ilen; ++ } ++ ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SHL(maccrd->crd_skip / 4)); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_CHL(enccrd->crd_skip - maccrd->crd_skip)); ++ } else if (!enccrd && maccrd) { ++ srclen = maccrd->crd_len; ++ ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(chsel, 0x58, DMA_FN_HKEY0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR(0x58, ((struct pasemi_session *)ses->dma_addr)->hkey)); ++ ++ pasemi_desc_start(&work_desc, XCT_FUN_O | XCT_FUN_I | XCT_FUN_CRM_SIG ++ | XCT_FUN_A | XCT_FUN_FUN(chsel)); ++ } ++ ++ if (enccrd) { ++ switch (enccrd->crd_alg) { ++ case CRYPTO_3DES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_3DES | ++ XCT_FUN_BCM_CBC); ++ ivsize = sizeof(u64); ++ break; ++ case CRYPTO_DES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_DES | ++ XCT_FUN_BCM_CBC); ++ ivsize = sizeof(u64); ++ break; ++ case CRYPTO_AES_CBC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_AES | ++ XCT_FUN_BCM_CBC); ++ ivsize = 2 * sizeof(u64); ++ break; ++ case CRYPTO_ARC4: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_ALG_ARC); ++ ivsize = 0; ++ break; ++ default: ++ printk(DRV_NAME ": unimplemented enccrd->crd_alg %d\n", ++ enccrd->crd_alg); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ ivp = (ivsize == sizeof(u64)) ? (caddr_t) &ses->civ[1] : (caddr_t) &ses->civ[0]; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ memcpy(ivp, enccrd->crd_iv, ivsize); ++ /* If IV is not present in the buffer already, it has to be copied there */ ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ivp); ++ } else { ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ /* IV is provided expicitly in descriptor */ ++ memcpy(ivp, enccrd->crd_iv, ivsize); ++ else ++ /* IV is provided in the packet */ ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ++ ivp); ++ } ++ } ++ ++ if (maccrd) { ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_MD5 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_SHA1: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_SHA1 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_MD5_HMAC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_MD5 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ case CRYPTO_SHA1_HMAC: ++ pasemi_desc_hdr(&work_desc, XCT_FUN_SIG_HMAC_SHA1 | ++ XCT_FUN_HSZ((crp->crp_ilen - maccrd->crd_inject) / 4)); ++ break; ++ default: ++ printk(DRV_NAME ": unimplemented maccrd->crd_alg %d\n", ++ maccrd->crd_alg); ++ err = -EINVAL; ++ goto errout; ++ } ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ /* using SKB buffers */ ++ skb = (struct sk_buff *)crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ printk(DRV_NAME ": skb frags unimplemented\n"); ++ err = -EINVAL; ++ goto errout; ++ } ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(skb->len, pci_map_single( ++ sc->dma_pdev, skb->data, ++ skb->len, DMA_TO_DEVICE))); ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR( ++ srclen, pci_map_single( ++ sc->dma_pdev, skb->data, ++ srclen, DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* using IOV buffers */ ++ uiop = (struct uio *)crp->crp_buf; ++ if (uiop->uio_iovcnt > 1) { ++ printk(DRV_NAME ": iov frags unimplemented\n"); ++ err = -EINVAL; ++ goto errout; ++ } ++ ++ /* crp_olen is never set; always use crp_ilen */ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( ++ sc->dma_pdev, ++ uiop->uio_iov->iov_base, ++ crp->crp_ilen, DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR(srclen, pci_map_single( ++ sc->dma_pdev, ++ uiop->uio_iov->iov_base, ++ srclen, DMA_TO_DEVICE))); ++ } else { ++ /* using contig buffers */ ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_DST_PTR(crp->crp_ilen, pci_map_single( ++ sc->dma_pdev, ++ crp->crp_buf, ++ crp->crp_ilen, DMA_TO_DEVICE))); ++ pasemi_desc_build( ++ &work_desc, ++ XCT_FUN_SRC_PTR(srclen, pci_map_single( ++ sc->dma_pdev, ++ crp->crp_buf, srclen, ++ DMA_TO_DEVICE))); ++ pasemi_desc_hdr(&work_desc, XCT_FUN_LLEN(srclen)); ++ } ++ ++ spin_lock_irqsave(&txring->fill_lock, flags); ++ ++ if (txring->sesn != PASEMI_SESSION(crp->crp_sid)) { ++ txring->sesn = PASEMI_SESSION(crp->crp_sid); ++ reinit = 1; ++ } ++ ++ if (enccrd) { ++ pasemi_desc_start(&init_desc, ++ XCT_CTRL_HDR(chsel, reinit ? reinit_size : 0x10, DMA_FN_CIV0)); ++ pasemi_desc_build(&init_desc, ++ XCT_FUN_SRC_PTR(reinit ? reinit_size : 0x10, ses->dma_addr)); ++ } ++ ++ if (((txring->next_to_fill + pasemi_desc_size(&init_desc) + ++ pasemi_desc_size(&work_desc)) - ++ txring->next_to_clean) > TX_RING_SIZE) { ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ err = ERESTART; ++ goto errout; ++ } ++ ++ pasemi_ring_add_desc(txring, &init_desc, NULL); ++ pasemi_ring_add_desc(txring, &work_desc, crp); ++ ++ pasemi_ring_incr(sc, chsel, ++ pasemi_desc_size(&init_desc) + ++ pasemi_desc_size(&work_desc)); ++ ++ spin_unlock_irqrestore(&txring->fill_lock, flags); ++ ++ mod_timer(&txring->crypto_timer, jiffies + TIMER_INTERVAL); ++ ++ return 0; ++ ++erralg: ++ printk(DRV_NAME ": unsupported algorithm or algorithm order alg1 %d alg2 %d\n", ++ crd1->crd_alg, crd2->crd_alg); ++ err = -EINVAL; ++ ++errout: ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } ++ return err; ++} ++ ++static int pasemi_clean_tx(struct pasemi_softc *sc, int chan) ++{ ++ int i, j, ring_idx; ++ struct pasemi_fnu_txring *ring = &sc->tx[chan]; ++ u16 delta_cnt; ++ int flags, loops = 10; ++ int desc_size; ++ struct cryptop *crp; ++ ++ spin_lock_irqsave(&ring->clean_lock, flags); ++ ++ while ((delta_cnt = (dma_status->tx_sta[sc->base_chan + chan] ++ & PAS_STATUS_PCNT_M) - ring->total_pktcnt) ++ && loops--) { ++ ++ for (i = 0; i < delta_cnt; i++) { ++ desc_size = TX_DESC_INFO(ring, ring->next_to_clean).desc_size; ++ crp = TX_DESC_INFO(ring, ring->next_to_clean).cf_crp; ++ if (crp) { ++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); ++ if (TX_DESC_INFO(ring, ring->next_to_clean).desc_postop & PASEMI_CHECK_SIG) { ++ /* Need to make sure signature matched, ++ * if not - return error */ ++ if (!(ring->desc[ring_idx + 1] & (1ULL << 63))) ++ crp->crp_etype = -EINVAL; ++ } ++ crypto_done(TX_DESC_INFO(ring, ++ ring->next_to_clean).cf_crp); ++ TX_DESC_INFO(ring, ring->next_to_clean).cf_crp = NULL; ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx + 1]), ++ PCI_DMA_TODEVICE); ++ ++ ring->desc[ring_idx] = ring->desc[ring_idx + 1] = 0; ++ ++ ring->next_to_clean++; ++ for (j = 1; j < desc_size; j++) { ++ ring_idx = 2 * ++ (ring->next_to_clean & ++ (TX_RING_SIZE-1)); ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN(ring->desc[ring_idx]), ++ PCI_DMA_TODEVICE); ++ if (ring->desc[ring_idx + 1]) ++ pci_unmap_single( ++ sc->dma_pdev, ++ XCT_PTR_ADDR_LEN( ++ ring->desc[ ++ ring_idx + 1]), ++ PCI_DMA_TODEVICE); ++ ring->desc[ring_idx] = ++ ring->desc[ring_idx + 1] = 0; ++ ring->next_to_clean++; ++ } ++ } else { ++ for (j = 0; j < desc_size; j++) { ++ ring_idx = 2 * (ring->next_to_clean & (TX_RING_SIZE-1)); ++ ring->desc[ring_idx] = ++ ring->desc[ring_idx + 1] = 0; ++ ring->next_to_clean++; ++ } ++ } ++ } ++ ++ ring->total_pktcnt += delta_cnt; ++ } ++ spin_unlock_irqrestore(&ring->clean_lock, flags); ++ ++ return 0; ++} ++ ++static void sweepup_tx(struct pasemi_softc *sc) ++{ ++ int i; ++ ++ for (i = 0; i < sc->sc_num_channels; i++) ++ pasemi_clean_tx(sc, i); ++} ++ ++static irqreturn_t pasemi_intr(int irq, void *arg, struct pt_regs *regs) ++{ ++ struct pasemi_softc *sc = arg; ++ unsigned int reg; ++ int chan = irq - sc->base_irq; ++ int chan_index = sc->base_chan + chan; ++ u64 stat = dma_status->tx_sta[chan_index]; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (!(stat & PAS_STATUS_CAUSE_M)) ++ return IRQ_NONE; ++ ++ pasemi_clean_tx(sc, chan); ++ ++ stat = dma_status->tx_sta[chan_index]; ++ ++ reg = PAS_IOB_DMA_TXCH_RESET_PINTC | ++ PAS_IOB_DMA_TXCH_RESET_PCNT(sc->tx[chan].total_pktcnt); ++ ++ if (stat & PAS_STATUS_SOFT) ++ reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), reg); ++ ++ ++ return IRQ_HANDLED; ++} ++ ++static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan) ++{ ++ u32 val; ++ int chan_index = chan + sc->base_chan; ++ int ret; ++ struct pasemi_fnu_txring *ring; ++ ++ ring = &sc->tx[chan]; ++ ++ spin_lock_init(&ring->fill_lock); ++ spin_lock_init(&ring->clean_lock); ++ ++ ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) * ++ TX_RING_SIZE, GFP_KERNEL); ++ if (!ring->desc_info) ++ return -ENOMEM; ++ ++ /* Allocate descriptors */ ++ ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev, ++ TX_RING_SIZE * ++ 2 * sizeof(u64), ++ &ring->dma, GFP_KERNEL); ++ if (!ring->desc) ++ return -ENOMEM; ++ ++ memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64)); ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30); ++ ++ ring->total_pktcnt = 0; ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index), ++ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); ++ ++ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); ++ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val); ++ ++ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index), ++ PAS_DMA_TXCHAN_CFG_TY_FUNC | ++ PAS_DMA_TXCHAN_CFG_TATTR(chan) | ++ PAS_DMA_TXCHAN_CFG_WT(2)); ++ ++ /* enable tx channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ PAS_DMA_TXCHAN_TCMDSTA_EN); ++ ++ out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index), ++ PAS_IOB_DMA_TXCH_CFG_CNTTH(1000)); ++ ++ ring->next_to_fill = 0; ++ ring->next_to_clean = 0; ++ ++ snprintf(ring->irq_name, sizeof(ring->irq_name), ++ "%s%d", "crypto", chan); ++ ++ ring->irq = irq_create_mapping(NULL, sc->base_irq + chan); ++ ret = request_irq(ring->irq, (irq_handler_t) ++ pasemi_intr, IRQF_DISABLED, ring->irq_name, sc); ++ if (ret) { ++ printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n", ++ ring->irq, ret); ++ ring->irq = -1; ++ return ret; ++ } ++ ++ setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc); ++ ++ return 0; ++} ++ ++static device_method_t pasemi_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, pasemi_newsession), ++ DEVMETHOD(cryptodev_freesession, pasemi_freesession), ++ DEVMETHOD(cryptodev_process, pasemi_process), ++}; ++ ++/* Set up the crypto device structure, private data, ++ * and anything else we need before we start */ ++ ++static int __devinit ++pasemi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ struct pasemi_softc *sc; ++ int ret, i; ++ ++ DPRINTF(KERN_ERR "%s()\n", __FUNCTION__); ++ ++ sc = kzalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return -ENOMEM; ++ ++ softc_device_init(sc, DRV_NAME, 1, pasemi_methods); ++ ++ pci_set_drvdata(pdev, sc); ++ ++ spin_lock_init(&sc->sc_chnlock); ++ ++ sc->sc_sessions = (struct pasemi_session **) ++ kzalloc(PASEMI_INITIAL_SESSIONS * ++ sizeof(struct pasemi_session *), GFP_ATOMIC); ++ if (sc->sc_sessions == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ sc->sc_nsessions = PASEMI_INITIAL_SESSIONS; ++ sc->sc_lastchn = 0; ++ sc->base_irq = pdev->irq + 6; ++ sc->base_chan = 6; ++ sc->sc_cid = -1; ++ sc->dma_pdev = pdev; ++ ++ sc->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); ++ if (!sc->iob_pdev) { ++ dev_err(&pdev->dev, "Can't find I/O Bridge\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ /* This is hardcoded and ugly, but we have some firmware versions ++ * who don't provide the register space in the device tree. Luckily ++ * they are at well-known locations so we can just do the math here. ++ */ ++ sc->dma_regs = ++ ioremap(0xe0000000 + (sc->dma_pdev->devfn << 12), 0x2000); ++ sc->iob_regs = ++ ioremap(0xe0000000 + (sc->iob_pdev->devfn << 12), 0x2000); ++ if (!sc->dma_regs || !sc->iob_regs) { ++ dev_err(&pdev->dev, "Can't map registers\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ dma_status = __ioremap(0xfd800000, 0x1000, 0); ++ if (!dma_status) { ++ ret = -ENODEV; ++ dev_err(&pdev->dev, "Can't map dmastatus space\n"); ++ goto out; ++ } ++ ++ sc->tx = (struct pasemi_fnu_txring *) ++ kzalloc(sizeof(struct pasemi_fnu_txring) ++ * 8, GFP_KERNEL); ++ if (!sc->tx) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* Initialize the h/w */ ++ out_le32(sc->dma_regs + PAS_DMA_COM_CFG, ++ (in_le32(sc->dma_regs + PAS_DMA_COM_CFG) | ++ PAS_DMA_COM_CFG_FWF)); ++ out_le32(sc->dma_regs + PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); ++ ++ for (i = 0; i < PASEMI_FNU_CHANNELS; i++) { ++ sc->sc_num_channels++; ++ ret = pasemi_dma_setup_tx_resources(sc, i); ++ if (ret) ++ goto out; ++ } ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc), ++ CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ printk(KERN_ERR DRV_NAME ": could not get crypto driver id\n"); ++ ret = -ENXIO; ++ goto out; ++ } ++ ++ /* register algorithms with the framework */ ++ printk(DRV_NAME ":"); ++ ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ ++ return 0; ++ ++out: ++ pasemi_dma_remove(pdev); ++ return ret; ++} ++ ++#define MAX_RETRIES 5000 ++ ++static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan) ++{ ++ struct pasemi_fnu_txring *ring = &sc->tx[chan]; ++ int chan_index = chan + sc->base_chan; ++ int retries; ++ u32 stat; ++ ++ /* Stop the channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ PAS_DMA_TXCHAN_TCMDSTA_ST); ++ ++ for (retries = 0; retries < MAX_RETRIES; retries++) { ++ stat = in_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index)); ++ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) ++ break; ++ cond_resched(); ++ } ++ ++ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) ++ dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n", ++ chan_index); ++ ++ /* Disable the channel */ ++ out_le32(sc->dma_regs + ++ PAS_DMA_TXCHAN_TCMDSTA(chan_index), ++ 0); ++ ++ if (ring->desc_info) ++ kfree((void *) ring->desc_info); ++ if (ring->desc) ++ dma_free_coherent(&sc->dma_pdev->dev, ++ TX_RING_SIZE * ++ 2 * sizeof(u64), ++ (void *) ring->desc, ring->dma); ++ if (ring->irq != -1) ++ free_irq(ring->irq, sc); ++ ++ del_timer(&ring->crypto_timer); ++} ++ ++static void __devexit pasemi_dma_remove(struct pci_dev *pdev) ++{ ++ struct pasemi_softc *sc = pci_get_drvdata(pdev); ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (sc->sc_cid >= 0) { ++ crypto_unregister_all(sc->sc_cid); ++ } ++ ++ if (sc->tx) { ++ for (i = 0; i < sc->sc_num_channels; i++) ++ pasemi_free_tx_resources(sc, i); ++ ++ kfree(sc->tx); ++ } ++ if (sc->sc_sessions) { ++ for (i = 0; i < sc->sc_nsessions; i++) ++ kfree(sc->sc_sessions[i]); ++ kfree(sc->sc_sessions); ++ } ++ if (sc->iob_pdev) ++ pci_dev_put(sc->iob_pdev); ++ if (sc->dma_regs) ++ iounmap(sc->dma_regs); ++ if (sc->iob_regs) ++ iounmap(sc->iob_regs); ++ kfree(sc); ++} ++ ++static struct pci_device_id pasemi_dma_pci_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa007) }, ++}; ++ ++MODULE_DEVICE_TABLE(pci, pasemi_dma_pci_tbl); ++ ++static struct pci_driver pasemi_dma_driver = { ++ .name = "pasemi_dma", ++ .id_table = pasemi_dma_pci_tbl, ++ .probe = pasemi_dma_probe, ++ .remove = __devexit_p(pasemi_dma_remove), ++}; ++ ++static void __exit pasemi_dma_cleanup_module(void) ++{ ++ pci_unregister_driver(&pasemi_dma_driver); ++ __iounmap(dma_status); ++ dma_status = NULL; ++} ++ ++int pasemi_dma_init_module(void) ++{ ++ return pci_register_driver(&pasemi_dma_driver); ++} ++ ++module_init(pasemi_dma_init_module); ++module_exit(pasemi_dma_cleanup_module); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Egor Martovetsky egor@pasemi.com"); ++MODULE_DESCRIPTION("OCF driver for PA Semi PWRficient DMA Crypto Engine"); +diff -Nur linux-2.6.30.orig/crypto/ocf/pasemi/pasemi_fnu.h linux-2.6.30/crypto/ocf/pasemi/pasemi_fnu.h +--- linux-2.6.30.orig/crypto/ocf/pasemi/pasemi_fnu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/pasemi/pasemi_fnu.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,410 @@ ++/* ++ * Copyright (C) 2007 PA Semi, Inc ++ * ++ * Driver for the PA Semi PWRficient DMA Crypto Engine, soft state and ++ * hardware register layouts. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * 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 PASEMI_FNU_H ++#define PASEMI_FNU_H ++ ++#include ++ ++#define PASEMI_SESSION(sid) ((sid) & 0xffffffff) ++#define PASEMI_SID(sesn) ((sesn) & 0xffffffff) ++#define DPRINTF(a...) if (debug) { printk(DRV_NAME ": " a); } ++ ++/* Must be a power of two */ ++#define RX_RING_SIZE 512 ++#define TX_RING_SIZE 512 ++#define TX_DESC(ring, num) ((ring)->desc[2 * (num & (TX_RING_SIZE-1))]) ++#define TX_DESC_INFO(ring, num) ((ring)->desc_info[(num) & (TX_RING_SIZE-1)]) ++#define MAX_DESC_SIZE 8 ++#define PASEMI_INITIAL_SESSIONS 10 ++#define PASEMI_FNU_CHANNELS 8 ++ ++/* DMA descriptor */ ++struct pasemi_desc { ++ u64 quad[2*MAX_DESC_SIZE]; ++ int quad_cnt; ++ int size; ++ int postop; ++}; ++ ++/* ++ * Holds per descriptor data ++ */ ++struct pasemi_desc_info { ++ int desc_size; ++ int desc_postop; ++#define PASEMI_CHECK_SIG 0x1 ++ ++ struct cryptop *cf_crp; ++}; ++ ++/* ++ * Holds per channel data ++ */ ++struct pasemi_fnu_txring { ++ volatile u64 *desc; ++ volatile struct ++ pasemi_desc_info *desc_info; ++ dma_addr_t dma; ++ struct timer_list crypto_timer; ++ spinlock_t fill_lock; ++ spinlock_t clean_lock; ++ unsigned int next_to_fill; ++ unsigned int next_to_clean; ++ u16 total_pktcnt; ++ int irq; ++ int sesn; ++ char irq_name[10]; ++}; ++ ++/* ++ * Holds data specific to a single pasemi device. ++ */ ++struct pasemi_softc { ++ softc_device_decl sc_cdev; ++ struct pci_dev *dma_pdev; /* device backpointer */ ++ struct pci_dev *iob_pdev; /* device backpointer */ ++ void __iomem *dma_regs; ++ void __iomem *iob_regs; ++ int base_irq; ++ int base_chan; ++ int32_t sc_cid; /* crypto tag */ ++ int sc_nsessions; ++ struct pasemi_session **sc_sessions; ++ int sc_num_channels;/* number of crypto channels */ ++ ++ /* pointer to the array of txring datastructures, one txring per channel */ ++ struct pasemi_fnu_txring *tx; ++ ++ /* ++ * mutual exclusion for the channel scheduler ++ */ ++ spinlock_t sc_chnlock; ++ /* last channel used, for now use round-robin to allocate channels */ ++ int sc_lastchn; ++}; ++ ++struct pasemi_session { ++ u64 civ[2]; ++ u64 keysz; ++ u64 key[4]; ++ u64 ccmd; ++ u64 hkey[4]; ++ u64 hseq; ++ u64 giv[2]; ++ u64 hiv[4]; ++ ++ int used; ++ dma_addr_t dma_addr; ++ int chan; ++}; ++ ++/* status register layout in IOB region, at 0xfd800000 */ ++struct pasdma_status { ++ u64 rx_sta[64]; ++ u64 tx_sta[20]; ++}; ++ ++#define ALG_IS_CIPHER(alg) ((alg == CRYPTO_DES_CBC) || \ ++ (alg == CRYPTO_3DES_CBC) || \ ++ (alg == CRYPTO_AES_CBC) || \ ++ (alg == CRYPTO_ARC4) || \ ++ (alg == CRYPTO_NULL_CBC)) ++ ++#define ALG_IS_SIG(alg) ((alg == CRYPTO_MD5) || \ ++ (alg == CRYPTO_MD5_HMAC) || \ ++ (alg == CRYPTO_SHA1) || \ ++ (alg == CRYPTO_SHA1_HMAC) || \ ++ (alg == CRYPTO_NULL_HMAC)) ++ ++enum { ++ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ ++ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ ++ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ ++ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ ++ PAS_DMA_COM_CFG = 0x114, /* DMA Configuration Register */ ++}; ++ ++/* All these registers live in the PCI configuration space for the DMA PCI ++ * device. Use the normal PCI config access functions for them. ++ */ ++ ++#define PAS_DMA_COM_CFG_FWF 0x18000000 ++ ++#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ ++#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ ++#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ ++#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ ++ ++#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ ++#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ ++#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ ++#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ ++#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ ++#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ ++#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ ++#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ ++#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ ++#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ ++#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ ++#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_CFG_TY_FUNC 0x00000002 /* Type = interface */ ++#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ ++#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c ++#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 ++#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ ++ PAS_DMA_TXCHAN_CFG_TATTR_M) ++#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 ++#define PAS_DMA_TXCHAN_CFG_WT_S 6 ++#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ ++ PAS_DMA_TXCHAN_CFG_WT_M) ++#define PAS_DMA_TXCHAN_CFG_LPSQ_FAST 0x00000400 ++#define PAS_DMA_TXCHAN_CFG_LPDQ_FAST 0x00000800 ++#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ ++#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ ++#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ ++#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 ++#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 ++#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ ++ PAS_DMA_TXCHAN_BASEL_BRBL_M) ++#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) ++#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff ++#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 ++#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ ++ PAS_DMA_TXCHAN_BASEU_BRBH_M) ++/* # of cache lines worth of buffer ring */ ++#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 ++#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ ++#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ ++ PAS_DMA_TXCHAN_BASEU_SIZ_M) ++ ++#define PAS_STATUS_PCNT_M 0x000000000000ffffull ++#define PAS_STATUS_PCNT_S 0 ++#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull ++#define PAS_STATUS_DCNT_S 16 ++#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull ++#define PAS_STATUS_BPCNT_S 32 ++#define PAS_STATUS_CAUSE_M 0xf000000000000000ull ++#define PAS_STATUS_TIMER 0x1000000000000000ull ++#define PAS_STATUS_ERROR 0x2000000000000000ull ++#define PAS_STATUS_SOFT 0x4000000000000000ull ++#define PAS_STATUS_INT 0x8000000000000000ull ++ ++#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 ++#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ ++ PAS_IOB_DMA_RXCH_CFG_CNTTH_M) ++#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 ++#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ ++ PAS_IOB_DMA_TXCH_CFG_CNTTH_M) ++#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) ++#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 ++#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ ++ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) ++#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) ++#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 ++#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ ++ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) ++#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) ++#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 ++#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 16 ++#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ ++ PAS_IOB_DMA_RXCH_RESET_PCNT_M) ++#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 ++#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 ++#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 ++#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 ++#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 ++#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 ++#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) ++#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 ++#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 16 ++#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ ++ PAS_IOB_DMA_TXCH_RESET_PCNT_M) ++#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 ++#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 ++#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 ++#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 ++#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 ++#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 ++ ++#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 ++#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ ++ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) ++ ++/* Transmit descriptor fields */ ++#define XCT_MACTX_T 0x8000000000000000ull ++#define XCT_MACTX_ST 0x4000000000000000ull ++#define XCT_MACTX_NORES 0x0000000000000000ull ++#define XCT_MACTX_8BRES 0x1000000000000000ull ++#define XCT_MACTX_24BRES 0x2000000000000000ull ++#define XCT_MACTX_40BRES 0x3000000000000000ull ++#define XCT_MACTX_I 0x0800000000000000ull ++#define XCT_MACTX_O 0x0400000000000000ull ++#define XCT_MACTX_E 0x0200000000000000ull ++#define XCT_MACTX_VLAN_M 0x0180000000000000ull ++#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull ++#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull ++#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull ++#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull ++#define XCT_MACTX_CRC_M 0x0060000000000000ull ++#define XCT_MACTX_CRC_NOP 0x0000000000000000ull ++#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull ++#define XCT_MACTX_CRC_PAD 0x0040000000000000ull ++#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull ++#define XCT_MACTX_SS 0x0010000000000000ull ++#define XCT_MACTX_LLEN_M 0x00007fff00000000ull ++#define XCT_MACTX_LLEN_S 32ull ++#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ ++ XCT_MACTX_LLEN_M) ++#define XCT_MACTX_IPH_M 0x00000000f8000000ull ++#define XCT_MACTX_IPH_S 27ull ++#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ ++ XCT_MACTX_IPH_M) ++#define XCT_MACTX_IPO_M 0x0000000007c00000ull ++#define XCT_MACTX_IPO_S 22ull ++#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ ++ XCT_MACTX_IPO_M) ++#define XCT_MACTX_CSUM_M 0x0000000000000060ull ++#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull ++#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull ++#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull ++#define XCT_MACTX_V6 0x0000000000000010ull ++#define XCT_MACTX_C 0x0000000000000004ull ++#define XCT_MACTX_AL2 0x0000000000000002ull ++ ++#define XCT_PTR_T 0x8000000000000000ull ++#define XCT_PTR_LEN_M 0x7ffff00000000000ull ++#define XCT_PTR_LEN_S 44 ++#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ ++ XCT_PTR_LEN_M) ++#define XCT_PTR_ADDR_M 0x00000fffffffffffull ++#define XCT_PTR_ADDR_S 0 ++#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ ++ XCT_PTR_ADDR_M) ++ ++/* Function descriptor fields */ ++#define XCT_FUN_T 0x8000000000000000ull ++#define XCT_FUN_ST 0x4000000000000000ull ++#define XCT_FUN_NORES 0x0000000000000000ull ++#define XCT_FUN_8BRES 0x1000000000000000ull ++#define XCT_FUN_24BRES 0x2000000000000000ull ++#define XCT_FUN_40BRES 0x3000000000000000ull ++#define XCT_FUN_I 0x0800000000000000ull ++#define XCT_FUN_O 0x0400000000000000ull ++#define XCT_FUN_E 0x0200000000000000ull ++#define XCT_FUN_FUN_S 54 ++#define XCT_FUN_FUN_M 0x01c0000000000000ull ++#define XCT_FUN_FUN(num) ((((long)(num)) << XCT_FUN_FUN_S) & \ ++ XCT_FUN_FUN_M) ++#define XCT_FUN_CRM_NOP 0x0000000000000000ull ++#define XCT_FUN_CRM_SIG 0x0008000000000000ull ++#define XCT_FUN_CRM_ENC 0x0010000000000000ull ++#define XCT_FUN_CRM_DEC 0x0018000000000000ull ++#define XCT_FUN_CRM_SIG_ENC 0x0020000000000000ull ++#define XCT_FUN_CRM_ENC_SIG 0x0028000000000000ull ++#define XCT_FUN_CRM_SIG_DEC 0x0030000000000000ull ++#define XCT_FUN_CRM_DEC_SIG 0x0038000000000000ull ++#define XCT_FUN_LLEN_M 0x0007ffff00000000ull ++#define XCT_FUN_LLEN_S 32ULL ++#define XCT_FUN_LLEN(x) ((((long)(x)) << XCT_FUN_LLEN_S) & \ ++ XCT_FUN_LLEN_M) ++#define XCT_FUN_SHL_M 0x00000000f8000000ull ++#define XCT_FUN_SHL_S 27ull ++#define XCT_FUN_SHL(x) ((((long)(x)) << XCT_FUN_SHL_S) & \ ++ XCT_FUN_SHL_M) ++#define XCT_FUN_CHL_M 0x0000000007c00000ull ++#define XCT_FUN_CHL_S 22ull ++#define XCT_FUN_CHL(x) ((((long)(x)) << XCT_FUN_CHL_S) & \ ++ XCT_FUN_CHL_M) ++#define XCT_FUN_HSZ_M 0x00000000003c0000ull ++#define XCT_FUN_HSZ_S 18ull ++#define XCT_FUN_HSZ(x) ((((long)(x)) << XCT_FUN_HSZ_S) & \ ++ XCT_FUN_HSZ_M) ++#define XCT_FUN_ALG_DES 0x0000000000000000ull ++#define XCT_FUN_ALG_3DES 0x0000000000008000ull ++#define XCT_FUN_ALG_AES 0x0000000000010000ull ++#define XCT_FUN_ALG_ARC 0x0000000000018000ull ++#define XCT_FUN_ALG_KASUMI 0x0000000000020000ull ++#define XCT_FUN_BCM_ECB 0x0000000000000000ull ++#define XCT_FUN_BCM_CBC 0x0000000000001000ull ++#define XCT_FUN_BCM_CFB 0x0000000000002000ull ++#define XCT_FUN_BCM_OFB 0x0000000000003000ull ++#define XCT_FUN_BCM_CNT 0x0000000000003800ull ++#define XCT_FUN_BCM_KAS_F8 0x0000000000002800ull ++#define XCT_FUN_BCM_KAS_F9 0x0000000000001800ull ++#define XCT_FUN_BCP_NO_PAD 0x0000000000000000ull ++#define XCT_FUN_BCP_ZRO 0x0000000000000200ull ++#define XCT_FUN_BCP_PL 0x0000000000000400ull ++#define XCT_FUN_BCP_INCR 0x0000000000000600ull ++#define XCT_FUN_SIG_MD5 (0ull << 4) ++#define XCT_FUN_SIG_SHA1 (2ull << 4) ++#define XCT_FUN_SIG_HMAC_MD5 (8ull << 4) ++#define XCT_FUN_SIG_HMAC_SHA1 (10ull << 4) ++#define XCT_FUN_A 0x0000000000000008ull ++#define XCT_FUN_C 0x0000000000000004ull ++#define XCT_FUN_AL2 0x0000000000000002ull ++#define XCT_FUN_SE 0x0000000000000001ull ++ ++#define XCT_FUN_SRC_PTR(len, addr) (XCT_PTR_LEN(len) | XCT_PTR_ADDR(addr)) ++#define XCT_FUN_DST_PTR(len, addr) (XCT_FUN_SRC_PTR(len, addr) | \ ++ 0x8000000000000000ull) ++ ++#define XCT_CTRL_HDR_FUN_NUM_M 0x01c0000000000000ull ++#define XCT_CTRL_HDR_FUN_NUM_S 54 ++#define XCT_CTRL_HDR_LEN_M 0x0007ffff00000000ull ++#define XCT_CTRL_HDR_LEN_S 32 ++#define XCT_CTRL_HDR_REG_M 0x00000000000000ffull ++#define XCT_CTRL_HDR_REG_S 0 ++ ++#define XCT_CTRL_HDR(funcN,len,reg) (0x9400000000000000ull | \ ++ ((((long)(funcN)) << XCT_CTRL_HDR_FUN_NUM_S) \ ++ & XCT_CTRL_HDR_FUN_NUM_M) | \ ++ ((((long)(len)) << \ ++ XCT_CTRL_HDR_LEN_S) & XCT_CTRL_HDR_LEN_M) | \ ++ ((((long)(reg)) << \ ++ XCT_CTRL_HDR_REG_S) & XCT_CTRL_HDR_REG_M)) ++ ++/* Function config command options */ ++#define DMA_CALGO_DES 0x00 ++#define DMA_CALGO_3DES 0x01 ++#define DMA_CALGO_AES 0x02 ++#define DMA_CALGO_ARC 0x03 ++ ++#define DMA_FN_CIV0 0x02 ++#define DMA_FN_CIV1 0x03 ++#define DMA_FN_HKEY0 0x0a ++ ++#define XCT_PTR_ADDR_LEN(ptr) ((ptr) & XCT_PTR_ADDR_M), \ ++ (((ptr) & XCT_PTR_LEN_M) >> XCT_PTR_LEN_S) ++ ++#endif /* PASEMI_FNU_H */ +diff -Nur linux-2.6.30.orig/crypto/ocf/random.c linux-2.6.30/crypto/ocf/random.c +--- linux-2.6.30.orig/crypto/ocf/random.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/random.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,317 @@ ++/* ++ * A system independant way of adding entropy to the kernels pool ++ * this way the drivers can focus on the real work and we can take ++ * care of pushing it to the appropriate place in the kernel. ++ * ++ * This should be fast and callable from timers/interrupts ++ * ++ * Written by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_OCF_FIPS ++#include "rndtest.h" ++#endif ++ ++#ifndef HAS_RANDOM_INPUT_WAIT ++#error "Please do not enable OCF_RANDOMHARVEST unless you have applied patches" ++#endif ++ ++/* ++ * a hack to access the debug levels from the crypto driver ++ */ ++extern int crypto_debug; ++#define debug crypto_debug ++ ++/* ++ * a list of all registered random providers ++ */ ++static LIST_HEAD(random_ops); ++static int started = 0; ++static int initted = 0; ++ ++struct random_op { ++ struct list_head random_list; ++ u_int32_t driverid; ++ int (*read_random)(void *arg, u_int32_t *buf, int len); ++ void *arg; ++}; ++ ++static int random_proc(void *arg); ++ ++static pid_t randomproc = (pid_t) -1; ++static spinlock_t random_lock; ++ ++/* ++ * just init the spin locks ++ */ ++static int ++crypto_random_init(void) ++{ ++ spin_lock_init(&random_lock); ++ initted = 1; ++ return(0); ++} ++ ++/* ++ * Add the given random reader to our list (if not present) ++ * and start the thread (if not already started) ++ * ++ * we have to assume that driver id is ok for now ++ */ ++int ++crypto_rregister( ++ u_int32_t driverid, ++ int (*read_random)(void *arg, u_int32_t *buf, int len), ++ void *arg) ++{ ++ unsigned long flags; ++ int ret = 0; ++ struct random_op *rops, *tmp; ++ ++ dprintk("%s,%d: %s(0x%x, %p, %p)\n", __FILE__, __LINE__, ++ __FUNCTION__, driverid, read_random, arg); ++ ++ if (!initted) ++ crypto_random_init(); ++ ++#if 0 ++ struct cryptocap *cap; ++ ++ cap = crypto_checkdriver(driverid); ++ if (!cap) ++ return EINVAL; ++#endif ++ ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ if (rops->driverid == driverid && rops->read_random == read_random) ++ return EEXIST; ++ } ++ ++ rops = (struct random_op *) kmalloc(sizeof(*rops), GFP_KERNEL); ++ if (!rops) ++ return ENOMEM; ++ ++ rops->driverid = driverid; ++ rops->read_random = read_random; ++ rops->arg = arg; ++ ++ spin_lock_irqsave(&random_lock, flags); ++ list_add_tail(&rops->random_list, &random_ops); ++ if (!started) { ++ randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES); ++ if (randomproc < 0) { ++ ret = randomproc; ++ printk("crypto: crypto_rregister cannot start random thread; " ++ "error %d", ret); ++ } else ++ started = 1; ++ } ++ spin_unlock_irqrestore(&random_lock, flags); ++ ++ return ret; ++} ++EXPORT_SYMBOL(crypto_rregister); ++ ++int ++crypto_runregister_all(u_int32_t driverid) ++{ ++ struct random_op *rops, *tmp; ++ unsigned long flags; ++ ++ dprintk("%s,%d: %s(0x%x)\n", __FILE__, __LINE__, __FUNCTION__, driverid); ++ ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ if (rops->driverid == driverid) { ++ list_del(&rops->random_list); ++ kfree(rops); ++ } ++ } ++ ++ spin_lock_irqsave(&random_lock, flags); ++ if (list_empty(&random_ops) && started) ++ kill_pid(randomproc, SIGKILL, 1); ++ spin_unlock_irqrestore(&random_lock, flags); ++ return(0); ++} ++EXPORT_SYMBOL(crypto_runregister_all); ++ ++/* ++ * while we can add entropy to random.c continue to read random data from ++ * the drivers and push it to random. ++ */ ++static int ++random_proc(void *arg) ++{ ++ int n; ++ int wantcnt; ++ int bufcnt = 0; ++ int retval = 0; ++ int *buf = NULL; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ daemonize(); ++ spin_lock_irq(¤t->sigmask_lock); ++ sigemptyset(¤t->blocked); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ sprintf(current->comm, "ocf-random"); ++#else ++ daemonize("ocf-random"); ++ allow_signal(SIGKILL); ++#endif ++ ++ (void) get_fs(); ++ set_fs(get_ds()); ++ ++#ifdef CONFIG_OCF_FIPS ++#define NUM_INT (RNDTEST_NBYTES/sizeof(int)) ++#else ++#define NUM_INT 32 ++#endif ++ ++ /* ++ * some devices can transferr their RNG data direct into memory, ++ * so make sure it is device friendly ++ */ ++ buf = kmalloc(NUM_INT * sizeof(int), GFP_DMA); ++ if (NULL == buf) { ++ printk("crypto: RNG could not allocate memory\n"); ++ retval = -ENOMEM; ++ goto bad_alloc; ++ } ++ ++ wantcnt = NUM_INT; /* start by adding some entropy */ ++ ++ /* ++ * its possible due to errors or driver removal that we no longer ++ * have anything to do, if so exit or we will consume all the CPU ++ * doing nothing ++ */ ++ while (!list_empty(&random_ops)) { ++ struct random_op *rops, *tmp; ++ ++#ifdef CONFIG_OCF_FIPS ++ if (wantcnt) ++ wantcnt = NUM_INT; /* FIPs mode can do 20000 bits or none */ ++#endif ++ ++ /* see if we can get enough entropy to make the world ++ * a better place. ++ */ ++ while (bufcnt < wantcnt && bufcnt < NUM_INT) { ++ list_for_each_entry_safe(rops, tmp, &random_ops, random_list) { ++ ++ n = (*rops->read_random)(rops->arg, &buf[bufcnt], ++ NUM_INT - bufcnt); ++ ++ /* on failure remove the random number generator */ ++ if (n == -1) { ++ list_del(&rops->random_list); ++ printk("crypto: RNG (driverid=0x%x) failed, disabling\n", ++ rops->driverid); ++ kfree(rops); ++ } else if (n > 0) ++ bufcnt += n; ++ } ++ /* give up CPU for a bit, just in case as this is a loop */ ++ schedule(); ++ } ++ ++ ++#ifdef CONFIG_OCF_FIPS ++ if (bufcnt > 0 && rndtest_buf((unsigned char *) &buf[0])) { ++ dprintk("crypto: buffer had fips errors, discarding\n"); ++ bufcnt = 0; ++ } ++#endif ++ ++ /* ++ * if we have a certified buffer, we can send some data ++ * to /dev/random and move along ++ */ ++ if (bufcnt > 0) { ++ /* add what we have */ ++ random_input_words(buf, bufcnt, bufcnt*sizeof(int)*8); ++ bufcnt = 0; ++ } ++ ++ /* give up CPU for a bit so we don't hog while filling */ ++ schedule(); ++ ++ /* wait for needing more */ ++ wantcnt = random_input_wait(); ++ ++ if (wantcnt <= 0) ++ wantcnt = 0; /* try to get some info again */ ++ else ++ /* round up to one word or we can loop forever */ ++ wantcnt = (wantcnt + (sizeof(int)*8)) / (sizeof(int)*8); ++ if (wantcnt > NUM_INT) { ++ wantcnt = NUM_INT; ++ } ++ ++ if (signal_pending(current)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_lock_irq(¤t->sigmask_lock); ++#endif ++ flush_signals(current); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ spin_unlock_irq(¤t->sigmask_lock); ++#endif ++ } ++ } ++ ++ kfree(buf); ++ ++bad_alloc: ++ spin_lock_irq(&random_lock); ++ randomproc = (pid_t) -1; ++ started = 0; ++ spin_unlock_irq(&random_lock); ++ ++ return retval; ++} ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/README linux-2.6.30/crypto/ocf/README +--- linux-2.6.30.orig/crypto/ocf/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/README 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,167 @@ ++README - ocf-linux-20071215 ++--------------------------- ++ ++This README provides instructions for getting ocf-linux compiled and ++operating in a generic linux environment. For other information you ++might like to visit the home page for this project: ++ ++ http://ocf-linux.sourceforge.net/ ++ ++Adding OCF to linux ++------------------- ++ ++ Not much in this file for now, just some notes. I usually build ++ the ocf support as modules but it can be built into the kernel as ++ well. To use it: ++ ++ * mknod /dev/crypto c 10 70 ++ ++ * to add OCF to your kernel source, you have two options. Apply ++ the kernel specific patch: ++ ++ cd linux-2.4*; gunzip < ocf-linux-24-XXXXXXXX.patch.gz | patch -p1 ++ cd linux-2.6*; gunzip < ocf-linux-26-XXXXXXXX.patch.gz | patch -p1 ++ ++ if you do one of the above, then you can proceed to the next step, ++ or you can do the above process by hand with using the patches against ++ linux-2.4.35 and 2.6.23 to include the ocf code under crypto/ocf. ++ Here's how to add it: ++ ++ for 2.4.35 (and later) ++ ++ cd linux-2.4.35/crypto ++ tar xvzf ocf-linux.tar.gz ++ cd .. ++ patch -p1 < crypto/ocf/patches/linux-2.4.35-ocf.patch ++ ++ for 2.6.23 (and later), find the kernel patch specific (or nearest) ++ to your kernel versions and then: ++ ++ cd linux-2.6.NN/crypto ++ tar xvzf ocf-linux.tar.gz ++ cd .. ++ patch -p1 < crypto/ocf/patches/linux-2.6.NN-ocf.patch ++ ++ It should be easy to take this patch and apply it to other more ++ recent versions of the kernels. The same patches should also work ++ relatively easily on kernels as old as 2.6.11 and 2.4.18. ++ ++ * under 2.4 if you are on a non-x86 platform, you may need to: ++ ++ cp linux-2.X.x/include/asm-i386/kmap_types.h linux-2.X.x/include/asm-YYY ++ ++ so that you can build the kernel crypto support needed for the cryptosoft ++ driver. ++ ++ * For simplicity you should enable all the crypto support in your kernel ++ except for the test driver. Likewise for the OCF options. Do not ++ enable OCF crypto drivers for HW that you do not have (for example ++ ixp4xx will not compile on non-Xscale systems). ++ ++ * make sure that cryptodev.h (from ocf-linux.tar.gz) is installed as ++ crypto/cryptodev.h in an include directory that is used for building ++ applications for your platform. For example on a host system that ++ might be: ++ ++ /usr/include/crypto/cryptodev.h ++ ++ * patch your openssl-0.9.8i code with the openssl-0.9.8i.patch. ++ (NOTE: there is no longer a need to patch ssh). The patch is against: ++ openssl-0_9_8e ++ ++ If you need a patch for an older version of openssl, you should look ++ to older OCF releases. This patch is unlikely to work on older ++ openssl versions. ++ ++ openssl-0.9.8i.patch ++ - enables --with-cryptodev for non BSD systems ++ - adds -cpu option to openssl speed for calculating CPU load ++ under linux ++ - fixes null pointer in openssl speed multi thread output. ++ - fixes test keys to work with linux crypto's more stringent ++ key checking. ++ - adds MD5/SHA acceleration (Ronen Shitrit), only enabled ++ with the --with-cryptodev-digests option ++ - fixes bug in engine code caching. ++ ++ * build crypto-tools-XXXXXXXX.tar.gz if you want to try some of the BSD ++ tools for testing OCF (ie., cryptotest). ++ ++How to load the OCF drivers ++--------------------------- ++ ++ First insert the base modules: ++ ++ insmod ocf ++ insmod cryptodev ++ ++ You can then install the software OCF driver with: ++ ++ insmod cryptosoft ++ ++ and one or more of the OCF HW drivers with: ++ ++ insmod safe ++ insmod hifn7751 ++ insmod ixp4xx ++ ... ++ ++ all the drivers take a debug option to enable verbose debug so that ++ you can see what is going on. For debug you load them as: ++ ++ insmod ocf crypto_debug=1 ++ insmod cryptodev cryptodev_debug=1 ++ insmod cryptosoft swcr_debug=1 ++ ++ You may load more than one OCF crypto driver but then there is no guarantee ++ as to which will be used. ++ ++ You can also enable debug at run time on 2.6 systems with the following: ++ ++ echo 1 > /sys/module/ocf/parameters/crypto_debug ++ echo 1 > /sys/module/cryptodev/parameters/cryptodev_debug ++ echo 1 > /sys/module/cryptosoft/parameters/swcr_debug ++ echo 1 > /sys/module/hifn7751/parameters/hifn_debug ++ echo 1 > /sys/module/safe/parameters/safe_debug ++ echo 1 > /sys/module/ixp4xx/parameters/ixp_debug ++ ... ++ ++Testing the OCF support ++----------------------- ++ ++ run "cryptotest", it should do a short test for a couple of ++ des packets. If it does everything is working. ++ ++ If this works, then ssh will use the driver when invoked as: ++ ++ ssh -c 3des username@host ++ ++ to see for sure that it is operating, enable debug as defined above. ++ ++ To get a better idea of performance run: ++ ++ cryptotest 100 4096 ++ ++ There are more options to cryptotest, see the help. ++ ++ It is also possible to use openssl to test the speed of the crypto ++ drivers. ++ ++ openssl speed -evp des -engine cryptodev -elapsed ++ openssl speed -evp des3 -engine cryptodev -elapsed ++ openssl speed -evp aes128 -engine cryptodev -elapsed ++ ++ and multiple threads (10) with: ++ ++ openssl speed -evp des -engine cryptodev -elapsed -multi 10 ++ openssl speed -evp des3 -engine cryptodev -elapsed -multi 10 ++ openssl speed -evp aes128 -engine cryptodev -elapsed -multi 10 ++ ++ for public key testing you can try: ++ ++ cryptokeytest ++ openssl speed -engine cryptodev rsa -elapsed ++ openssl speed -engine cryptodev dsa -elapsed ++ ++David McCullough ++david_mccullough@securecomputing.com +diff -Nur linux-2.6.30.orig/crypto/ocf/rndtest.c linux-2.6.30/crypto/ocf/rndtest.c +--- linux-2.6.30.orig/crypto/ocf/rndtest.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/rndtest.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,300 @@ ++/* $OpenBSD$ */ ++ ++/* ++ * OCF/Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Jason L. Wright ++ * 4. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rndtest.h" ++ ++static struct rndtest_stats rndstats; ++ ++static void rndtest_test(struct rndtest_state *); ++ ++/* The tests themselves */ ++static int rndtest_monobit(struct rndtest_state *); ++static int rndtest_runs(struct rndtest_state *); ++static int rndtest_longruns(struct rndtest_state *); ++static int rndtest_chi_4(struct rndtest_state *); ++ ++static int rndtest_runs_check(struct rndtest_state *, int, int *); ++static void rndtest_runs_record(struct rndtest_state *, int, int *); ++ ++static const struct rndtest_testfunc { ++ int (*test)(struct rndtest_state *); ++} rndtest_funcs[] = { ++ { rndtest_monobit }, ++ { rndtest_runs }, ++ { rndtest_chi_4 }, ++ { rndtest_longruns }, ++}; ++ ++#define RNDTEST_NTESTS (sizeof(rndtest_funcs)/sizeof(rndtest_funcs[0])) ++ ++static void ++rndtest_test(struct rndtest_state *rsp) ++{ ++ int i, rv = 0; ++ ++ rndstats.rst_tests++; ++ for (i = 0; i < RNDTEST_NTESTS; i++) ++ rv |= (*rndtest_funcs[i].test)(rsp); ++ rsp->rs_discard = (rv != 0); ++} ++ ++ ++extern int crypto_debug; ++#define rndtest_verbose 2 ++#define rndtest_report(rsp, failure, fmt, a...) \ ++ { if (failure || crypto_debug) { printk("rng_test: " fmt "\n", a); } else; } ++ ++#define RNDTEST_MONOBIT_MINONES 9725 ++#define RNDTEST_MONOBIT_MAXONES 10275 ++ ++static int ++rndtest_monobit(struct rndtest_state *rsp) ++{ ++ int i, ones = 0, j; ++ u_int8_t r; ++ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ r = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, r <<= 1) ++ if (r & 0x80) ++ ones++; ++ } ++ if (ones > RNDTEST_MONOBIT_MINONES && ++ ones < RNDTEST_MONOBIT_MAXONES) { ++ if (rndtest_verbose > 1) ++ rndtest_report(rsp, 0, "monobit pass (%d < %d < %d)", ++ RNDTEST_MONOBIT_MINONES, ones, ++ RNDTEST_MONOBIT_MAXONES); ++ return (0); ++ } else { ++ if (rndtest_verbose) ++ rndtest_report(rsp, 1, ++ "monobit failed (%d ones)", ones); ++ rndstats.rst_monobit++; ++ return (-1); ++ } ++} ++ ++#define RNDTEST_RUNS_NINTERVAL 6 ++ ++static const struct rndtest_runs_tabs { ++ u_int16_t min, max; ++} rndtest_runs_tab[] = { ++ { 2343, 2657 }, ++ { 1135, 1365 }, ++ { 542, 708 }, ++ { 251, 373 }, ++ { 111, 201 }, ++ { 111, 201 }, ++}; ++ ++static int ++rndtest_runs(struct rndtest_state *rsp) ++{ ++ int i, j, ones, zeros, rv = 0; ++ int onei[RNDTEST_RUNS_NINTERVAL], zeroi[RNDTEST_RUNS_NINTERVAL]; ++ u_int8_t c; ++ ++ bzero(onei, sizeof(onei)); ++ bzero(zeroi, sizeof(zeroi)); ++ ones = zeros = 0; ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ c = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, c <<= 1) { ++ if (c & 0x80) { ++ ones++; ++ rndtest_runs_record(rsp, zeros, zeroi); ++ zeros = 0; ++ } else { ++ zeros++; ++ rndtest_runs_record(rsp, ones, onei); ++ ones = 0; ++ } ++ } ++ } ++ rndtest_runs_record(rsp, ones, onei); ++ rndtest_runs_record(rsp, zeros, zeroi); ++ ++ rv |= rndtest_runs_check(rsp, 0, zeroi); ++ rv |= rndtest_runs_check(rsp, 1, onei); ++ ++ if (rv) ++ rndstats.rst_runs++; ++ ++ return (rv); ++} ++ ++static void ++rndtest_runs_record(struct rndtest_state *rsp, int len, int *intrv) ++{ ++ if (len == 0) ++ return; ++ if (len > RNDTEST_RUNS_NINTERVAL) ++ len = RNDTEST_RUNS_NINTERVAL; ++ len -= 1; ++ intrv[len]++; ++} ++ ++static int ++rndtest_runs_check(struct rndtest_state *rsp, int val, int *src) ++{ ++ int i, rv = 0; ++ ++ for (i = 0; i < RNDTEST_RUNS_NINTERVAL; i++) { ++ if (src[i] < rndtest_runs_tab[i].min || ++ src[i] > rndtest_runs_tab[i].max) { ++ rndtest_report(rsp, 1, ++ "%s interval %d failed (%d, %d-%d)", ++ val ? "ones" : "zeros", ++ i + 1, src[i], rndtest_runs_tab[i].min, ++ rndtest_runs_tab[i].max); ++ rv = -1; ++ } else { ++ rndtest_report(rsp, 0, ++ "runs pass %s interval %d (%d < %d < %d)", ++ val ? "ones" : "zeros", ++ i + 1, rndtest_runs_tab[i].min, src[i], ++ rndtest_runs_tab[i].max); ++ } ++ } ++ return (rv); ++} ++ ++static int ++rndtest_longruns(struct rndtest_state *rsp) ++{ ++ int i, j, ones = 0, zeros = 0, maxones = 0, maxzeros = 0; ++ u_int8_t c; ++ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ c = rsp->rs_buf[i]; ++ for (j = 0; j < 8; j++, c <<= 1) { ++ if (c & 0x80) { ++ zeros = 0; ++ ones++; ++ if (ones > maxones) ++ maxones = ones; ++ } else { ++ ones = 0; ++ zeros++; ++ if (zeros > maxzeros) ++ maxzeros = zeros; ++ } ++ } ++ } ++ ++ if (maxones < 26 && maxzeros < 26) { ++ rndtest_report(rsp, 0, "longruns pass (%d ones, %d zeros)", ++ maxones, maxzeros); ++ return (0); ++ } else { ++ rndtest_report(rsp, 1, "longruns fail (%d ones, %d zeros)", ++ maxones, maxzeros); ++ rndstats.rst_longruns++; ++ return (-1); ++ } ++} ++ ++/* ++ * chi^2 test over 4 bits: (this is called the poker test in FIPS 140-2, ++ * but it is really the chi^2 test over 4 bits (the poker test as described ++ * by Knuth vol 2 is something different, and I take him as authoritative ++ * on nomenclature over NIST). ++ */ ++#define RNDTEST_CHI4_K 16 ++#define RNDTEST_CHI4_K_MASK (RNDTEST_CHI4_K - 1) ++ ++/* ++ * The unnormalized values are used so that we don't have to worry about ++ * fractional precision. The "real" value is found by: ++ * (V - 1562500) * (16 / 5000) = Vn (where V is the unnormalized value) ++ */ ++#define RNDTEST_CHI4_VMIN 1563181 /* 2.1792 */ ++#define RNDTEST_CHI4_VMAX 1576929 /* 46.1728 */ ++ ++static int ++rndtest_chi_4(struct rndtest_state *rsp) ++{ ++ unsigned int freq[RNDTEST_CHI4_K], i, sum; ++ ++ for (i = 0; i < RNDTEST_CHI4_K; i++) ++ freq[i] = 0; ++ ++ /* Get number of occurances of each 4 bit pattern */ ++ for (i = 0; i < RNDTEST_NBYTES; i++) { ++ freq[(rsp->rs_buf[i] >> 4) & RNDTEST_CHI4_K_MASK]++; ++ freq[(rsp->rs_buf[i] >> 0) & RNDTEST_CHI4_K_MASK]++; ++ } ++ ++ for (i = 0, sum = 0; i < RNDTEST_CHI4_K; i++) ++ sum += freq[i] * freq[i]; ++ ++ if (sum >= 1563181 && sum <= 1576929) { ++ rndtest_report(rsp, 0, "chi^2(4): pass (sum %u)", sum); ++ return (0); ++ } else { ++ rndtest_report(rsp, 1, "chi^2(4): failed (sum %u)", sum); ++ rndstats.rst_chi++; ++ return (-1); ++ } ++} ++ ++int ++rndtest_buf(unsigned char *buf) ++{ ++ struct rndtest_state rsp; ++ ++ memset(&rsp, 0, sizeof(rsp)); ++ rsp.rs_buf = buf; ++ rndtest_test(&rsp); ++ return(rsp.rs_discard); ++} ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/rndtest.h linux-2.6.30/crypto/ocf/rndtest.h +--- linux-2.6.30.orig/crypto/ocf/rndtest.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/rndtest.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* $FreeBSD: src/sys/dev/rndtest/rndtest.h,v 1.1 2003/03/11 22:54:44 sam Exp $ */ ++/* $OpenBSD$ */ ++ ++/* ++ * Copyright (c) 2002 Jason L. Wright (jason@thought.net) ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Jason L. Wright ++ * 4. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ++ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/* Some of the tests depend on these values */ ++#define RNDTEST_NBYTES 2500 ++#define RNDTEST_NBITS (8 * RNDTEST_NBYTES) ++ ++struct rndtest_state { ++ int rs_discard; /* discard/accept random data */ ++ u_int8_t *rs_buf; ++}; ++ ++struct rndtest_stats { ++ u_int32_t rst_discard; /* number of bytes discarded */ ++ u_int32_t rst_tests; /* number of test runs */ ++ u_int32_t rst_monobit; /* monobit test failures */ ++ u_int32_t rst_runs; /* 0/1 runs failures */ ++ u_int32_t rst_longruns; /* longruns failures */ ++ u_int32_t rst_chi; /* chi^2 failures */ ++}; ++ ++extern int rndtest_buf(unsigned char *buf); +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/Makefile linux-2.6.30/crypto/ocf/safe/Makefile +--- linux-2.6.30.orig/crypto/ocf/safe/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_SAFE) += safe.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/md5.c linux-2.6.30/crypto/ocf/safe/md5.c +--- linux-2.6.30.orig/crypto/ocf/safe/md5.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/md5.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,308 @@ ++/* $KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/crypto/md5.c,v 1.9 2004/01/27 19:49:19 des Exp $"); ++ ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) ++ ++#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z))) ++#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z))) ++#define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) ++#define I(X, Y, Z) ((Y) ^ ((X) | (~Z))) ++ ++#define ROUND1(a, b, c, d, k, s, i) { \ ++ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND2(a, b, c, d, k, s, i) { \ ++ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND3(a, b, c, d, k, s, i) { \ ++ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define ROUND4(a, b, c, d, k, s, i) { \ ++ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ ++ (a) = SHIFT((a), (s)); \ ++ (a) = (b) + (a); \ ++} ++ ++#define Sa 7 ++#define Sb 12 ++#define Sc 17 ++#define Sd 22 ++ ++#define Se 5 ++#define Sf 9 ++#define Sg 14 ++#define Sh 20 ++ ++#define Si 4 ++#define Sj 11 ++#define Sk 16 ++#define Sl 23 ++ ++#define Sm 6 ++#define Sn 10 ++#define So 15 ++#define Sp 21 ++ ++#define MD5_A0 0x67452301 ++#define MD5_B0 0xefcdab89 ++#define MD5_C0 0x98badcfe ++#define MD5_D0 0x10325476 ++ ++/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ ++static const u_int32_t T[65] = { ++ 0, ++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, ++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, ++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, ++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, ++ ++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, ++ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, ++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, ++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, ++ ++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, ++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, ++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, ++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, ++ ++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, ++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, ++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, ++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, ++}; ++ ++static const u_int8_t md5_paddat[MD5_BUFLEN] = { ++ 0x80, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++static void md5_calc(u_int8_t *, md5_ctxt *); ++ ++void md5_init(ctxt) ++ md5_ctxt *ctxt; ++{ ++ ctxt->md5_n = 0; ++ ctxt->md5_i = 0; ++ ctxt->md5_sta = MD5_A0; ++ ctxt->md5_stb = MD5_B0; ++ ctxt->md5_stc = MD5_C0; ++ ctxt->md5_std = MD5_D0; ++ bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); ++} ++ ++void md5_loop(ctxt, input, len) ++ md5_ctxt *ctxt; ++ u_int8_t *input; ++ u_int len; /* number of bytes */ ++{ ++ u_int gap, i; ++ ++ ctxt->md5_n += len * 8; /* byte to bit */ ++ gap = MD5_BUFLEN - ctxt->md5_i; ++ ++ if (len >= gap) { ++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap); ++ md5_calc(ctxt->md5_buf, ctxt); ++ ++ for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { ++ md5_calc((u_int8_t *)(input + i), ctxt); ++ } ++ ++ ctxt->md5_i = len - i; ++ bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); ++ } else { ++ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ len); ++ ctxt->md5_i += len; ++ } ++} ++ ++void md5_pad(ctxt) ++ md5_ctxt *ctxt; ++{ ++ u_int gap; ++ ++ /* Don't count up padding. Keep md5_n. */ ++ gap = MD5_BUFLEN - ctxt->md5_i; ++ if (gap > 8) { ++ bcopy(md5_paddat, ++ (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap - sizeof(ctxt->md5_n)); ++ } else { ++ /* including gap == 8 */ ++ bcopy(md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), ++ gap); ++ md5_calc(ctxt->md5_buf, ctxt); ++ bcopy((md5_paddat + gap), ++ (void *)ctxt->md5_buf, ++ MD5_BUFLEN - sizeof(ctxt->md5_n)); ++ } ++ ++ /* 8 byte word */ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ ctxt->md5_buf[56] = ctxt->md5_n8[7]; ++ ctxt->md5_buf[57] = ctxt->md5_n8[6]; ++ ctxt->md5_buf[58] = ctxt->md5_n8[5]; ++ ctxt->md5_buf[59] = ctxt->md5_n8[4]; ++ ctxt->md5_buf[60] = ctxt->md5_n8[3]; ++ ctxt->md5_buf[61] = ctxt->md5_n8[2]; ++ ctxt->md5_buf[62] = ctxt->md5_n8[1]; ++ ctxt->md5_buf[63] = ctxt->md5_n8[0]; ++#endif ++ ++ md5_calc(ctxt->md5_buf, ctxt); ++} ++ ++void md5_result(digest, ctxt) ++ u_int8_t *digest; ++ md5_ctxt *ctxt; ++{ ++ /* 4 byte words */ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ bcopy(&ctxt->md5_st8[0], digest, 16); ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; ++ digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; ++ digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; ++ digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; ++ digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; ++ digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; ++ digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; ++ digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; ++#endif ++} ++ ++static void md5_calc(b64, ctxt) ++ u_int8_t *b64; ++ md5_ctxt *ctxt; ++{ ++ u_int32_t A = ctxt->md5_sta; ++ u_int32_t B = ctxt->md5_stb; ++ u_int32_t C = ctxt->md5_stc; ++ u_int32_t D = ctxt->md5_std; ++#if BYTE_ORDER == LITTLE_ENDIAN ++ u_int32_t *X = (u_int32_t *)b64; ++#endif ++#if BYTE_ORDER == BIG_ENDIAN ++ /* 4 byte words */ ++ /* what a brute force but fast! */ ++ u_int32_t X[16]; ++ u_int8_t *y = (u_int8_t *)X; ++ y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; ++ y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; ++ y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; ++ y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; ++ y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; ++ y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; ++ y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; ++ y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; ++ y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; ++ y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; ++ y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; ++ y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; ++ y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; ++ y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; ++ y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; ++ y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; ++#endif ++ ++ ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); ++ ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); ++ ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); ++ ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); ++ ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); ++ ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); ++ ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); ++ ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); ++ ++ ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); ++ ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); ++ ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); ++ ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); ++ ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); ++ ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); ++ ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); ++ ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); ++ ++ ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); ++ ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); ++ ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); ++ ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); ++ ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); ++ ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); ++ ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); ++ ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); ++ ++ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); ++ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); ++ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); ++ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); ++ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); ++ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); ++ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); ++ ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); ++ ++ ctxt->md5_sta += A; ++ ctxt->md5_stb += B; ++ ctxt->md5_stc += C; ++ ctxt->md5_std += D; ++} +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/md5.h linux-2.6.30/crypto/ocf/safe/md5.h +--- linux-2.6.30.orig/crypto/ocf/safe/md5.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/md5.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* $FreeBSD: src/sys/crypto/md5.h,v 1.4 2002/03/20 05:13:50 alfred Exp $ */ ++/* $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $ */ ++ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#ifndef _NETINET6_MD5_H_ ++#define _NETINET6_MD5_H_ ++ ++#define MD5_BUFLEN 64 ++ ++typedef struct { ++ union { ++ u_int32_t md5_state32[4]; ++ u_int8_t md5_state8[16]; ++ } md5_st; ++ ++#define md5_sta md5_st.md5_state32[0] ++#define md5_stb md5_st.md5_state32[1] ++#define md5_stc md5_st.md5_state32[2] ++#define md5_std md5_st.md5_state32[3] ++#define md5_st8 md5_st.md5_state8 ++ ++ union { ++ u_int64_t md5_count64; ++ u_int8_t md5_count8[8]; ++ } md5_count; ++#define md5_n md5_count.md5_count64 ++#define md5_n8 md5_count.md5_count8 ++ ++ u_int md5_i; ++ u_int8_t md5_buf[MD5_BUFLEN]; ++} md5_ctxt; ++ ++extern void md5_init(md5_ctxt *); ++extern void md5_loop(md5_ctxt *, u_int8_t *, u_int); ++extern void md5_pad(md5_ctxt *); ++extern void md5_result(u_int8_t *, md5_ctxt *); ++ ++/* compatibility */ ++#define MD5_CTX md5_ctxt ++#define MD5Init(x) md5_init((x)) ++#define MD5Update(x, y, z) md5_loop((x), (y), (z)) ++#define MD5Final(x, y) \ ++do { \ ++ md5_pad((y)); \ ++ md5_result((x), (y)); \ ++} while (0) ++ ++#endif /* ! _NETINET6_MD5_H_*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safe.c linux-2.6.30/crypto/ocf/safe/safe.c +--- linux-2.6.30.orig/crypto/ocf/safe/safe.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safe.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,2288 @@ ++/*- ++ * Linux port done by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++__FBSDID("$FreeBSD: src/sys/dev/safe/safe.c,v 1.18 2007/03/21 03:42:50 sam Exp $"); ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * SafeNet SafeXcel-1141 hardware crypto accelerator ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#if 1 ++#define DPRINTF(a) do { \ ++ if (debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_dev) : "safe"); \ ++ printk a; \ ++ } \ ++ } while (0) ++#else ++#define DPRINTF(a) ++#endif ++ ++/* ++ * until we find a cleaner way, include the BSD md5/sha1 code ++ * here ++ */ ++#define HMAC_HACK 1 ++#ifdef HMAC_HACK ++#define LITTLE_ENDIAN 1234 ++#define BIG_ENDIAN 4321 ++#ifdef __LITTLE_ENDIAN ++#define BYTE_ORDER LITTLE_ENDIAN ++#endif ++#ifdef __BIG_ENDIAN ++#define BYTE_ORDER BIG_ENDIAN ++#endif ++#include ++#include ++#include ++#include ++ ++u_int8_t hmac_ipad_buffer[64] = { ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 ++}; ++ ++u_int8_t hmac_opad_buffer[64] = { ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, ++ 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C ++}; ++#endif /* HMAC_HACK */ ++ ++/* add proc entry for this */ ++struct safe_stats safestats; ++ ++#define debug safe_debug ++int safe_debug = 0; ++module_param(safe_debug, int, 0644); ++MODULE_PARM_DESC(safe_debug, "Enable debug"); ++ ++static void safe_callback(struct safe_softc *, struct safe_ringentry *); ++static void safe_feed(struct safe_softc *, struct safe_ringentry *); ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++static void safe_rng_init(struct safe_softc *); ++int safe_rngbufsize = 8; /* 32 bytes each read */ ++module_param(safe_rngbufsize, int, 0644); ++MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)"); ++int safe_rngmaxalarm = 8; /* max alarms before reset */ ++module_param(safe_rngmaxalarm, int, 0644); ++MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset"); ++#endif /* SAFE_NO_RNG */ ++ ++static void safe_totalreset(struct safe_softc *sc); ++static int safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op); ++static int safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op); ++static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re); ++static int safe_kprocess(device_t dev, struct cryptkop *krp, int hint); ++static int safe_kstart(struct safe_softc *sc); ++static int safe_ksigbits(struct safe_softc *sc, struct crparam *cr); ++static void safe_kfeed(struct safe_softc *sc); ++static void safe_kpoll(unsigned long arg); ++static void safe_kload_reg(struct safe_softc *sc, u_int32_t off, ++ u_int32_t len, struct crparam *n); ++ ++static int safe_newsession(device_t, u_int32_t *, struct cryptoini *); ++static int safe_freesession(device_t, u_int64_t); ++static int safe_process(device_t, struct cryptop *, int); ++ ++static device_method_t safe_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, safe_newsession), ++ DEVMETHOD(cryptodev_freesession,safe_freesession), ++ DEVMETHOD(cryptodev_process, safe_process), ++ DEVMETHOD(cryptodev_kprocess, safe_kprocess), ++}; ++ ++#define READ_REG(sc,r) readl((sc)->sc_base_addr + (r)) ++#define WRITE_REG(sc,r,val) writel((val), (sc)->sc_base_addr + (r)) ++ ++#define SAFE_MAX_CHIPS 8 ++static struct safe_softc *safe_chip_idx[SAFE_MAX_CHIPS]; ++ ++/* ++ * split our buffers up into safe DMAable byte fragments to avoid lockup ++ * bug in 1141 HW on rev 1.0. ++ */ ++ ++static int ++pci_map_linear( ++ struct safe_softc *sc, ++ struct safe_operand *buf, ++ void *addr, ++ int len) ++{ ++ dma_addr_t tmp; ++ int chunk, tlen = len; ++ ++ tmp = pci_map_single(sc->sc_pcidev, addr, len, PCI_DMA_BIDIRECTIONAL); ++ ++ buf->mapsize += len; ++ while (len > 0) { ++ chunk = (len > sc->sc_max_dsize) ? sc->sc_max_dsize : len; ++ buf->segs[buf->nsegs].ds_addr = tmp; ++ buf->segs[buf->nsegs].ds_len = chunk; ++ buf->segs[buf->nsegs].ds_tlen = tlen; ++ buf->nsegs++; ++ tmp += chunk; ++ len -= chunk; ++ tlen = 0; ++ } ++ return 0; ++} ++ ++/* ++ * map in a given uio buffer (great on some arches :-) ++ */ ++ ++static int ++pci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio) ++{ ++ struct iovec *iov = uio->uio_iov; ++ int n; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ buf->mapsize = 0; ++ buf->nsegs = 0; ++ ++ for (n = 0; n < uio->uio_iovcnt; n++) { ++ pci_map_linear(sc, buf, iov->iov_base, iov->iov_len); ++ iov++; ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++/* ++ * map in a given sk_buff ++ */ ++ ++static int ++pci_map_skb(struct safe_softc *sc,struct safe_operand *buf,struct sk_buff *skb) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ buf->mapsize = 0; ++ buf->nsegs = 0; ++ ++ pci_map_linear(sc, buf, skb->data, skb_headlen(skb)); ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ pci_map_linear(sc, buf, ++ page_address(skb_shinfo(skb)->frags[i].page) + ++ skb_shinfo(skb)->frags[i].page_offset, ++ skb_shinfo(skb)->frags[i].size); ++ } ++ ++ /* identify this buffer by the first segment */ ++ buf->map = (void *) buf->segs[0].ds_addr; ++ return(0); ++} ++ ++ ++#if 0 /* not needed at this time */ ++static void ++pci_sync_operand(struct safe_softc *sc, struct safe_operand *buf) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ for (i = 0; i < buf->nsegs; i++) ++ pci_dma_sync_single_for_cpu(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); ++} ++#endif ++ ++static void ++pci_unmap_operand(struct safe_softc *sc, struct safe_operand *buf) ++{ ++ int i; ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ for (i = 0; i < buf->nsegs; i++) { ++ if (buf->segs[i].ds_tlen) { ++ DPRINTF(("%s - unmap %d 0x%x %d\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); ++ pci_unmap_single(sc->sc_pcidev, buf->segs[i].ds_addr, ++ buf->segs[i].ds_tlen, PCI_DMA_BIDIRECTIONAL); ++ DPRINTF(("%s - unmap %d 0x%x %d done\n", __FUNCTION__, i, buf->segs[i].ds_addr, buf->segs[i].ds_tlen)); ++ } ++ buf->segs[i].ds_addr = 0; ++ buf->segs[i].ds_len = 0; ++ buf->segs[i].ds_tlen = 0; ++ } ++ buf->nsegs = 0; ++ buf->mapsize = 0; ++ buf->map = 0; ++} ++ ++ ++/* ++ * SafeXcel Interrupt routine ++ */ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++safe_intr(int irq, void *arg) ++#else ++safe_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct safe_softc *sc = arg; ++ int stat; ++ unsigned long flags; ++ ++ stat = READ_REG(sc, SAFE_HM_STAT); ++ ++ DPRINTF(("%s(stat=0x%x)\n", __FUNCTION__, stat)); ++ ++ if (stat == 0) /* shared irq, not for us */ ++ return IRQ_NONE; ++ ++ WRITE_REG(sc, SAFE_HI_CLR, stat); /* IACK */ ++ ++ if ((stat & SAFE_INT_PE_DDONE)) { ++ /* ++ * Descriptor(s) done; scan the ring and ++ * process completed operations. ++ */ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ while (sc->sc_back != sc->sc_front) { ++ struct safe_ringentry *re = sc->sc_back; ++ ++#ifdef SAFE_DEBUG ++ if (debug) { ++ safe_dump_ringstate(sc, __func__); ++ safe_dump_request(sc, __func__, re); ++ } ++#endif ++ /* ++ * safe_process marks ring entries that were allocated ++ * but not used with a csr of zero. This insures the ++ * ring front pointer never needs to be set backwards ++ * in the event that an entry is allocated but not used ++ * because of a setup error. ++ */ ++ DPRINTF(("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr)); ++ if (re->re_desc.d_csr != 0) { ++ if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) { ++ DPRINTF(("%s !CSR_IS_DONE\n", __FUNCTION__)); ++ break; ++ } ++ if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) { ++ DPRINTF(("%s !LEN_IS_DONE\n", __FUNCTION__)); ++ break; ++ } ++ sc->sc_nqchip--; ++ safe_callback(sc, re); ++ } ++ if (++(sc->sc_back) == sc->sc_ringtop) ++ sc->sc_back = sc->sc_ring; ++ } ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ } ++ ++ /* ++ * Check to see if we got any DMA Error ++ */ ++ if (stat & SAFE_INT_PE_ERROR) { ++ printk("%s: dmaerr dmastat %08x\n", device_get_nameunit(sc->sc_dev), ++ (int)READ_REG(sc, SAFE_PE_DMASTAT)); ++ safestats.st_dmaerr++; ++ safe_totalreset(sc); ++#if 0 ++ safe_feed(sc); ++#endif ++ } ++ ++ if (sc->sc_needwakeup) { /* XXX check high watermark */ ++ int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); ++ DPRINTF(("%s: wakeup crypto %x\n", __func__, ++ sc->sc_needwakeup)); ++ sc->sc_needwakeup &= ~wakeup; ++ crypto_unblock(sc->sc_cid, wakeup); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * safe_feed() - post a request to chip ++ */ ++static void ++safe_feed(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++#ifdef SAFE_DEBUG ++ if (debug) { ++ safe_dump_ringstate(sc, __func__); ++ safe_dump_request(sc, __func__, re); ++ } ++#endif ++ sc->sc_nqchip++; ++ if (sc->sc_nqchip > safestats.st_maxqchip) ++ safestats.st_maxqchip = sc->sc_nqchip; ++ /* poke h/w to check descriptor ring, any value can be written */ ++ WRITE_REG(sc, SAFE_HI_RD_DESCR, 0); ++} ++ ++#define N(a) (sizeof(a) / sizeof (a[0])) ++static void ++safe_setup_enckey(struct safe_session *ses, caddr_t key) ++{ ++ int i; ++ ++ bcopy(key, ses->ses_key, ses->ses_klen / 8); ++ ++ /* PE is little-endian, insure proper byte order */ ++ for (i = 0; i < N(ses->ses_key); i++) ++ ses->ses_key[i] = htole32(ses->ses_key[i]); ++} ++ ++static void ++safe_setup_mackey(struct safe_session *ses, int algo, caddr_t key, int klen) ++{ ++#ifdef HMAC_HACK ++ MD5_CTX md5ctx; ++ SHA1_CTX sha1ctx; ++ int i; ++ ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= HMAC_IPAD_VAL; ++ ++ if (algo == CRYPTO_MD5_HMAC) { ++ MD5Init(&md5ctx); ++ MD5Update(&md5ctx, key, klen); ++ MD5Update(&md5ctx, hmac_ipad_buffer, MD5_HMAC_BLOCK_LEN - klen); ++ bcopy(md5ctx.md5_st8, ses->ses_hminner, sizeof(md5ctx.md5_st8)); ++ } else { ++ SHA1Init(&sha1ctx); ++ SHA1Update(&sha1ctx, key, klen); ++ SHA1Update(&sha1ctx, hmac_ipad_buffer, ++ SHA1_HMAC_BLOCK_LEN - klen); ++ bcopy(sha1ctx.h.b32, ses->ses_hminner, sizeof(sha1ctx.h.b32)); ++ } ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); ++ ++ if (algo == CRYPTO_MD5_HMAC) { ++ MD5Init(&md5ctx); ++ MD5Update(&md5ctx, key, klen); ++ MD5Update(&md5ctx, hmac_opad_buffer, MD5_HMAC_BLOCK_LEN - klen); ++ bcopy(md5ctx.md5_st8, ses->ses_hmouter, sizeof(md5ctx.md5_st8)); ++ } else { ++ SHA1Init(&sha1ctx); ++ SHA1Update(&sha1ctx, key, klen); ++ SHA1Update(&sha1ctx, hmac_opad_buffer, ++ SHA1_HMAC_BLOCK_LEN - klen); ++ bcopy(sha1ctx.h.b32, ses->ses_hmouter, sizeof(sha1ctx.h.b32)); ++ } ++ ++ for (i = 0; i < klen; i++) ++ key[i] ^= HMAC_OPAD_VAL; ++ ++#if 0 ++ /* ++ * this code prevents SHA working on a BE host, ++ * so it is obviously wrong. I think the byte ++ * swap setup we do with the chip fixes this for us ++ */ ++ ++ /* PE is little-endian, insure proper byte order */ ++ for (i = 0; i < N(ses->ses_hminner); i++) { ++ ses->ses_hminner[i] = htole32(ses->ses_hminner[i]); ++ ses->ses_hmouter[i] = htole32(ses->ses_hmouter[i]); ++ } ++#endif ++#else /* HMAC_HACK */ ++ printk("safe: md5/sha not implemented\n"); ++#endif /* HMAC_HACK */ ++} ++#undef N ++ ++/* ++ * Allocate a new 'session' and return an encoded session id. 'sidp' ++ * contains our registration id, and should contain an encoded session ++ * id on successful allocation. ++ */ ++static int ++safe_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct safe_session *ses = NULL; ++ int sesn; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sidp == NULL || cri == NULL || sc == NULL) ++ return (EINVAL); ++ ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (c->cri_alg == CRYPTO_MD5_HMAC || ++ c->cri_alg == CRYPTO_SHA1_HMAC || ++ c->cri_alg == CRYPTO_NULL_HMAC) { ++ if (macini) ++ return (EINVAL); ++ macini = c; ++ } else if (c->cri_alg == CRYPTO_DES_CBC || ++ c->cri_alg == CRYPTO_3DES_CBC || ++ c->cri_alg == CRYPTO_AES_CBC || ++ c->cri_alg == CRYPTO_NULL_CBC) { ++ if (encini) ++ return (EINVAL); ++ encini = c; ++ } else ++ return (EINVAL); ++ } ++ if (encini == NULL && macini == NULL) ++ return (EINVAL); ++ if (encini) { /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return (EINVAL); ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) ++ return (EINVAL); ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return (EINVAL); ++ break; ++ } ++ } ++ ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct safe_session *) ++ kmalloc(sizeof(struct safe_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return (ENOMEM); ++ memset(ses, 0, sizeof(struct safe_session)); ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn].ses_used == 0) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ sesn = sc->sc_nsessions; ++ ses = (struct safe_session *) ++ kmalloc((sesn + 1) * sizeof(struct safe_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return (ENOMEM); ++ memset(ses, 0, (sesn + 1) * sizeof(struct safe_session)); ++ bcopy(sc->sc_sessions, ses, sesn * ++ sizeof(struct safe_session)); ++ bzero(sc->sc_sessions, sesn * ++ sizeof(struct safe_session)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ ++ bzero(ses, sizeof(struct safe_session)); ++ ses->ses_used = 1; ++ ++ if (encini) { ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ read_random(ses->ses_iv, sizeof(ses->ses_iv)); ++ ++ ses->ses_klen = encini->cri_klen; ++ if (encini->cri_key != NULL) ++ safe_setup_enckey(ses, encini->cri_key); ++ } ++ ++ if (macini) { ++ ses->ses_mlen = macini->cri_mlen; ++ if (ses->ses_mlen == 0) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC) ++ ses->ses_mlen = MD5_HASH_LEN; ++ else ++ ses->ses_mlen = SHA1_HASH_LEN; ++ } ++ ++ if (macini->cri_key != NULL) { ++ safe_setup_mackey(ses, macini->cri_alg, macini->cri_key, ++ macini->cri_klen / 8); ++ } ++ } ++ ++ *sidp = SAFE_SID(device_get_unit(sc->sc_dev), sesn); ++ return (0); ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++safe_freesession(device_t dev, u_int64_t tid) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ int session, ret; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc == NULL) ++ return (EINVAL); ++ ++ session = SAFE_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session])); ++ ret = 0; ++ } else ++ ret = EINVAL; ++ return (ret); ++} ++ ++ ++static int ++safe_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ int err = 0, i, nicealign, uniform; ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ int bypass, oplen, ivsize; ++ caddr_t iv; ++ int16_t coffset; ++ struct safe_session *ses; ++ struct safe_ringentry *re; ++ struct safe_sarec *sa; ++ struct safe_pdesc *pd; ++ u_int32_t cmd0, cmd1, staterec; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { ++ safestats.st_invalid++; ++ return (EINVAL); ++ } ++ if (SAFE_SESSION(crp->crp_sid) >= sc->sc_nsessions) { ++ safestats.st_badsession++; ++ return (EINVAL); ++ } ++ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ if (sc->sc_front == sc->sc_back && sc->sc_nqchip != 0) { ++ safestats.st_ringfull++; ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ return (ERESTART); ++ } ++ re = sc->sc_front; ++ ++ staterec = re->re_sa.sa_staterec; /* save */ ++ /* NB: zero everything but the PE descriptor */ ++ bzero(&re->re_sa, sizeof(struct safe_ringentry) - sizeof(re->re_desc)); ++ re->re_sa.sa_staterec = staterec; /* restore */ ++ ++ re->re_crp = crp; ++ re->re_sesn = SAFE_SESSION(crp->crp_sid); ++ ++ re->re_src.nsegs = 0; ++ re->re_dst.nsegs = 0; ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ re->re_src_skb = (struct sk_buff *)crp->crp_buf; ++ re->re_dst_skb = (struct sk_buff *)crp->crp_buf; ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ re->re_src_io = (struct uio *)crp->crp_buf; ++ re->re_dst_io = (struct uio *)crp->crp_buf; ++ } else { ++ safestats.st_badflags++; ++ err = EINVAL; ++ goto errout; /* XXX we don't handle contiguous blocks! */ ++ } ++ ++ sa = &re->re_sa; ++ ses = &sc->sc_sessions[re->re_sesn]; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ safestats.st_nodesc++; ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ ++ cmd0 = SAFE_SA_CMD0_BASIC; /* basic group operation */ ++ cmd1 = 0; ++ if (crd2 == NULL) { ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_NULL_HMAC) { ++ maccrd = crd1; ++ enccrd = NULL; ++ cmd0 |= SAFE_SA_CMD0_OP_HASH; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_NULL_CBC) { ++ maccrd = NULL; ++ enccrd = crd1; ++ cmd0 |= SAFE_SA_CMD0_OP_CRYPT; ++ } else { ++ safestats.st_badalg++; ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_NULL_HMAC) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_NULL_CBC) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_NULL_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_NULL_HMAC) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ safestats.st_badalg++; ++ err = EINVAL; ++ goto errout; ++ } ++ cmd0 |= SAFE_SA_CMD0_OP_BOTH; ++ } ++ ++ if (enccrd) { ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) ++ safe_setup_enckey(ses, enccrd->crd_key); ++ ++ if (enccrd->crd_alg == CRYPTO_DES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_DES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (enccrd->crd_alg == CRYPTO_3DES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_3DES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (enccrd->crd_alg == CRYPTO_AES_CBC) { ++ cmd0 |= SAFE_SA_CMD0_AES; ++ cmd1 |= SAFE_SA_CMD1_CBC; ++ if (ses->ses_klen == 128) ++ cmd1 |= SAFE_SA_CMD1_AES128; ++ else if (ses->ses_klen == 192) ++ cmd1 |= SAFE_SA_CMD1_AES192; ++ else ++ cmd1 |= SAFE_SA_CMD1_AES256; ++ ivsize = 4*sizeof(u_int32_t); ++ } else { ++ cmd0 |= SAFE_SA_CMD0_CRYPT_NULL; ++ ivsize = 0; ++ } ++ ++ /* ++ * Setup encrypt/decrypt state. When using basic ops ++ * we can't use an inline IV because hash/crypt offset ++ * must be from the end of the IV to the start of the ++ * crypt data and this leaves out the preceding header ++ * from the hash calculation. Instead we place the IV ++ * in the state record and set the hash/crypt offset to ++ * copy both the header+IV. ++ */ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ cmd0 |= SAFE_SA_CMD0_OUTBOUND; ++ ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ iv = enccrd->crd_iv; ++ else ++ iv = (caddr_t) ses->ses_iv; ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ bcopy(iv, re->re_sastate.sa_saved_iv, ivsize); ++ /* make iv LE */ ++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) ++ re->re_sastate.sa_saved_iv[i] = ++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]); ++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE | SAFE_SA_CMD0_SAVEIV; ++ re->re_flags |= SAFE_QFLAGS_COPYOUTIV; ++ } else { ++ cmd0 |= SAFE_SA_CMD0_INBOUND; ++ ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ bcopy(enccrd->crd_iv, ++ re->re_sastate.sa_saved_iv, ivsize); ++ } else { ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, ++ (caddr_t)re->re_sastate.sa_saved_iv); ++ } ++ /* make iv LE */ ++ for (i = 0; i < ivsize/sizeof(re->re_sastate.sa_saved_iv[0]); i++) ++ re->re_sastate.sa_saved_iv[i] = ++ cpu_to_le32(re->re_sastate.sa_saved_iv[i]); ++ cmd0 |= SAFE_SA_CMD0_IVLD_STATE; ++ } ++ /* ++ * For basic encryption use the zero pad algorithm. ++ * This pads results to an 8-byte boundary and ++ * suppresses padding verification for inbound (i.e. ++ * decrypt) operations. ++ * ++ * NB: Not sure if the 8-byte pad boundary is a problem. ++ */ ++ cmd0 |= SAFE_SA_CMD0_PAD_ZERO; ++ ++ /* XXX assert key bufs have the same size */ ++ bcopy(ses->ses_key, sa->sa_key, sizeof(sa->sa_key)); ++ } ++ ++ if (maccrd) { ++ if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ safe_setup_mackey(ses, maccrd->crd_alg, ++ maccrd->crd_key, maccrd->crd_klen / 8); ++ } ++ ++ if (maccrd->crd_alg == CRYPTO_MD5_HMAC) { ++ cmd0 |= SAFE_SA_CMD0_MD5; ++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ ++ } else if (maccrd->crd_alg == CRYPTO_SHA1_HMAC) { ++ cmd0 |= SAFE_SA_CMD0_SHA1; ++ cmd1 |= SAFE_SA_CMD1_HMAC; /* NB: enable HMAC */ ++ } else { ++ cmd0 |= SAFE_SA_CMD0_HASH_NULL; ++ } ++ /* ++ * Digest data is loaded from the SA and the hash ++ * result is saved to the state block where we ++ * retrieve it for return to the caller. ++ */ ++ /* XXX assert digest bufs have the same size */ ++ bcopy(ses->ses_hminner, sa->sa_indigest, ++ sizeof(sa->sa_indigest)); ++ bcopy(ses->ses_hmouter, sa->sa_outdigest, ++ sizeof(sa->sa_outdigest)); ++ ++ cmd0 |= SAFE_SA_CMD0_HSLD_SA | SAFE_SA_CMD0_SAVEHASH; ++ re->re_flags |= SAFE_QFLAGS_COPYOUTICV; ++ } ++ ++ if (enccrd && maccrd) { ++ /* ++ * The offset from hash data to the start of ++ * crypt data is the difference in the skips. ++ */ ++ bypass = maccrd->crd_skip; ++ coffset = enccrd->crd_skip - maccrd->crd_skip; ++ if (coffset < 0) { ++ DPRINTF(("%s: hash does not precede crypt; " ++ "mac skip %u enc skip %u\n", ++ __func__, maccrd->crd_skip, enccrd->crd_skip)); ++ safestats.st_skipmismatch++; ++ err = EINVAL; ++ goto errout; ++ } ++ oplen = enccrd->crd_skip + enccrd->crd_len; ++ if (maccrd->crd_skip + maccrd->crd_len != oplen) { ++ DPRINTF(("%s: hash amount %u != crypt amount %u\n", ++ __func__, maccrd->crd_skip + maccrd->crd_len, ++ oplen)); ++ safestats.st_lenmismatch++; ++ err = EINVAL; ++ goto errout; ++ } ++#ifdef SAFE_DEBUG ++ if (debug) { ++ printf("mac: skip %d, len %d, inject %d\n", ++ maccrd->crd_skip, maccrd->crd_len, ++ maccrd->crd_inject); ++ printf("enc: skip %d, len %d, inject %d\n", ++ enccrd->crd_skip, enccrd->crd_len, ++ enccrd->crd_inject); ++ printf("bypass %d coffset %d oplen %d\n", ++ bypass, coffset, oplen); ++ } ++#endif ++ if (coffset & 3) { /* offset must be 32-bit aligned */ ++ DPRINTF(("%s: coffset %u misaligned\n", ++ __func__, coffset)); ++ safestats.st_coffmisaligned++; ++ err = EINVAL; ++ goto errout; ++ } ++ coffset >>= 2; ++ if (coffset > 255) { /* offset must be <256 dwords */ ++ DPRINTF(("%s: coffset %u too big\n", ++ __func__, coffset)); ++ safestats.st_cofftoobig++; ++ err = EINVAL; ++ goto errout; ++ } ++ /* ++ * Tell the hardware to copy the header to the output. ++ * The header is defined as the data from the end of ++ * the bypass to the start of data to be encrypted. ++ * Typically this is the inline IV. Note that you need ++ * to do this even if src+dst are the same; it appears ++ * that w/o this bit the crypted data is written ++ * immediately after the bypass data. ++ */ ++ cmd1 |= SAFE_SA_CMD1_HDRCOPY; ++ /* ++ * Disable IP header mutable bit handling. This is ++ * needed to get correct HMAC calculations. ++ */ ++ cmd1 |= SAFE_SA_CMD1_MUTABLE; ++ } else { ++ if (enccrd) { ++ bypass = enccrd->crd_skip; ++ oplen = bypass + enccrd->crd_len; ++ } else { ++ bypass = maccrd->crd_skip; ++ oplen = bypass + maccrd->crd_len; ++ } ++ coffset = 0; ++ } ++ /* XXX verify multiple of 4 when using s/g */ ++ if (bypass > 96) { /* bypass offset must be <= 96 bytes */ ++ DPRINTF(("%s: bypass %u too big\n", __func__, bypass)); ++ safestats.st_bypasstoobig++; ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ if (pci_map_skb(sc, &re->re_src, re->re_src_skb)) { ++ safestats.st_noload++; ++ err = ENOMEM; ++ goto errout; ++ } ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ if (pci_map_uio(sc, &re->re_src, re->re_src_io)) { ++ safestats.st_noload++; ++ err = ENOMEM; ++ goto errout; ++ } ++ } ++ nicealign = safe_dmamap_aligned(sc, &re->re_src); ++ uniform = safe_dmamap_uniform(sc, &re->re_src); ++ ++ DPRINTF(("src nicealign %u uniform %u nsegs %u\n", ++ nicealign, uniform, re->re_src.nsegs)); ++ if (re->re_src.nsegs > 1) { ++ re->re_desc.d_src = sc->sc_spalloc.dma_paddr + ++ ((caddr_t) sc->sc_spfree - (caddr_t) sc->sc_spring); ++ for (i = 0; i < re->re_src_nsegs; i++) { ++ /* NB: no need to check if there's space */ ++ pd = sc->sc_spfree; ++ if (++(sc->sc_spfree) == sc->sc_springtop) ++ sc->sc_spfree = sc->sc_spring; ++ ++ KASSERT((pd->pd_flags&3) == 0 || ++ (pd->pd_flags&3) == SAFE_PD_DONE, ++ ("bogus source particle descriptor; flags %x", ++ pd->pd_flags)); ++ pd->pd_addr = re->re_src_segs[i].ds_addr; ++ pd->pd_size = re->re_src_segs[i].ds_len; ++ pd->pd_flags = SAFE_PD_READY; ++ } ++ cmd0 |= SAFE_SA_CMD0_IGATHER; ++ } else { ++ /* ++ * No need for gather, reference the operand directly. ++ */ ++ re->re_desc.d_src = re->re_src_segs[0].ds_addr; ++ } ++ ++ if (enccrd == NULL && maccrd != NULL) { ++ /* ++ * Hash op; no destination needed. ++ */ ++ } else { ++ if (crp->crp_flags & (CRYPTO_F_IOV|CRYPTO_F_SKBUF)) { ++ if (!nicealign) { ++ safestats.st_iovmisaligned++; ++ err = EINVAL; ++ goto errout; ++ } ++ if (uniform != 1) { ++ device_printf(sc->sc_dev, "!uniform source\n"); ++ if (!uniform) { ++ /* ++ * There's no way to handle the DMA ++ * requirements with this uio. We ++ * could create a separate DMA area for ++ * the result and then copy it back, ++ * but for now we just bail and return ++ * an error. Note that uio requests ++ * > SAFE_MAX_DSIZE are handled because ++ * the DMA map and segment list for the ++ * destination wil result in a ++ * destination particle list that does ++ * the necessary scatter DMA. ++ */ ++ safestats.st_iovnotuniform++; ++ err = EINVAL; ++ goto errout; ++ } ++ } else ++ re->re_dst = re->re_src; ++ } else { ++ safestats.st_badflags++; ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (re->re_dst.nsegs > 1) { ++ re->re_desc.d_dst = sc->sc_dpalloc.dma_paddr + ++ ((caddr_t) sc->sc_dpfree - (caddr_t) sc->sc_dpring); ++ for (i = 0; i < re->re_dst_nsegs; i++) { ++ pd = sc->sc_dpfree; ++ KASSERT((pd->pd_flags&3) == 0 || ++ (pd->pd_flags&3) == SAFE_PD_DONE, ++ ("bogus dest particle descriptor; flags %x", ++ pd->pd_flags)); ++ if (++(sc->sc_dpfree) == sc->sc_dpringtop) ++ sc->sc_dpfree = sc->sc_dpring; ++ pd->pd_addr = re->re_dst_segs[i].ds_addr; ++ pd->pd_flags = SAFE_PD_READY; ++ } ++ cmd0 |= SAFE_SA_CMD0_OSCATTER; ++ } else { ++ /* ++ * No need for scatter, reference the operand directly. ++ */ ++ re->re_desc.d_dst = re->re_dst_segs[0].ds_addr; ++ } ++ } ++ ++ /* ++ * All done with setup; fillin the SA command words ++ * and the packet engine descriptor. The operation ++ * is now ready for submission to the hardware. ++ */ ++ sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI; ++ sa->sa_cmd1 = cmd1 ++ | (coffset << SAFE_SA_CMD1_OFFSET_S) ++ | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */ ++ | SAFE_SA_CMD1_SRPCI ++ ; ++ /* ++ * NB: the order of writes is important here. In case the ++ * chip is scanning the ring because of an outstanding request ++ * it might nab this one too. In that case we need to make ++ * sure the setup is complete before we write the length ++ * field of the descriptor as it signals the descriptor is ++ * ready for processing. ++ */ ++ re->re_desc.d_csr = SAFE_PE_CSR_READY | SAFE_PE_CSR_SAPCI; ++ if (maccrd) ++ re->re_desc.d_csr |= SAFE_PE_CSR_LOADSA | SAFE_PE_CSR_HASHFINAL; ++ wmb(); ++ re->re_desc.d_len = oplen ++ | SAFE_PE_LEN_READY ++ | (bypass << SAFE_PE_LEN_BYPASS_S) ++ ; ++ ++ safestats.st_ipackets++; ++ safestats.st_ibytes += oplen; ++ ++ if (++(sc->sc_front) == sc->sc_ringtop) ++ sc->sc_front = sc->sc_ring; ++ ++ /* XXX honor batching */ ++ safe_feed(sc, re); ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ return (0); ++ ++errout: ++ if (re->re_src.map != re->re_dst.map) ++ pci_unmap_operand(sc, &re->re_dst); ++ if (re->re_src.map) ++ pci_unmap_operand(sc, &re->re_src); ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } else { ++ sc->sc_needwakeup |= CRYPTO_SYMQ; ++ } ++ return (err); ++} ++ ++static void ++safe_callback(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ struct cryptop *crp = (struct cryptop *)re->re_crp; ++ struct cryptodesc *crd; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safestats.st_opackets++; ++ safestats.st_obytes += re->re_dst.mapsize; ++ ++ if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) { ++ device_printf(sc->sc_dev, "csr 0x%x cmd0 0x%x cmd1 0x%x\n", ++ re->re_desc.d_csr, ++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1); ++ safestats.st_peoperr++; ++ crp->crp_etype = EIO; /* something more meaningful? */ ++ } ++ ++ if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map) ++ pci_unmap_operand(sc, &re->re_dst); ++ pci_unmap_operand(sc, &re->re_src); ++ ++ /* ++ * If result was written to a differet mbuf chain, swap ++ * it in as the return value and reclaim the original. ++ */ ++ if ((crp->crp_flags & CRYPTO_F_SKBUF) && re->re_src_skb != re->re_dst_skb) { ++ device_printf(sc->sc_dev, "no CRYPTO_F_SKBUF swapping support\n"); ++ /* kfree_skb(skb) */ ++ /* crp->crp_buf = (caddr_t)re->re_dst_skb */ ++ return; ++ } ++ ++ if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) { ++ /* copy out IV for future use */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ int i; ++ int ivsize; ++ ++ if (crd->crd_alg == CRYPTO_DES_CBC || ++ crd->crd_alg == CRYPTO_3DES_CBC) { ++ ivsize = 2*sizeof(u_int32_t); ++ } else if (crd->crd_alg == CRYPTO_AES_CBC) { ++ ivsize = 4*sizeof(u_int32_t); ++ } else ++ continue; ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ crd->crd_skip + crd->crd_len - ivsize, ivsize, ++ (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv); ++ for (i = 0; ++ i < ivsize/sizeof(sc->sc_sessions[re->re_sesn].ses_iv[0]); ++ i++) ++ sc->sc_sessions[re->re_sesn].ses_iv[i] = ++ cpu_to_le32(sc->sc_sessions[re->re_sesn].ses_iv[i]); ++ break; ++ } ++ } ++ ++ if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) { ++ /* copy out ICV result */ ++ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { ++ if (!(crd->crd_alg == CRYPTO_MD5_HMAC || ++ crd->crd_alg == CRYPTO_SHA1_HMAC || ++ crd->crd_alg == CRYPTO_NULL_HMAC)) ++ continue; ++ if (crd->crd_alg == CRYPTO_SHA1_HMAC) { ++ /* ++ * SHA-1 ICV's are byte-swapped; fix 'em up ++ * before copy them to their destination. ++ */ ++ re->re_sastate.sa_saved_indigest[0] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[0]); ++ re->re_sastate.sa_saved_indigest[1] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[1]); ++ re->re_sastate.sa_saved_indigest[2] = ++ cpu_to_be32(re->re_sastate.sa_saved_indigest[2]); ++ } else { ++ re->re_sastate.sa_saved_indigest[0] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[0]); ++ re->re_sastate.sa_saved_indigest[1] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[1]); ++ re->re_sastate.sa_saved_indigest[2] = ++ cpu_to_le32(re->re_sastate.sa_saved_indigest[2]); ++ } ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ crd->crd_inject, ++ sc->sc_sessions[re->re_sesn].ses_mlen, ++ (caddr_t)re->re_sastate.sa_saved_indigest); ++ break; ++ } ++ } ++ crypto_done(crp); ++} ++ ++ ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++#define SAFE_RNG_MAXWAIT 1000 ++ ++static void ++safe_rng_init(struct safe_softc *sc) ++{ ++ u_int32_t w, v; ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, 0); ++ /* use default value according to the manual */ ++ WRITE_REG(sc, SAFE_RNG_CNFG, 0x834); /* magic from SafeNet */ ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ /* ++ * There is a bug in rev 1.0 of the 1140 that when the RNG ++ * is brought out of reset the ready status flag does not ++ * work until the RNG has finished its internal initialization. ++ * ++ * So in order to determine the device is through its ++ * initialization we must read the data register, using the ++ * status reg in the read in case it is initialized. Then read ++ * the data register until it changes from the first read. ++ * Once it changes read the data register until it changes ++ * again. At this time the RNG is considered initialized. ++ * This could take between 750ms - 1000ms in time. ++ */ ++ i = 0; ++ w = READ_REG(sc, SAFE_RNG_OUT); ++ do { ++ v = READ_REG(sc, SAFE_RNG_OUT); ++ if (v != w) { ++ w = v; ++ break; ++ } ++ DELAY(10); ++ } while (++i < SAFE_RNG_MAXWAIT); ++ ++ /* Wait Until data changes again */ ++ i = 0; ++ do { ++ v = READ_REG(sc, SAFE_RNG_OUT); ++ if (v != w) ++ break; ++ DELAY(10); ++ } while (++i < SAFE_RNG_MAXWAIT); ++} ++ ++static __inline void ++safe_rng_disable_short_cycle(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, ++ READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN); ++} ++ ++static __inline void ++safe_rng_enable_short_cycle(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ WRITE_REG(sc, SAFE_RNG_CTRL, ++ READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN); ++} ++ ++static __inline u_int32_t ++safe_rng_read(struct safe_softc *sc) ++{ ++ int i; ++ ++ i = 0; ++ while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT) ++ ; ++ return READ_REG(sc, SAFE_RNG_OUT); ++} ++ ++static int ++safe_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ struct safe_softc *sc = (struct safe_softc *) arg; ++ int i, rc; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safestats.st_rng++; ++ /* ++ * Fetch the next block of data. ++ */ ++ if (maxwords > safe_rngbufsize) ++ maxwords = safe_rngbufsize; ++ if (maxwords > SAFE_RNG_MAXBUFSIZ) ++ maxwords = SAFE_RNG_MAXBUFSIZ; ++retry: ++ /* read as much as we can */ ++ for (rc = 0; rc < maxwords; rc++) { ++ if (READ_REG(sc, SAFE_RNG_STAT) != 0) ++ break; ++ buf[rc] = READ_REG(sc, SAFE_RNG_OUT); ++ } ++ if (rc == 0) ++ return 0; ++ /* ++ * Check the comparator alarm count and reset the h/w if ++ * it exceeds our threshold. This guards against the ++ * hardware oscillators resonating with external signals. ++ */ ++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) { ++ u_int32_t freq_inc, w; ++ ++ DPRINTF(("%s: alarm count %u exceeds threshold %u\n", __func__, ++ (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm)); ++ safestats.st_rngalarm++; ++ safe_rng_enable_short_cycle(sc); ++ freq_inc = 18; ++ for (i = 0; i < 64; i++) { ++ w = READ_REG(sc, SAFE_RNG_CNFG); ++ freq_inc = ((w + freq_inc) & 0x3fL); ++ w = ((w & ~0x3fL) | freq_inc); ++ WRITE_REG(sc, SAFE_RNG_CNFG, w); ++ ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ (void) safe_rng_read(sc); ++ DELAY(25); ++ ++ if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) { ++ safe_rng_disable_short_cycle(sc); ++ goto retry; ++ } ++ freq_inc = 1; ++ } ++ safe_rng_disable_short_cycle(sc); ++ } else ++ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); ++ ++ return(rc); ++} ++#endif /* defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) */ ++ ++ ++/* ++ * Resets the board. Values in the regesters are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++safe_reset_board(struct safe_softc *sc) ++{ ++ u_int32_t v; ++ /* ++ * Reset the device. The manual says no delay ++ * is needed between marking and clearing reset. ++ */ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ v = READ_REG(sc, SAFE_PE_DMACFG) &~ ++ (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET | ++ SAFE_PE_DMACFG_SGRESET); ++ WRITE_REG(sc, SAFE_PE_DMACFG, v ++ | SAFE_PE_DMACFG_PERESET ++ | SAFE_PE_DMACFG_PDRRESET ++ | SAFE_PE_DMACFG_SGRESET); ++ WRITE_REG(sc, SAFE_PE_DMACFG, v); ++} ++ ++/* ++ * Initialize registers we need to touch only once. ++ */ ++static void ++safe_init_board(struct safe_softc *sc) ++{ ++ u_int32_t v, dwords; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ v = READ_REG(sc, SAFE_PE_DMACFG); ++ v &=~ ( SAFE_PE_DMACFG_PEMODE ++ | SAFE_PE_DMACFG_FSENA /* failsafe enable */ ++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ ++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ ++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ ++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ ++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ ++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ ++ ); ++ v |= SAFE_PE_DMACFG_FSENA /* failsafe enable */ ++ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ ++ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ ++ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ ++ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ ++ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ ++#if 0 ++ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ ++#endif ++ ; ++ WRITE_REG(sc, SAFE_PE_DMACFG, v); ++ ++#ifdef __BIG_ENDIAN ++ /* tell the safenet that we are 4321 and not 1234 */ ++ WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b); ++#endif ++ ++ if (sc->sc_chiprev == SAFE_REV(1,0)) { ++ /* ++ * Avoid large PCI DMA transfers. Rev 1.0 has a bug where ++ * "target mode transfers" done while the chip is DMA'ing ++ * >1020 bytes cause the hardware to lockup. To avoid this ++ * we reduce the max PCI transfer size and use small source ++ * particle descriptors (<= 256 bytes). ++ */ ++ WRITE_REG(sc, SAFE_DMA_CFG, 256); ++ device_printf(sc->sc_dev, ++ "Reduce max DMA size to %u words for rev %u.%u WAR\n", ++ (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff), ++ (unsigned) SAFE_REV_MAJ(sc->sc_chiprev), ++ (unsigned) SAFE_REV_MIN(sc->sc_chiprev)); ++ sc->sc_max_dsize = 256; ++ } else { ++ sc->sc_max_dsize = SAFE_MAX_DSIZE; ++ } ++ ++ /* NB: operands+results are overlaid */ ++ WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ringalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ringalloc.dma_paddr); ++ /* ++ * Configure ring entry size and number of items in the ring. ++ */ ++ KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0, ++ ("PE ring entry not 32-bit aligned!")); ++ dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t); ++ WRITE_REG(sc, SAFE_PE_RINGCFG, ++ (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE); ++ WRITE_REG(sc, SAFE_PE_RINGPOLL, 0); /* disable polling */ ++ ++ WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_spalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dpalloc.dma_paddr); ++ WRITE_REG(sc, SAFE_PE_PARTSIZE, ++ (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART); ++ /* ++ * NB: destination particles are fixed size. We use ++ * an mbuf cluster and require all results go to ++ * clusters or smaller. ++ */ ++ WRITE_REG(sc, SAFE_PE_PARTCFG, sc->sc_max_dsize); ++ ++ /* it's now safe to enable PE mode, do it */ ++ WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE); ++ ++ /* ++ * Configure hardware to use level-triggered interrupts and ++ * to interrupt after each descriptor is processed. ++ */ ++ WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL); ++ WRITE_REG(sc, SAFE_HI_CLR, 0xffffffff); ++ WRITE_REG(sc, SAFE_HI_DESC_CNT, 1); ++ WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR); ++} ++ ++ ++/* ++ * Clean up after a chip crash. ++ * It is assumed that the caller in splimp() ++ */ ++static void ++safe_cleanchip(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc->sc_nqchip != 0) { ++ struct safe_ringentry *re = sc->sc_back; ++ ++ while (re != sc->sc_front) { ++ if (re->re_desc.d_csr != 0) ++ safe_free_entry(sc, re); ++ if (++re == sc->sc_ringtop) ++ re = sc->sc_ring; ++ } ++ sc->sc_back = re; ++ sc->sc_nqchip = 0; ++ } ++} ++ ++/* ++ * free a safe_q ++ * It is assumed that the caller is within splimp(). ++ */ ++static int ++safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re) ++{ ++ struct cryptop *crp; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ /* ++ * Free header MCR ++ */ ++ if ((re->re_dst_skb != NULL) && (re->re_src_skb != re->re_dst_skb)) ++#ifdef NOTYET ++ m_freem(re->re_dst_m); ++#else ++ printk("%s,%d: SKB not supported\n", __FILE__, __LINE__); ++#endif ++ ++ crp = (struct cryptop *)re->re_crp; ++ ++ re->re_desc.d_csr = 0; ++ ++ crp->crp_etype = EFAULT; ++ crypto_done(crp); ++ return(0); ++} ++ ++/* ++ * Routine to reset the chip and clean up. ++ * It is assumed that the caller is in splimp() ++ */ ++static void ++safe_totalreset(struct safe_softc *sc) ++{ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ safe_reset_board(sc); ++ safe_init_board(sc); ++ safe_cleanchip(sc); ++} ++ ++/* ++ * Is the operand suitable aligned for direct DMA. Each ++ * segment must be aligned on a 32-bit boundary and all ++ * but the last segment must be a multiple of 4 bytes. ++ */ ++static int ++safe_dmamap_aligned(struct safe_softc *sc, const struct safe_operand *op) ++{ ++ int i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ for (i = 0; i < op->nsegs; i++) { ++ if (op->segs[i].ds_addr & 3) ++ return (0); ++ if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3)) ++ return (0); ++ } ++ return (1); ++} ++ ++/* ++ * Is the operand suitable for direct DMA as the destination ++ * of an operation. The hardware requires that each ``particle'' ++ * but the last in an operation result have the same size. We ++ * fix that size at SAFE_MAX_DSIZE bytes. This routine returns ++ * 0 if some segment is not a multiple of of this size, 1 if all ++ * segments are exactly this size, or 2 if segments are at worst ++ * a multple of this size. ++ */ ++static int ++safe_dmamap_uniform(struct safe_softc *sc, const struct safe_operand *op) ++{ ++ int result = 1; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (op->nsegs > 0) { ++ int i; ++ ++ for (i = 0; i < op->nsegs-1; i++) { ++ if (op->segs[i].ds_len % sc->sc_max_dsize) ++ return (0); ++ if (op->segs[i].ds_len != sc->sc_max_dsize) ++ result = 2; ++ } ++ } ++ return (result); ++} ++ ++static int ++safe_kprocess(device_t dev, struct cryptkop *krp, int hint) ++{ ++ struct safe_softc *sc = device_get_softc(dev); ++ struct safe_pkq *q; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (sc == NULL) { ++ krp->krp_status = EINVAL; ++ goto err; ++ } ++ ++ if (krp->krp_op != CRK_MOD_EXP) { ++ krp->krp_status = EOPNOTSUPP; ++ goto err; ++ } ++ ++ q = (struct safe_pkq *) kmalloc(sizeof(*q), GFP_KERNEL); ++ if (q == NULL) { ++ krp->krp_status = ENOMEM; ++ goto err; ++ } ++ memset(q, 0, sizeof(*q)); ++ q->pkq_krp = krp; ++ INIT_LIST_HEAD(&q->pkq_list); ++ ++ spin_lock_irqsave(&sc->sc_pkmtx, flags); ++ list_add_tail(&q->pkq_list, &sc->sc_pkq); ++ safe_kfeed(sc); ++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags); ++ return (0); ++ ++err: ++ crypto_kdone(krp); ++ return (0); ++} ++ ++#define SAFE_CRK_PARAM_BASE 0 ++#define SAFE_CRK_PARAM_EXP 1 ++#define SAFE_CRK_PARAM_MOD 2 ++ ++static int ++safe_kstart(struct safe_softc *sc) ++{ ++ struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp; ++ int exp_bits, mod_bits, base_bits; ++ u_int32_t op, a_off, b_off, c_off, d_off; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (krp->krp_iparams < 3 || krp->krp_oparams != 1) { ++ krp->krp_status = EINVAL; ++ return (1); ++ } ++ ++ base_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_BASE]); ++ if (base_bits > 2048) ++ goto too_big; ++ if (base_bits <= 0) /* 5. base not zero */ ++ goto too_small; ++ ++ exp_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_EXP]); ++ if (exp_bits > 2048) ++ goto too_big; ++ if (exp_bits <= 0) /* 1. exponent word length > 0 */ ++ goto too_small; /* 4. exponent not zero */ ++ ++ mod_bits = safe_ksigbits(sc, &krp->krp_param[SAFE_CRK_PARAM_MOD]); ++ if (mod_bits > 2048) ++ goto too_big; ++ if (mod_bits <= 32) /* 2. modulus word length > 1 */ ++ goto too_small; /* 8. MSW of modulus != zero */ ++ if (mod_bits < exp_bits) /* 3 modulus len >= exponent len */ ++ goto too_small; ++ if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0) ++ goto bad_domain; /* 6. modulus is odd */ ++ if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits) ++ goto too_small; /* make sure result will fit */ ++ ++ /* 7. modulus > base */ ++ if (mod_bits < base_bits) ++ goto too_small; ++ if (mod_bits == base_bits) { ++ u_int8_t *basep, *modp; ++ int i; ++ ++ basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p + ++ ((base_bits + 7) / 8) - 1; ++ modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p + ++ ((mod_bits + 7) / 8) - 1; ++ ++ for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) { ++ if (*modp < *basep) ++ goto too_small; ++ if (*modp > *basep) ++ break; ++ } ++ } ++ ++ /* And on the 9th step, he rested. */ ++ ++ WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32); ++ WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32); ++ if (mod_bits > 1024) { ++ op = SAFE_PK_FUNC_EXP4; ++ a_off = 0x000; ++ b_off = 0x100; ++ c_off = 0x200; ++ d_off = 0x300; ++ } else { ++ op = SAFE_PK_FUNC_EXP16; ++ a_off = 0x000; ++ b_off = 0x080; ++ c_off = 0x100; ++ d_off = 0x180; ++ } ++ sc->sc_pk_reslen = b_off - a_off; ++ sc->sc_pk_resoff = d_off; ++ ++ /* A is exponent, B is modulus, C is base, D is result */ ++ safe_kload_reg(sc, a_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_EXP]); ++ WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2); ++ safe_kload_reg(sc, b_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_MOD]); ++ WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2); ++ safe_kload_reg(sc, c_off, b_off - a_off, ++ &krp->krp_param[SAFE_CRK_PARAM_BASE]); ++ WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2); ++ WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2); ++ ++ WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN); ++ ++ return (0); ++ ++too_big: ++ krp->krp_status = E2BIG; ++ return (1); ++too_small: ++ krp->krp_status = ERANGE; ++ return (1); ++bad_domain: ++ krp->krp_status = EDOM; ++ return (1); ++} ++ ++static int ++safe_ksigbits(struct safe_softc *sc, struct crparam *cr) ++{ ++ u_int plen = (cr->crp_nbits + 7) / 8; ++ int i, sig = plen * 8; ++ u_int8_t c, *p = cr->crp_p; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ for (i = plen - 1; i >= 0; i--) { ++ c = p[i]; ++ if (c != 0) { ++ while ((c & 0x80) == 0) { ++ sig--; ++ c <<= 1; ++ } ++ break; ++ } ++ sig -= 8; ++ } ++ return (sig); ++} ++ ++static void ++safe_kfeed(struct safe_softc *sc) ++{ ++ struct safe_pkq *q, *tmp; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (list_empty(&sc->sc_pkq) && sc->sc_pkq_cur == NULL) ++ return; ++ if (sc->sc_pkq_cur != NULL) ++ return; ++ list_for_each_entry_safe(q, tmp, &sc->sc_pkq, pkq_list) { ++ sc->sc_pkq_cur = q; ++ list_del(&q->pkq_list); ++ if (safe_kstart(sc) != 0) { ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ sc->sc_pkq_cur = NULL; ++ } else { ++ /* op started, start polling */ ++ mod_timer(&sc->sc_pkto, jiffies + 1); ++ break; ++ } ++ } ++} ++ ++static void ++safe_kpoll(unsigned long arg) ++{ ++ struct safe_softc *sc = NULL; ++ struct safe_pkq *q; ++ struct crparam *res; ++ int i; ++ u_int32_t buf[64]; ++ unsigned long flags; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (arg >= SAFE_MAX_CHIPS) ++ return; ++ sc = safe_chip_idx[arg]; ++ if (!sc) { ++ DPRINTF(("%s() - bad callback\n", __FUNCTION__)); ++ return; ++ } ++ ++ spin_lock_irqsave(&sc->sc_pkmtx, flags); ++ if (sc->sc_pkq_cur == NULL) ++ goto out; ++ if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) { ++ /* still running, check back later */ ++ mod_timer(&sc->sc_pkto, jiffies + 1); ++ goto out; ++ } ++ ++ q = sc->sc_pkq_cur; ++ res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams]; ++ bzero(buf, sizeof(buf)); ++ bzero(res->crp_p, (res->crp_nbits + 7) / 8); ++ for (i = 0; i < sc->sc_pk_reslen >> 2; i++) ++ buf[i] = le32_to_cpu(READ_REG(sc, SAFE_PK_RAM_START + ++ sc->sc_pk_resoff + (i << 2))); ++ bcopy(buf, res->crp_p, (res->crp_nbits + 7) / 8); ++ /* ++ * reduce the bits that need copying if possible ++ */ ++ res->crp_nbits = min(res->crp_nbits,sc->sc_pk_reslen * 8); ++ res->crp_nbits = safe_ksigbits(sc, res); ++ ++ for (i = SAFE_PK_RAM_START; i < SAFE_PK_RAM_END; i += 4) ++ WRITE_REG(sc, i, 0); ++ ++ crypto_kdone(q->pkq_krp); ++ kfree(q); ++ sc->sc_pkq_cur = NULL; ++ ++ safe_kfeed(sc); ++out: ++ spin_unlock_irqrestore(&sc->sc_pkmtx, flags); ++} ++ ++static void ++safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len, ++ struct crparam *n) ++{ ++ u_int32_t buf[64], i; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ bzero(buf, sizeof(buf)); ++ bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8); ++ ++ for (i = 0; i < len >> 2; i++) ++ WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2), ++ cpu_to_le32(buf[i])); ++} ++ ++#ifdef SAFE_DEBUG ++static void ++safe_dump_dmastatus(struct safe_softc *sc, const char *tag) ++{ ++ printf("%s: ENDIAN 0x%x SRC 0x%x DST 0x%x STAT 0x%x\n" ++ , tag ++ , READ_REG(sc, SAFE_DMA_ENDIAN) ++ , READ_REG(sc, SAFE_DMA_SRCADDR) ++ , READ_REG(sc, SAFE_DMA_DSTADDR) ++ , READ_REG(sc, SAFE_DMA_STAT) ++ ); ++} ++ ++static void ++safe_dump_intrstate(struct safe_softc *sc, const char *tag) ++{ ++ printf("%s: HI_CFG 0x%x HI_MASK 0x%x HI_DESC_CNT 0x%x HU_STAT 0x%x HM_STAT 0x%x\n" ++ , tag ++ , READ_REG(sc, SAFE_HI_CFG) ++ , READ_REG(sc, SAFE_HI_MASK) ++ , READ_REG(sc, SAFE_HI_DESC_CNT) ++ , READ_REG(sc, SAFE_HU_STAT) ++ , READ_REG(sc, SAFE_HM_STAT) ++ ); ++} ++ ++static void ++safe_dump_ringstate(struct safe_softc *sc, const char *tag) ++{ ++ u_int32_t estat = READ_REG(sc, SAFE_PE_ERNGSTAT); ++ ++ /* NB: assume caller has lock on ring */ ++ printf("%s: ERNGSTAT %x (next %u) back %lu front %lu\n", ++ tag, ++ estat, (estat >> SAFE_PE_ERNGSTAT_NEXT_S), ++ (unsigned long)(sc->sc_back - sc->sc_ring), ++ (unsigned long)(sc->sc_front - sc->sc_ring)); ++} ++ ++static void ++safe_dump_request(struct safe_softc *sc, const char* tag, struct safe_ringentry *re) ++{ ++ int ix, nsegs; ++ ++ ix = re - sc->sc_ring; ++ printf("%s: %p (%u): csr %x src %x dst %x sa %x len %x\n" ++ , tag ++ , re, ix ++ , re->re_desc.d_csr ++ , re->re_desc.d_src ++ , re->re_desc.d_dst ++ , re->re_desc.d_sa ++ , re->re_desc.d_len ++ ); ++ if (re->re_src.nsegs > 1) { ++ ix = (re->re_desc.d_src - sc->sc_spalloc.dma_paddr) / ++ sizeof(struct safe_pdesc); ++ for (nsegs = re->re_src.nsegs; nsegs; nsegs--) { ++ printf(" spd[%u] %p: %p size %u flags %x" ++ , ix, &sc->sc_spring[ix] ++ , (caddr_t)(uintptr_t) sc->sc_spring[ix].pd_addr ++ , sc->sc_spring[ix].pd_size ++ , sc->sc_spring[ix].pd_flags ++ ); ++ if (sc->sc_spring[ix].pd_size == 0) ++ printf(" (zero!)"); ++ printf("\n"); ++ if (++ix == SAFE_TOTAL_SPART) ++ ix = 0; ++ } ++ } ++ if (re->re_dst.nsegs > 1) { ++ ix = (re->re_desc.d_dst - sc->sc_dpalloc.dma_paddr) / ++ sizeof(struct safe_pdesc); ++ for (nsegs = re->re_dst.nsegs; nsegs; nsegs--) { ++ printf(" dpd[%u] %p: %p flags %x\n" ++ , ix, &sc->sc_dpring[ix] ++ , (caddr_t)(uintptr_t) sc->sc_dpring[ix].pd_addr ++ , sc->sc_dpring[ix].pd_flags ++ ); ++ if (++ix == SAFE_TOTAL_DPART) ++ ix = 0; ++ } ++ } ++ printf("sa: cmd0 %08x cmd1 %08x staterec %x\n", ++ re->re_sa.sa_cmd0, re->re_sa.sa_cmd1, re->re_sa.sa_staterec); ++ printf("sa: key %x %x %x %x %x %x %x %x\n" ++ , re->re_sa.sa_key[0] ++ , re->re_sa.sa_key[1] ++ , re->re_sa.sa_key[2] ++ , re->re_sa.sa_key[3] ++ , re->re_sa.sa_key[4] ++ , re->re_sa.sa_key[5] ++ , re->re_sa.sa_key[6] ++ , re->re_sa.sa_key[7] ++ ); ++ printf("sa: indigest %x %x %x %x %x\n" ++ , re->re_sa.sa_indigest[0] ++ , re->re_sa.sa_indigest[1] ++ , re->re_sa.sa_indigest[2] ++ , re->re_sa.sa_indigest[3] ++ , re->re_sa.sa_indigest[4] ++ ); ++ printf("sa: outdigest %x %x %x %x %x\n" ++ , re->re_sa.sa_outdigest[0] ++ , re->re_sa.sa_outdigest[1] ++ , re->re_sa.sa_outdigest[2] ++ , re->re_sa.sa_outdigest[3] ++ , re->re_sa.sa_outdigest[4] ++ ); ++ printf("sr: iv %x %x %x %x\n" ++ , re->re_sastate.sa_saved_iv[0] ++ , re->re_sastate.sa_saved_iv[1] ++ , re->re_sastate.sa_saved_iv[2] ++ , re->re_sastate.sa_saved_iv[3] ++ ); ++ printf("sr: hashbc %u indigest %x %x %x %x %x\n" ++ , re->re_sastate.sa_saved_hashbc ++ , re->re_sastate.sa_saved_indigest[0] ++ , re->re_sastate.sa_saved_indigest[1] ++ , re->re_sastate.sa_saved_indigest[2] ++ , re->re_sastate.sa_saved_indigest[3] ++ , re->re_sastate.sa_saved_indigest[4] ++ ); ++} ++ ++static void ++safe_dump_ring(struct safe_softc *sc, const char *tag) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sc->sc_ringmtx, flags); ++ printf("\nSafeNet Ring State:\n"); ++ safe_dump_intrstate(sc, tag); ++ safe_dump_dmastatus(sc, tag); ++ safe_dump_ringstate(sc, tag); ++ if (sc->sc_nqchip) { ++ struct safe_ringentry *re = sc->sc_back; ++ do { ++ safe_dump_request(sc, tag, re); ++ if (++re == sc->sc_ringtop) ++ re = sc->sc_ring; ++ } while (re != sc->sc_front); ++ } ++ spin_unlock_irqrestore(&sc->sc_ringmtx, flags); ++} ++#endif /* SAFE_DEBUG */ ++ ++ ++static int safe_probe(struct pci_dev *dev, const struct pci_device_id *ent) ++{ ++ struct safe_softc *sc = NULL; ++ u32 mem_start, mem_len, cmd; ++ int i, rc, devinfo; ++ dma_addr_t raddr; ++ static int num_chips = 0; ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ if (pci_enable_device(dev) < 0) ++ return(-ENODEV); ++ ++ if (!dev->irq) { ++ printk("safe: found device with no IRQ assigned. check BIOS settings!"); ++ pci_disable_device(dev); ++ return(-ENODEV); ++ } ++ ++ if (pci_set_mwi(dev)) { ++ printk("safe: pci_set_mwi failed!"); ++ return(-ENODEV); ++ } ++ ++ sc = (struct safe_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return(-ENOMEM); ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, "safe", num_chips, safe_methods); ++ ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++ sc->sc_pcidev = dev; ++ if (num_chips < SAFE_MAX_CHIPS) { ++ safe_chip_idx[device_get_unit(sc->sc_dev)] = sc; ++ num_chips++; ++ } ++ ++ INIT_LIST_HEAD(&sc->sc_pkq); ++ spin_lock_init(&sc->sc_pkmtx); ++ ++ pci_set_drvdata(sc->sc_pcidev, sc); ++ ++ /* we read its hardware registers as memory */ ++ mem_start = pci_resource_start(sc->sc_pcidev, 0); ++ mem_len = pci_resource_len(sc->sc_pcidev, 0); ++ ++ sc->sc_base_addr = (ocf_iomem_t) ioremap(mem_start, mem_len); ++ if (!sc->sc_base_addr) { ++ device_printf(sc->sc_dev, "failed to ioremap 0x%x-0x%x\n", ++ mem_start, mem_start + mem_len - 1); ++ goto out; ++ } ++ ++ /* fix up the bus size */ ++ if (pci_set_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable DMA configuration, aborting.\n"); ++ goto out; ++ } ++ if (pci_set_consistent_dma_mask(sc->sc_pcidev, DMA_32BIT_MASK)) { ++ device_printf(sc->sc_dev, "No usable consistent DMA configuration, aborting.\n"); ++ goto out; ++ } ++ ++ pci_set_master(sc->sc_pcidev); ++ ++ pci_read_config_dword(sc->sc_pcidev, PCI_COMMAND, &cmd); ++ ++ if (!(cmd & PCI_COMMAND_MEMORY)) { ++ device_printf(sc->sc_dev, "failed to enable memory mapping\n"); ++ goto out; ++ } ++ ++ if (!(cmd & PCI_COMMAND_MASTER)) { ++ device_printf(sc->sc_dev, "failed to enable bus mastering\n"); ++ goto out; ++ } ++ ++ rc = request_irq(dev->irq, safe_intr, IRQF_SHARED, "safe", sc); ++ if (rc) { ++ device_printf(sc->sc_dev, "failed to hook irq %d\n", sc->sc_irq); ++ goto out; ++ } ++ sc->sc_irq = dev->irq; ++ ++ sc->sc_chiprev = READ_REG(sc, SAFE_DEVINFO) & ++ (SAFE_DEVINFO_REV_MAJ | SAFE_DEVINFO_REV_MIN); ++ ++ /* ++ * Allocate packet engine descriptors. ++ */ ++ sc->sc_ringalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ &sc->sc_ringalloc.dma_paddr); ++ if (!sc->sc_ringalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate PE descriptor ring\n"); ++ goto out; ++ } ++ ++ /* ++ * Hookup the static portion of all our data structures. ++ */ ++ sc->sc_ring = (struct safe_ringentry *) sc->sc_ringalloc.dma_vaddr; ++ sc->sc_ringtop = sc->sc_ring + SAFE_MAX_NQUEUE; ++ sc->sc_front = sc->sc_ring; ++ sc->sc_back = sc->sc_ring; ++ raddr = sc->sc_ringalloc.dma_paddr; ++ bzero(sc->sc_ring, SAFE_MAX_NQUEUE * sizeof(struct safe_ringentry)); ++ for (i = 0; i < SAFE_MAX_NQUEUE; i++) { ++ struct safe_ringentry *re = &sc->sc_ring[i]; ++ ++ re->re_desc.d_sa = raddr + ++ offsetof(struct safe_ringentry, re_sa); ++ re->re_sa.sa_staterec = raddr + ++ offsetof(struct safe_ringentry, re_sastate); ++ ++ raddr += sizeof (struct safe_ringentry); ++ } ++ spin_lock_init(&sc->sc_ringmtx); ++ ++ /* ++ * Allocate scatter and gather particle descriptors. ++ */ ++ sc->sc_spalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_SPART * sizeof (struct safe_pdesc), ++ &sc->sc_spalloc.dma_paddr); ++ if (!sc->sc_spalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate source particle descriptor ring\n"); ++ goto out; ++ } ++ sc->sc_spring = (struct safe_pdesc *) sc->sc_spalloc.dma_vaddr; ++ sc->sc_springtop = sc->sc_spring + SAFE_TOTAL_SPART; ++ sc->sc_spfree = sc->sc_spring; ++ bzero(sc->sc_spring, SAFE_TOTAL_SPART * sizeof(struct safe_pdesc)); ++ ++ sc->sc_dpalloc.dma_vaddr = pci_alloc_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ &sc->sc_dpalloc.dma_paddr); ++ if (!sc->sc_dpalloc.dma_vaddr) { ++ device_printf(sc->sc_dev, "cannot allocate destination particle descriptor ring\n"); ++ goto out; ++ } ++ sc->sc_dpring = (struct safe_pdesc *) sc->sc_dpalloc.dma_vaddr; ++ sc->sc_dpringtop = sc->sc_dpring + SAFE_TOTAL_DPART; ++ sc->sc_dpfree = sc->sc_dpring; ++ bzero(sc->sc_dpring, SAFE_TOTAL_DPART * sizeof(struct safe_pdesc)); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc), CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ device_printf(sc->sc_dev, "could not get crypto driver id\n"); ++ goto out; ++ } ++ ++ printf("%s:", device_get_nameunit(sc->sc_dev)); ++ ++ devinfo = READ_REG(sc, SAFE_DEVINFO); ++ if (devinfo & SAFE_DEVINFO_RNG) { ++ sc->sc_flags |= SAFE_FLAGS_RNG; ++ printf(" rng"); ++ } ++ if (devinfo & SAFE_DEVINFO_PKEY) { ++ printf(" key"); ++ sc->sc_flags |= SAFE_FLAGS_KEY; ++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0); ++#if 0 ++ crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0); ++#endif ++ init_timer(&sc->sc_pkto); ++ sc->sc_pkto.function = safe_kpoll; ++ sc->sc_pkto.data = (unsigned long) device_get_unit(sc->sc_dev); ++ } ++ if (devinfo & SAFE_DEVINFO_DES) { ++ printf(" des/3des"); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_AES) { ++ printf(" aes"); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_MD5) { ++ printf(" md5"); ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ } ++ if (devinfo & SAFE_DEVINFO_SHA1) { ++ printf(" sha1"); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ } ++ printf(" null"); ++ crypto_register(sc->sc_cid, CRYPTO_NULL_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_NULL_HMAC, 0, 0); ++ /* XXX other supported algorithms */ ++ printf("\n"); ++ ++ safe_reset_board(sc); /* reset h/w */ ++ safe_init_board(sc); /* init h/w */ ++ ++#if defined(CONFIG_OCF_RANDOMHARVEST) && !defined(SAFE_NO_RNG) ++ if (sc->sc_flags & SAFE_FLAGS_RNG) { ++ safe_rng_init(sc); ++ crypto_rregister(sc->sc_cid, safe_read_random, sc); ++ } ++#endif /* SAFE_NO_RNG */ ++ ++ return (0); ++ ++out: ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_ringalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); ++ if (sc->sc_spalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); ++ if (sc->sc_dpalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); ++ kfree(sc); ++ return(-ENODEV); ++} ++ ++static void safe_remove(struct pci_dev *dev) ++{ ++ struct safe_softc *sc = pci_get_drvdata(dev); ++ ++ DPRINTF(("%s()\n", __FUNCTION__)); ++ ++ /* XXX wait/abort active ops */ ++ ++ WRITE_REG(sc, SAFE_HI_MASK, 0); /* disable interrupts */ ++ ++ del_timer_sync(&sc->sc_pkto); ++ ++ crypto_unregister_all(sc->sc_cid); ++ ++ safe_cleanchip(sc); ++ ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_ringalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_MAX_NQUEUE * sizeof (struct safe_ringentry), ++ sc->sc_ringalloc.dma_vaddr, sc->sc_ringalloc.dma_paddr); ++ if (sc->sc_spalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_spalloc.dma_vaddr, sc->sc_spalloc.dma_paddr); ++ if (sc->sc_dpalloc.dma_vaddr) ++ pci_free_consistent(sc->sc_pcidev, ++ SAFE_TOTAL_DPART * sizeof (struct safe_pdesc), ++ sc->sc_dpalloc.dma_vaddr, sc->sc_dpalloc.dma_paddr); ++ sc->sc_irq = -1; ++ sc->sc_ringalloc.dma_vaddr = NULL; ++ sc->sc_spalloc.dma_vaddr = NULL; ++ sc->sc_dpalloc.dma_vaddr = NULL; ++} ++ ++static struct pci_device_id safe_pci_tbl[] = { ++ { PCI_VENDOR_SAFENET, PCI_PRODUCT_SAFEXCEL, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(pci, safe_pci_tbl); ++ ++static struct pci_driver safe_driver = { ++ .name = "safe", ++ .id_table = safe_pci_tbl, ++ .probe = safe_probe, ++ .remove = safe_remove, ++ /* add PM stuff here one day */ ++}; ++ ++static int __init safe_init (void) ++{ ++ struct safe_softc *sc = NULL; ++ int rc; ++ ++ DPRINTF(("%s(%p)\n", __FUNCTION__, safe_init)); ++ ++ rc = pci_register_driver(&safe_driver); ++ pci_register_driver_compat(&safe_driver, rc); ++ ++ return rc; ++} ++ ++static void __exit safe_exit (void) ++{ ++ pci_unregister_driver(&safe_driver); ++} ++ ++module_init(safe_init); ++module_exit(safe_exit); ++ ++MODULE_LICENSE("BSD"); ++MODULE_AUTHOR("David McCullough "); ++MODULE_DESCRIPTION("OCF driver for safenet PCI crypto devices"); +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safereg.h linux-2.6.30/crypto/ocf/safe/safereg.h +--- linux-2.6.30.orig/crypto/ocf/safe/safereg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safereg.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,421 @@ ++/*- ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * $FreeBSD: src/sys/dev/safe/safereg.h,v 1.1 2003/07/21 21:46:07 sam Exp $ ++ */ ++#ifndef _SAFE_SAFEREG_H_ ++#define _SAFE_SAFEREG_H_ ++ ++/* ++ * Register definitions for SafeNet SafeXcel-1141 crypto device. ++ * Definitions from revision 1.3 (Nov 6 2002) of the User's Manual. ++ */ ++ ++#define BS_BAR 0x10 /* DMA base address register */ ++#define BS_TRDY_TIMEOUT 0x40 /* TRDY timeout */ ++#define BS_RETRY_TIMEOUT 0x41 /* DMA retry timeout */ ++ ++#define PCI_VENDOR_SAFENET 0x16ae /* SafeNet, Inc. */ ++ ++/* SafeNet */ ++#define PCI_PRODUCT_SAFEXCEL 0x1141 /* 1141 */ ++ ++#define SAFE_PE_CSR 0x0000 /* Packet Enginge Ctrl/Status */ ++#define SAFE_PE_SRC 0x0004 /* Packet Engine Source */ ++#define SAFE_PE_DST 0x0008 /* Packet Engine Destination */ ++#define SAFE_PE_SA 0x000c /* Packet Engine SA */ ++#define SAFE_PE_LEN 0x0010 /* Packet Engine Length */ ++#define SAFE_PE_DMACFG 0x0040 /* Packet Engine DMA Configuration */ ++#define SAFE_PE_DMASTAT 0x0044 /* Packet Engine DMA Status */ ++#define SAFE_PE_PDRBASE 0x0048 /* Packet Engine Descriptor Ring Base */ ++#define SAFE_PE_RDRBASE 0x004c /* Packet Engine Result Ring Base */ ++#define SAFE_PE_RINGCFG 0x0050 /* Packet Engine Ring Configuration */ ++#define SAFE_PE_RINGPOLL 0x0054 /* Packet Engine Ring Poll */ ++#define SAFE_PE_IRNGSTAT 0x0058 /* Packet Engine Internal Ring Status */ ++#define SAFE_PE_ERNGSTAT 0x005c /* Packet Engine External Ring Status */ ++#define SAFE_PE_IOTHRESH 0x0060 /* Packet Engine I/O Threshold */ ++#define SAFE_PE_GRNGBASE 0x0064 /* Packet Engine Gather Ring Base */ ++#define SAFE_PE_SRNGBASE 0x0068 /* Packet Engine Scatter Ring Base */ ++#define SAFE_PE_PARTSIZE 0x006c /* Packet Engine Particlar Ring Size */ ++#define SAFE_PE_PARTCFG 0x0070 /* Packet Engine Particle Ring Config */ ++#define SAFE_CRYPTO_CTRL 0x0080 /* Crypto Control */ ++#define SAFE_DEVID 0x0084 /* Device ID */ ++#define SAFE_DEVINFO 0x0088 /* Device Info */ ++#define SAFE_HU_STAT 0x00a0 /* Host Unmasked Status */ ++#define SAFE_HM_STAT 0x00a4 /* Host Masked Status (read-only) */ ++#define SAFE_HI_CLR 0x00a4 /* Host Clear Interrupt (write-only) */ ++#define SAFE_HI_MASK 0x00a8 /* Host Mask Control */ ++#define SAFE_HI_CFG 0x00ac /* Interrupt Configuration */ ++#define SAFE_HI_RD_DESCR 0x00b4 /* Force Descriptor Read */ ++#define SAFE_HI_DESC_CNT 0x00b8 /* Host Descriptor Done Count */ ++#define SAFE_DMA_ENDIAN 0x00c0 /* Master Endian Status */ ++#define SAFE_DMA_SRCADDR 0x00c4 /* DMA Source Address Status */ ++#define SAFE_DMA_DSTADDR 0x00c8 /* DMA Destination Address Status */ ++#define SAFE_DMA_STAT 0x00cc /* DMA Current Status */ ++#define SAFE_DMA_CFG 0x00d4 /* DMA Configuration/Status */ ++#define SAFE_ENDIAN 0x00e0 /* Endian Configuration */ ++#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */ ++#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */ ++#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */ ++#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */ ++#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */ ++#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */ ++#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */ ++#define SAFE_PK_FUNC 0x081c /* Public Key Function */ ++#define SAFE_PK_RAM_START 0x1000 /* Public Key RAM start address */ ++#define SAFE_PK_RAM_END 0x1fff /* Public Key RAM end address */ ++ ++#define SAFE_RNG_OUT 0x0100 /* RNG Output */ ++#define SAFE_RNG_STAT 0x0104 /* RNG Status */ ++#define SAFE_RNG_CTRL 0x0108 /* RNG Control */ ++#define SAFE_RNG_A 0x010c /* RNG A */ ++#define SAFE_RNG_B 0x0110 /* RNG B */ ++#define SAFE_RNG_X_LO 0x0114 /* RNG X [31:0] */ ++#define SAFE_RNG_X_MID 0x0118 /* RNG X [63:32] */ ++#define SAFE_RNG_X_HI 0x011c /* RNG X [80:64] */ ++#define SAFE_RNG_X_CNTR 0x0120 /* RNG Counter */ ++#define SAFE_RNG_ALM_CNT 0x0124 /* RNG Alarm Count */ ++#define SAFE_RNG_CNFG 0x0128 /* RNG Configuration */ ++#define SAFE_RNG_LFSR1_LO 0x012c /* RNG LFSR1 [31:0] */ ++#define SAFE_RNG_LFSR1_HI 0x0130 /* RNG LFSR1 [47:32] */ ++#define SAFE_RNG_LFSR2_LO 0x0134 /* RNG LFSR1 [31:0] */ ++#define SAFE_RNG_LFSR2_HI 0x0138 /* RNG LFSR1 [47:32] */ ++ ++#define SAFE_PE_CSR_READY 0x00000001 /* ready for processing */ ++#define SAFE_PE_CSR_DONE 0x00000002 /* h/w completed processing */ ++#define SAFE_PE_CSR_LOADSA 0x00000004 /* load SA digests */ ++#define SAFE_PE_CSR_HASHFINAL 0x00000010 /* do hash pad & write result */ ++#define SAFE_PE_CSR_SABUSID 0x000000c0 /* bus id for SA */ ++#define SAFE_PE_CSR_SAPCI 0x00000040 /* PCI bus id for SA */ ++#define SAFE_PE_CSR_NXTHDR 0x0000ff00 /* next hdr value for IPsec */ ++#define SAFE_PE_CSR_FPAD 0x0000ff00 /* fixed pad for basic ops */ ++#define SAFE_PE_CSR_STATUS 0x00ff0000 /* operation result status */ ++#define SAFE_PE_CSR_AUTH_FAIL 0x00010000 /* ICV mismatch (inbound) */ ++#define SAFE_PE_CSR_PAD_FAIL 0x00020000 /* pad verify fail (inbound) */ ++#define SAFE_PE_CSR_SEQ_FAIL 0x00040000 /* sequence number (inbound) */ ++#define SAFE_PE_CSR_XERROR 0x00080000 /* extended error follows */ ++#define SAFE_PE_CSR_XECODE 0x00f00000 /* extended error code */ ++#define SAFE_PE_CSR_XECODE_S 20 ++#define SAFE_PE_CSR_XECODE_BADCMD 0 /* invalid command */ ++#define SAFE_PE_CSR_XECODE_BADALG 1 /* invalid algorithm */ ++#define SAFE_PE_CSR_XECODE_ALGDIS 2 /* algorithm disabled */ ++#define SAFE_PE_CSR_XECODE_ZEROLEN 3 /* zero packet length */ ++#define SAFE_PE_CSR_XECODE_DMAERR 4 /* bus DMA error */ ++#define SAFE_PE_CSR_XECODE_PIPEABORT 5 /* secondary bus DMA error */ ++#define SAFE_PE_CSR_XECODE_BADSPI 6 /* IPsec SPI mismatch */ ++#define SAFE_PE_CSR_XECODE_TIMEOUT 10 /* failsafe timeout */ ++#define SAFE_PE_CSR_PAD 0xff000000 /* ESP padding control/status */ ++#define SAFE_PE_CSR_PAD_MIN 0x00000000 /* minimum IPsec padding */ ++#define SAFE_PE_CSR_PAD_16 0x08000000 /* pad to 16-byte boundary */ ++#define SAFE_PE_CSR_PAD_32 0x10000000 /* pad to 32-byte boundary */ ++#define SAFE_PE_CSR_PAD_64 0x20000000 /* pad to 64-byte boundary */ ++#define SAFE_PE_CSR_PAD_128 0x40000000 /* pad to 128-byte boundary */ ++#define SAFE_PE_CSR_PAD_256 0x80000000 /* pad to 256-byte boundary */ ++ ++/* ++ * Check the CSR to see if the PE has returned ownership to ++ * the host. Note that before processing a descriptor this ++ * must be done followed by a check of the SAFE_PE_LEN register ++ * status bits to avoid premature processing of a descriptor ++ * on its way back to the host. ++ */ ++#define SAFE_PE_CSR_IS_DONE(_csr) \ ++ (((_csr) & (SAFE_PE_CSR_READY | SAFE_PE_CSR_DONE)) == SAFE_PE_CSR_DONE) ++ ++#define SAFE_PE_LEN_LENGTH 0x000fffff /* total length (bytes) */ ++#define SAFE_PE_LEN_READY 0x00400000 /* ready for processing */ ++#define SAFE_PE_LEN_DONE 0x00800000 /* h/w completed processing */ ++#define SAFE_PE_LEN_BYPASS 0xff000000 /* bypass offset (bytes) */ ++#define SAFE_PE_LEN_BYPASS_S 24 ++ ++#define SAFE_PE_LEN_IS_DONE(_len) \ ++ (((_len) & (SAFE_PE_LEN_READY | SAFE_PE_LEN_DONE)) == SAFE_PE_LEN_DONE) ++ ++/* NB: these apply to HU_STAT, HM_STAT, HI_CLR, and HI_MASK */ ++#define SAFE_INT_PE_CDONE 0x00000002 /* PE context done */ ++#define SAFE_INT_PE_DDONE 0x00000008 /* PE descriptor done */ ++#define SAFE_INT_PE_ERROR 0x00000010 /* PE error */ ++#define SAFE_INT_PE_ODONE 0x00000020 /* PE operation done */ ++ ++#define SAFE_HI_CFG_PULSE 0x00000001 /* use pulse interrupt */ ++#define SAFE_HI_CFG_LEVEL 0x00000000 /* use level interrupt */ ++#define SAFE_HI_CFG_AUTOCLR 0x00000002 /* auto-clear pulse interrupt */ ++ ++#define SAFE_ENDIAN_PASS 0x000000e4 /* straight pass-thru */ ++#define SAFE_ENDIAN_SWAB 0x0000001b /* swap bytes in 32-bit word */ ++ ++#define SAFE_PE_DMACFG_PERESET 0x00000001 /* reset packet engine */ ++#define SAFE_PE_DMACFG_PDRRESET 0x00000002 /* reset PDR counters/ptrs */ ++#define SAFE_PE_DMACFG_SGRESET 0x00000004 /* reset scatter/gather cache */ ++#define SAFE_PE_DMACFG_FSENA 0x00000008 /* enable failsafe reset */ ++#define SAFE_PE_DMACFG_PEMODE 0x00000100 /* packet engine mode */ ++#define SAFE_PE_DMACFG_SAPREC 0x00000200 /* SA precedes packet */ ++#define SAFE_PE_DMACFG_PKFOLL 0x00000400 /* packet follows descriptor */ ++#define SAFE_PE_DMACFG_GPRBID 0x00003000 /* gather particle ring busid */ ++#define SAFE_PE_DMACFG_GPRPCI 0x00001000 /* PCI gather particle ring */ ++#define SAFE_PE_DMACFG_SPRBID 0x0000c000 /* scatter part. ring busid */ ++#define SAFE_PE_DMACFG_SPRPCI 0x00004000 /* PCI scatter part. ring */ ++#define SAFE_PE_DMACFG_ESDESC 0x00010000 /* endian swap descriptors */ ++#define SAFE_PE_DMACFG_ESSA 0x00020000 /* endian swap SA data */ ++#define SAFE_PE_DMACFG_ESPACKET 0x00040000 /* endian swap packet data */ ++#define SAFE_PE_DMACFG_ESPDESC 0x00080000 /* endian swap particle desc. */ ++#define SAFE_PE_DMACFG_NOPDRUP 0x00100000 /* supp. PDR ownership update */ ++#define SAFE_PD_EDMACFG_PCIMODE 0x01000000 /* PCI target mode */ ++ ++#define SAFE_PE_DMASTAT_PEIDONE 0x00000001 /* PE core input done */ ++#define SAFE_PE_DMASTAT_PEODONE 0x00000002 /* PE core output done */ ++#define SAFE_PE_DMASTAT_ENCDONE 0x00000004 /* encryption done */ ++#define SAFE_PE_DMASTAT_IHDONE 0x00000008 /* inner hash done */ ++#define SAFE_PE_DMASTAT_OHDONE 0x00000010 /* outer hash (HMAC) done */ ++#define SAFE_PE_DMASTAT_PADFLT 0x00000020 /* crypto pad fault */ ++#define SAFE_PE_DMASTAT_ICVFLT 0x00000040 /* ICV fault */ ++#define SAFE_PE_DMASTAT_SPIMIS 0x00000080 /* SPI mismatch */ ++#define SAFE_PE_DMASTAT_CRYPTO 0x00000100 /* crypto engine timeout */ ++#define SAFE_PE_DMASTAT_CQACT 0x00000200 /* command queue active */ ++#define SAFE_PE_DMASTAT_IRACT 0x00000400 /* input request active */ ++#define SAFE_PE_DMASTAT_ORACT 0x00000800 /* output request active */ ++#define SAFE_PE_DMASTAT_PEISIZE 0x003ff000 /* PE input size:32-bit words */ ++#define SAFE_PE_DMASTAT_PEOSIZE 0xffc00000 /* PE out. size:32-bit words */ ++ ++#define SAFE_PE_RINGCFG_SIZE 0x000003ff /* ring size (descriptors) */ ++#define SAFE_PE_RINGCFG_OFFSET 0xffff0000 /* offset btw desc's (dwords) */ ++#define SAFE_PE_RINGCFG_OFFSET_S 16 ++ ++#define SAFE_PE_RINGPOLL_POLL 0x00000fff /* polling frequency/divisor */ ++#define SAFE_PE_RINGPOLL_RETRY 0x03ff0000 /* polling frequency/divisor */ ++#define SAFE_PE_RINGPOLL_CONT 0x80000000 /* continuously poll */ ++ ++#define SAFE_PE_IRNGSTAT_CQAVAIL 0x00000001 /* command queue available */ ++ ++#define SAFE_PE_ERNGSTAT_NEXT 0x03ff0000 /* index of next packet desc. */ ++#define SAFE_PE_ERNGSTAT_NEXT_S 16 ++ ++#define SAFE_PE_IOTHRESH_INPUT 0x000003ff /* input threshold (dwords) */ ++#define SAFE_PE_IOTHRESH_OUTPUT 0x03ff0000 /* output threshold (dwords) */ ++ ++#define SAFE_PE_PARTCFG_SIZE 0x0000ffff /* scatter particle size */ ++#define SAFE_PE_PARTCFG_GBURST 0x00030000 /* gather particle burst */ ++#define SAFE_PE_PARTCFG_GBURST_2 0x00000000 ++#define SAFE_PE_PARTCFG_GBURST_4 0x00010000 ++#define SAFE_PE_PARTCFG_GBURST_8 0x00020000 ++#define SAFE_PE_PARTCFG_GBURST_16 0x00030000 ++#define SAFE_PE_PARTCFG_SBURST 0x000c0000 /* scatter particle burst */ ++#define SAFE_PE_PARTCFG_SBURST_2 0x00000000 ++#define SAFE_PE_PARTCFG_SBURST_4 0x00040000 ++#define SAFE_PE_PARTCFG_SBURST_8 0x00080000 ++#define SAFE_PE_PARTCFG_SBURST_16 0x000c0000 ++ ++#define SAFE_PE_PARTSIZE_SCAT 0xffff0000 /* scatter particle ring size */ ++#define SAFE_PE_PARTSIZE_GATH 0x0000ffff /* gather particle ring size */ ++ ++#define SAFE_CRYPTO_CTRL_3DES 0x00000001 /* enable 3DES support */ ++#define SAFE_CRYPTO_CTRL_PKEY 0x00010000 /* enable public key support */ ++#define SAFE_CRYPTO_CTRL_RNG 0x00020000 /* enable RNG support */ ++ ++#define SAFE_DEVINFO_REV_MIN 0x0000000f /* minor rev for chip */ ++#define SAFE_DEVINFO_REV_MAJ 0x000000f0 /* major rev for chip */ ++#define SAFE_DEVINFO_REV_MAJ_S 4 ++#define SAFE_DEVINFO_DES 0x00000100 /* DES/3DES support present */ ++#define SAFE_DEVINFO_ARC4 0x00000200 /* ARC4 support present */ ++#define SAFE_DEVINFO_AES 0x00000400 /* AES support present */ ++#define SAFE_DEVINFO_MD5 0x00001000 /* MD5 support present */ ++#define SAFE_DEVINFO_SHA1 0x00002000 /* SHA-1 support present */ ++#define SAFE_DEVINFO_RIPEMD 0x00004000 /* RIPEMD support present */ ++#define SAFE_DEVINFO_DEFLATE 0x00010000 /* Deflate support present */ ++#define SAFE_DEVINFO_SARAM 0x00100000 /* on-chip SA RAM present */ ++#define SAFE_DEVINFO_EMIBUS 0x00200000 /* EMI bus present */ ++#define SAFE_DEVINFO_PKEY 0x00400000 /* public key support present */ ++#define SAFE_DEVINFO_RNG 0x00800000 /* RNG present */ ++ ++#define SAFE_REV(_maj, _min) (((_maj) << SAFE_DEVINFO_REV_MAJ_S) | (_min)) ++#define SAFE_REV_MAJ(_chiprev) \ ++ (((_chiprev) & SAFE_DEVINFO_REV_MAJ) >> SAFE_DEVINFO_REV_MAJ_S) ++#define SAFE_REV_MIN(_chiprev) ((_chiprev) & SAFE_DEVINFO_REV_MIN) ++ ++#define SAFE_PK_FUNC_MULT 0x00000001 /* Multiply function */ ++#define SAFE_PK_FUNC_SQUARE 0x00000004 /* Square function */ ++#define SAFE_PK_FUNC_ADD 0x00000010 /* Add function */ ++#define SAFE_PK_FUNC_SUB 0x00000020 /* Subtract function */ ++#define SAFE_PK_FUNC_LSHIFT 0x00000040 /* Left-shift function */ ++#define SAFE_PK_FUNC_RSHIFT 0x00000080 /* Right-shift function */ ++#define SAFE_PK_FUNC_DIV 0x00000100 /* Divide function */ ++#define SAFE_PK_FUNC_CMP 0x00000400 /* Compare function */ ++#define SAFE_PK_FUNC_COPY 0x00000800 /* Copy function */ ++#define SAFE_PK_FUNC_EXP16 0x00002000 /* Exponentiate (4-bit ACT) */ ++#define SAFE_PK_FUNC_EXP4 0x00004000 /* Exponentiate (2-bit ACT) */ ++#define SAFE_PK_FUNC_RUN 0x00008000 /* start/status */ ++ ++#define SAFE_RNG_STAT_BUSY 0x00000001 /* busy, data not valid */ ++ ++#define SAFE_RNG_CTRL_PRE_LFSR 0x00000001 /* enable output pre-LFSR */ ++#define SAFE_RNG_CTRL_TST_MODE 0x00000002 /* enable test mode */ ++#define SAFE_RNG_CTRL_TST_RUN 0x00000004 /* start test state machine */ ++#define SAFE_RNG_CTRL_ENA_RING1 0x00000008 /* test entropy oscillator #1 */ ++#define SAFE_RNG_CTRL_ENA_RING2 0x00000010 /* test entropy oscillator #2 */ ++#define SAFE_RNG_CTRL_DIS_ALARM 0x00000020 /* disable RNG alarm reports */ ++#define SAFE_RNG_CTRL_TST_CLOCK 0x00000040 /* enable test clock */ ++#define SAFE_RNG_CTRL_SHORTEN 0x00000080 /* shorten state timers */ ++#define SAFE_RNG_CTRL_TST_ALARM 0x00000100 /* simulate alarm state */ ++#define SAFE_RNG_CTRL_RST_LFSR 0x00000200 /* reset LFSR */ ++ ++/* ++ * Packet engine descriptor. Note that d_csr is a copy of the ++ * SAFE_PE_CSR register and all definitions apply, and d_len ++ * is a copy of the SAFE_PE_LEN register and all definitions apply. ++ * d_src and d_len may point directly to contiguous data or to a ++ * list of ``particle descriptors'' when using scatter/gather i/o. ++ */ ++struct safe_desc { ++ u_int32_t d_csr; /* per-packet control/status */ ++ u_int32_t d_src; /* source address */ ++ u_int32_t d_dst; /* destination address */ ++ u_int32_t d_sa; /* SA address */ ++ u_int32_t d_len; /* length, bypass, status */ ++}; ++ ++/* ++ * Scatter/Gather particle descriptor. ++ * ++ * NB: scatter descriptors do not specify a size; this is fixed ++ * by the setting of the SAFE_PE_PARTCFG register. ++ */ ++struct safe_pdesc { ++ u_int32_t pd_addr; /* particle address */ ++#ifdef __BIG_ENDIAN ++ u_int16_t pd_flags; /* control word */ ++ u_int16_t pd_size; /* particle size (bytes) */ ++#else ++ u_int16_t pd_flags; /* control word */ ++ u_int16_t pd_size; /* particle size (bytes) */ ++#endif ++}; ++ ++#define SAFE_PD_READY 0x0001 /* ready for processing */ ++#define SAFE_PD_DONE 0x0002 /* h/w completed processing */ ++ ++/* ++ * Security Association (SA) Record (Rev 1). One of these is ++ * required for each operation processed by the packet engine. ++ */ ++struct safe_sarec { ++ u_int32_t sa_cmd0; ++ u_int32_t sa_cmd1; ++ u_int32_t sa_resv0; ++ u_int32_t sa_resv1; ++ u_int32_t sa_key[8]; /* DES/3DES/AES key */ ++ u_int32_t sa_indigest[5]; /* inner digest */ ++ u_int32_t sa_outdigest[5]; /* outer digest */ ++ u_int32_t sa_spi; /* SPI */ ++ u_int32_t sa_seqnum; /* sequence number */ ++ u_int32_t sa_seqmask[2]; /* sequence number mask */ ++ u_int32_t sa_resv2; ++ u_int32_t sa_staterec; /* address of state record */ ++ u_int32_t sa_resv3[2]; ++ u_int32_t sa_samgmt0; /* SA management field 0 */ ++ u_int32_t sa_samgmt1; /* SA management field 0 */ ++}; ++ ++#define SAFE_SA_CMD0_OP 0x00000007 /* operation code */ ++#define SAFE_SA_CMD0_OP_CRYPT 0x00000000 /* encrypt/decrypt (basic) */ ++#define SAFE_SA_CMD0_OP_BOTH 0x00000001 /* encrypt-hash/hash-decrypto */ ++#define SAFE_SA_CMD0_OP_HASH 0x00000003 /* hash (outbound-only) */ ++#define SAFE_SA_CMD0_OP_ESP 0x00000000 /* ESP in/out (proto) */ ++#define SAFE_SA_CMD0_OP_AH 0x00000001 /* AH in/out (proto) */ ++#define SAFE_SA_CMD0_INBOUND 0x00000008 /* inbound operation */ ++#define SAFE_SA_CMD0_OUTBOUND 0x00000000 /* outbound operation */ ++#define SAFE_SA_CMD0_GROUP 0x00000030 /* operation group */ ++#define SAFE_SA_CMD0_BASIC 0x00000000 /* basic operation */ ++#define SAFE_SA_CMD0_PROTO 0x00000010 /* protocol/packet operation */ ++#define SAFE_SA_CMD0_BUNDLE 0x00000020 /* bundled operation (resvd) */ ++#define SAFE_SA_CMD0_PAD 0x000000c0 /* crypto pad method */ ++#define SAFE_SA_CMD0_PAD_IPSEC 0x00000000 /* IPsec padding */ ++#define SAFE_SA_CMD0_PAD_PKCS7 0x00000040 /* PKCS#7 padding */ ++#define SAFE_SA_CMD0_PAD_CONS 0x00000080 /* constant padding */ ++#define SAFE_SA_CMD0_PAD_ZERO 0x000000c0 /* zero padding */ ++#define SAFE_SA_CMD0_CRYPT_ALG 0x00000f00 /* symmetric crypto algorithm */ ++#define SAFE_SA_CMD0_DES 0x00000000 /* DES crypto algorithm */ ++#define SAFE_SA_CMD0_3DES 0x00000100 /* 3DES crypto algorithm */ ++#define SAFE_SA_CMD0_AES 0x00000300 /* AES crypto algorithm */ ++#define SAFE_SA_CMD0_CRYPT_NULL 0x00000f00 /* null crypto algorithm */ ++#define SAFE_SA_CMD0_HASH_ALG 0x0000f000 /* hash algorithm */ ++#define SAFE_SA_CMD0_MD5 0x00000000 /* MD5 hash algorithm */ ++#define SAFE_SA_CMD0_SHA1 0x00001000 /* SHA-1 hash algorithm */ ++#define SAFE_SA_CMD0_HASH_NULL 0x0000f000 /* null hash algorithm */ ++#define SAFE_SA_CMD0_HDR_PROC 0x00080000 /* header processing */ ++#define SAFE_SA_CMD0_IBUSID 0x00300000 /* input bus id */ ++#define SAFE_SA_CMD0_IPCI 0x00100000 /* PCI input bus id */ ++#define SAFE_SA_CMD0_OBUSID 0x00c00000 /* output bus id */ ++#define SAFE_SA_CMD0_OPCI 0x00400000 /* PCI output bus id */ ++#define SAFE_SA_CMD0_IVLD 0x03000000 /* IV loading */ ++#define SAFE_SA_CMD0_IVLD_NONE 0x00000000 /* IV no load (reuse) */ ++#define SAFE_SA_CMD0_IVLD_IBUF 0x01000000 /* IV load from input buffer */ ++#define SAFE_SA_CMD0_IVLD_STATE 0x02000000 /* IV load from state */ ++#define SAFE_SA_CMD0_HSLD 0x0c000000 /* hash state loading */ ++#define SAFE_SA_CMD0_HSLD_SA 0x00000000 /* hash state load from SA */ ++#define SAFE_SA_CMD0_HSLD_STATE 0x08000000 /* hash state load from state */ ++#define SAFE_SA_CMD0_HSLD_NONE 0x0c000000 /* hash state no load */ ++#define SAFE_SA_CMD0_SAVEIV 0x10000000 /* save IV */ ++#define SAFE_SA_CMD0_SAVEHASH 0x20000000 /* save hash state */ ++#define SAFE_SA_CMD0_IGATHER 0x40000000 /* input gather */ ++#define SAFE_SA_CMD0_OSCATTER 0x80000000 /* output scatter */ ++ ++#define SAFE_SA_CMD1_HDRCOPY 0x00000002 /* copy header to output */ ++#define SAFE_SA_CMD1_PAYCOPY 0x00000004 /* copy payload to output */ ++#define SAFE_SA_CMD1_PADCOPY 0x00000008 /* copy pad to output */ ++#define SAFE_SA_CMD1_IPV4 0x00000000 /* IPv4 protocol */ ++#define SAFE_SA_CMD1_IPV6 0x00000010 /* IPv6 protocol */ ++#define SAFE_SA_CMD1_MUTABLE 0x00000020 /* mutable bit processing */ ++#define SAFE_SA_CMD1_SRBUSID 0x000000c0 /* state record bus id */ ++#define SAFE_SA_CMD1_SRPCI 0x00000040 /* state record from PCI */ ++#define SAFE_SA_CMD1_CRMODE 0x00000300 /* crypto mode */ ++#define SAFE_SA_CMD1_ECB 0x00000000 /* ECB crypto mode */ ++#define SAFE_SA_CMD1_CBC 0x00000100 /* CBC crypto mode */ ++#define SAFE_SA_CMD1_OFB 0x00000200 /* OFB crypto mode */ ++#define SAFE_SA_CMD1_CFB 0x00000300 /* CFB crypto mode */ ++#define SAFE_SA_CMD1_CRFEEDBACK 0x00000c00 /* crypto feedback mode */ ++#define SAFE_SA_CMD1_64BIT 0x00000000 /* 64-bit crypto feedback */ ++#define SAFE_SA_CMD1_8BIT 0x00000400 /* 8-bit crypto feedback */ ++#define SAFE_SA_CMD1_1BIT 0x00000800 /* 1-bit crypto feedback */ ++#define SAFE_SA_CMD1_128BIT 0x00000c00 /* 128-bit crypto feedback */ ++#define SAFE_SA_CMD1_OPTIONS 0x00001000 /* HMAC/options mutable bit */ ++#define SAFE_SA_CMD1_HMAC SAFE_SA_CMD1_OPTIONS ++#define SAFE_SA_CMD1_SAREV1 0x00008000 /* SA Revision 1 */ ++#define SAFE_SA_CMD1_OFFSET 0x00ff0000 /* hash/crypto offset(dwords) */ ++#define SAFE_SA_CMD1_OFFSET_S 16 ++#define SAFE_SA_CMD1_AESKEYLEN 0x0f000000 /* AES key length */ ++#define SAFE_SA_CMD1_AES128 0x02000000 /* 128-bit AES key */ ++#define SAFE_SA_CMD1_AES192 0x03000000 /* 192-bit AES key */ ++#define SAFE_SA_CMD1_AES256 0x04000000 /* 256-bit AES key */ ++ ++/* ++ * Security Associate State Record (Rev 1). ++ */ ++struct safe_sastate { ++ u_int32_t sa_saved_iv[4]; /* saved IV (DES/3DES/AES) */ ++ u_int32_t sa_saved_hashbc; /* saved hash byte count */ ++ u_int32_t sa_saved_indigest[5]; /* saved inner digest */ ++}; ++#endif /* _SAFE_SAFEREG_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/safevar.h linux-2.6.30/crypto/ocf/safe/safevar.h +--- linux-2.6.30.orig/crypto/ocf/safe/safevar.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/safevar.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,230 @@ ++/*- ++ * The linux port of this code done by David McCullough ++ * Copyright (C) 2004-2007 David McCullough ++ * The license and original author are listed below. ++ * ++ * Copyright (c) 2003 Sam Leffler, Errno Consulting ++ * Copyright (c) 2003 Global Technology Associates, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * $FreeBSD: src/sys/dev/safe/safevar.h,v 1.2 2006/05/17 18:34:26 pjd Exp $ ++ */ ++#ifndef _SAFE_SAFEVAR_H_ ++#define _SAFE_SAFEVAR_H_ ++ ++/* Maximum queue length */ ++#ifndef SAFE_MAX_NQUEUE ++#define SAFE_MAX_NQUEUE 60 ++#endif ++ ++#define SAFE_MAX_PART 64 /* Maximum scatter/gather depth */ ++#define SAFE_DMA_BOUNDARY 0 /* No boundary for source DMA ops */ ++#define SAFE_MAX_DSIZE 2048 /* MCLBYTES Fixed scatter particle size */ ++#define SAFE_MAX_SSIZE 0x0ffff /* Maximum gather particle size */ ++#define SAFE_MAX_DMA 0xfffff /* Maximum PE operand size (20 bits) */ ++/* total src+dst particle descriptors */ ++#define SAFE_TOTAL_DPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) ++#define SAFE_TOTAL_SPART (SAFE_MAX_NQUEUE * SAFE_MAX_PART) ++ ++#define SAFE_RNG_MAXBUFSIZ 128 /* 32-bit words */ ++ ++#define SAFE_CARD(sid) (((sid) & 0xf0000000) >> 28) ++#define SAFE_SESSION(sid) ( (sid) & 0x0fffffff) ++#define SAFE_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) ++ ++#define SAFE_DEF_RTY 0xff /* PCI Retry Timeout */ ++#define SAFE_DEF_TOUT 0xff /* PCI TRDY Timeout */ ++#define SAFE_DEF_CACHELINE 0x01 /* Cache Line setting */ ++ ++#ifdef __KERNEL__ ++/* ++ * State associated with the allocation of each chunk ++ * of memory setup for DMA. ++ */ ++struct safe_dma_alloc { ++ dma_addr_t dma_paddr; ++ void *dma_vaddr; ++}; ++ ++/* ++ * Cryptographic operand state. One of these exists for each ++ * source and destination operand passed in from the crypto ++ * subsystem. When possible source and destination operands ++ * refer to the same memory. More often they are distinct. ++ * We track the virtual address of each operand as well as ++ * where each is mapped for DMA. ++ */ ++struct safe_operand { ++ union { ++ struct sk_buff *skb; ++ struct uio *io; ++ } u; ++ void *map; ++ int mapsize; /* total number of bytes in segs */ ++ struct { ++ dma_addr_t ds_addr; ++ int ds_len; ++ int ds_tlen; ++ } segs[SAFE_MAX_PART]; ++ int nsegs; ++}; ++ ++/* ++ * Packet engine ring entry and cryptographic operation state. ++ * The packet engine requires a ring of descriptors that contain ++ * pointers to various cryptographic state. However the ring ++ * configuration register allows you to specify an arbitrary size ++ * for ring entries. We use this feature to collect most of the ++ * state for each cryptographic request into one spot. Other than ++ * ring entries only the ``particle descriptors'' (scatter/gather ++ * lists) and the actual operand data are kept separate. The ++ * particle descriptors must also be organized in rings. The ++ * operand data can be located aribtrarily (modulo alignment constraints). ++ * ++ * Note that the descriptor ring is mapped onto the PCI bus so ++ * the hardware can DMA data. This means the entire ring must be ++ * contiguous. ++ */ ++struct safe_ringentry { ++ struct safe_desc re_desc; /* command descriptor */ ++ struct safe_sarec re_sa; /* SA record */ ++ struct safe_sastate re_sastate; /* SA state record */ ++ ++ struct cryptop *re_crp; /* crypto operation */ ++ ++ struct safe_operand re_src; /* source operand */ ++ struct safe_operand re_dst; /* destination operand */ ++ ++ int re_sesn; /* crypto session ID */ ++ int re_flags; ++#define SAFE_QFLAGS_COPYOUTIV 0x1 /* copy back on completion */ ++#define SAFE_QFLAGS_COPYOUTICV 0x2 /* copy back on completion */ ++}; ++ ++#define re_src_skb re_src.u.skb ++#define re_src_io re_src.u.io ++#define re_src_map re_src.map ++#define re_src_nsegs re_src.nsegs ++#define re_src_segs re_src.segs ++#define re_src_mapsize re_src.mapsize ++ ++#define re_dst_skb re_dst.u.skb ++#define re_dst_io re_dst.u.io ++#define re_dst_map re_dst.map ++#define re_dst_nsegs re_dst.nsegs ++#define re_dst_segs re_dst.segs ++#define re_dst_mapsize re_dst.mapsize ++ ++struct rndstate_test; ++ ++struct safe_session { ++ u_int32_t ses_used; ++ u_int32_t ses_klen; /* key length in bits */ ++ u_int32_t ses_key[8]; /* DES/3DES/AES key */ ++ u_int32_t ses_mlen; /* hmac length in bytes */ ++ u_int32_t ses_hminner[5]; /* hmac inner state */ ++ u_int32_t ses_hmouter[5]; /* hmac outer state */ ++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */ ++}; ++ ++struct safe_pkq { ++ struct list_head pkq_list; ++ struct cryptkop *pkq_krp; ++}; ++ ++struct safe_softc { ++ softc_device_decl sc_dev; ++ u32 sc_irq; ++ ++ struct pci_dev *sc_pcidev; ++ ocf_iomem_t sc_base_addr; ++ ++ u_int sc_chiprev; /* major/minor chip revision */ ++ int sc_flags; /* device specific flags */ ++#define SAFE_FLAGS_KEY 0x01 /* has key accelerator */ ++#define SAFE_FLAGS_RNG 0x02 /* hardware rng */ ++ int sc_suspended; ++ int sc_needwakeup; /* notify crypto layer */ ++ int32_t sc_cid; /* crypto tag */ ++ ++ struct safe_dma_alloc sc_ringalloc; /* PE ring allocation state */ ++ struct safe_ringentry *sc_ring; /* PE ring */ ++ struct safe_ringentry *sc_ringtop; /* PE ring top */ ++ struct safe_ringentry *sc_front; /* next free entry */ ++ struct safe_ringentry *sc_back; /* next pending entry */ ++ int sc_nqchip; /* # passed to chip */ ++ spinlock_t sc_ringmtx; /* PE ring lock */ ++ struct safe_pdesc *sc_spring; /* src particle ring */ ++ struct safe_pdesc *sc_springtop; /* src particle ring top */ ++ struct safe_pdesc *sc_spfree; /* next free src particle */ ++ struct safe_dma_alloc sc_spalloc; /* src particle ring state */ ++ struct safe_pdesc *sc_dpring; /* dest particle ring */ ++ struct safe_pdesc *sc_dpringtop; /* dest particle ring top */ ++ struct safe_pdesc *sc_dpfree; /* next free dest particle */ ++ struct safe_dma_alloc sc_dpalloc; /* dst particle ring state */ ++ int sc_nsessions; /* # of sessions */ ++ struct safe_session *sc_sessions; /* sessions */ ++ ++ struct timer_list sc_pkto; /* PK polling */ ++ spinlock_t sc_pkmtx; /* PK lock */ ++ struct list_head sc_pkq; /* queue of PK requests */ ++ struct safe_pkq *sc_pkq_cur; /* current processing request */ ++ u_int32_t sc_pk_reslen, sc_pk_resoff; ++ ++ int sc_max_dsize; /* maximum safe DMA size */ ++}; ++#endif /* __KERNEL__ */ ++ ++struct safe_stats { ++ u_int64_t st_ibytes; ++ u_int64_t st_obytes; ++ u_int32_t st_ipackets; ++ u_int32_t st_opackets; ++ u_int32_t st_invalid; /* invalid argument */ ++ u_int32_t st_badsession; /* invalid session id */ ++ u_int32_t st_badflags; /* flags indicate !(mbuf | uio) */ ++ u_int32_t st_nodesc; /* op submitted w/o descriptors */ ++ u_int32_t st_badalg; /* unsupported algorithm */ ++ u_int32_t st_ringfull; /* PE descriptor ring full */ ++ u_int32_t st_peoperr; /* PE marked error */ ++ u_int32_t st_dmaerr; /* PE DMA error */ ++ u_int32_t st_bypasstoobig; /* bypass > 96 bytes */ ++ u_int32_t st_skipmismatch; /* enc part begins before auth part */ ++ u_int32_t st_lenmismatch; /* enc length different auth length */ ++ u_int32_t st_coffmisaligned; /* crypto offset not 32-bit aligned */ ++ u_int32_t st_cofftoobig; /* crypto offset > 255 words */ ++ u_int32_t st_iovmisaligned; /* iov op not aligned */ ++ u_int32_t st_iovnotuniform; /* iov op not suitable */ ++ u_int32_t st_unaligned; /* unaligned src caused copy */ ++ u_int32_t st_notuniform; /* non-uniform src caused copy */ ++ u_int32_t st_nomap; /* bus_dmamap_create failed */ ++ u_int32_t st_noload; /* bus_dmamap_load_* failed */ ++ u_int32_t st_nombuf; /* MGET* failed */ ++ u_int32_t st_nomcl; /* MCLGET* failed */ ++ u_int32_t st_maxqchip; /* max mcr1 ops out for processing */ ++ u_int32_t st_rng; /* RNG requests */ ++ u_int32_t st_rngalarm; /* RNG alarm requests */ ++ u_int32_t st_noicvcopy; /* ICV data copies suppressed */ ++}; ++#endif /* _SAFE_SAFEVAR_H_ */ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/sha1.c linux-2.6.30/crypto/ocf/safe/sha1.c +--- linux-2.6.30.orig/crypto/ocf/safe/sha1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/sha1.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,279 @@ ++/* $KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++/* ++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) ++ * based on: http://csrc.nist.gov/fips/fip180-1.txt ++ * implemented by Jun-ichiro itojun Itoh ++ */ ++ ++#if 0 ++#include ++__FBSDID("$FreeBSD: src/sys/crypto/sha1.c,v 1.9 2003/06/10 21:36:57 obrien Exp $"); ++ ++#include ++#include ++#include ++#include ++ ++#include ++#endif ++ ++/* sanity check */ ++#if BYTE_ORDER != BIG_ENDIAN ++# if BYTE_ORDER != LITTLE_ENDIAN ++# define unsupported 1 ++# endif ++#endif ++ ++#ifndef unsupported ++ ++/* constant table */ ++static u_int32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; ++#define K(t) _K[(t) / 20] ++ ++#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) ++#define F1(b, c, d) (((b) ^ (c)) ^ (d)) ++#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) ++#define F3(b, c, d) (((b) ^ (c)) ^ (d)) ++ ++#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) ++ ++#undef H ++#define H(n) (ctxt->h.b32[(n)]) ++#define COUNT (ctxt->count) ++#define BCOUNT (ctxt->c.b64[0] / 8) ++#define W(n) (ctxt->m.b32[(n)]) ++ ++#define PUTBYTE(x) { \ ++ ctxt->m.b8[(COUNT % 64)] = (x); \ ++ COUNT++; \ ++ COUNT %= 64; \ ++ ctxt->c.b64[0] += 8; \ ++ if (COUNT % 64 == 0) \ ++ sha1_step(ctxt); \ ++ } ++ ++#define PUTPAD(x) { \ ++ ctxt->m.b8[(COUNT % 64)] = (x); \ ++ COUNT++; \ ++ COUNT %= 64; \ ++ if (COUNT % 64 == 0) \ ++ sha1_step(ctxt); \ ++ } ++ ++static void sha1_step(struct sha1_ctxt *); ++ ++static void ++sha1_step(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ u_int32_t a, b, c, d, e; ++ size_t t, s; ++ u_int32_t tmp; ++ ++#if BYTE_ORDER == LITTLE_ENDIAN ++ struct sha1_ctxt tctxt; ++ bcopy(&ctxt->m.b8[0], &tctxt.m.b8[0], 64); ++ ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; ++ ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; ++ ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; ++ ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; ++ ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; ++ ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; ++ ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; ++ ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; ++ ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; ++ ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; ++ ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; ++ ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; ++ ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; ++ ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; ++ ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; ++ ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; ++ ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; ++ ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; ++ ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; ++ ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; ++ ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; ++ ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; ++ ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; ++ ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; ++ ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; ++ ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; ++ ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; ++ ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; ++ ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; ++ ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; ++ ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; ++ ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; ++#endif ++ ++ a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); ++ ++ for (t = 0; t < 20; t++) { ++ s = t & 0x0f; ++ if (t >= 16) { ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ } ++ tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 20; t < 40; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 40; t < 60; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ for (t = 60; t < 80; t++) { ++ s = t & 0x0f; ++ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); ++ tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); ++ e = d; d = c; c = S(30, b); b = a; a = tmp; ++ } ++ ++ H(0) = H(0) + a; ++ H(1) = H(1) + b; ++ H(2) = H(2) + c; ++ H(3) = H(3) + d; ++ H(4) = H(4) + e; ++ ++ bzero(&ctxt->m.b8[0], 64); ++} ++ ++/*------------------------------------------------------------*/ ++ ++void ++sha1_init(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ bzero(ctxt, sizeof(struct sha1_ctxt)); ++ H(0) = 0x67452301; ++ H(1) = 0xefcdab89; ++ H(2) = 0x98badcfe; ++ H(3) = 0x10325476; ++ H(4) = 0xc3d2e1f0; ++} ++ ++void ++sha1_pad(ctxt) ++ struct sha1_ctxt *ctxt; ++{ ++ size_t padlen; /*pad length in bytes*/ ++ size_t padstart; ++ ++ PUTPAD(0x80); ++ ++ padstart = COUNT % 64; ++ padlen = 64 - padstart; ++ if (padlen < 8) { ++ bzero(&ctxt->m.b8[padstart], padlen); ++ COUNT += padlen; ++ COUNT %= 64; ++ sha1_step(ctxt); ++ padstart = COUNT % 64; /* should be 0 */ ++ padlen = 64 - padstart; /* should be 64 */ ++ } ++ bzero(&ctxt->m.b8[padstart], padlen - 8); ++ COUNT += (padlen - 8); ++ COUNT %= 64; ++#if BYTE_ORDER == BIG_ENDIAN ++ PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); ++ PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); ++ PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); ++ PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); ++#else ++ PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); ++ PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); ++ PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); ++ PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); ++#endif ++} ++ ++void ++sha1_loop(ctxt, input, len) ++ struct sha1_ctxt *ctxt; ++ const u_int8_t *input; ++ size_t len; ++{ ++ size_t gaplen; ++ size_t gapstart; ++ size_t off; ++ size_t copysiz; ++ ++ off = 0; ++ ++ while (off < len) { ++ gapstart = COUNT % 64; ++ gaplen = 64 - gapstart; ++ ++ copysiz = (gaplen < len - off) ? gaplen : len - off; ++ bcopy(&input[off], &ctxt->m.b8[gapstart], copysiz); ++ COUNT += copysiz; ++ COUNT %= 64; ++ ctxt->c.b64[0] += copysiz * 8; ++ if (COUNT % 64 == 0) ++ sha1_step(ctxt); ++ off += copysiz; ++ } ++} ++ ++void ++sha1_result(ctxt, digest0) ++ struct sha1_ctxt *ctxt; ++ caddr_t digest0; ++{ ++ u_int8_t *digest; ++ ++ digest = (u_int8_t *)digest0; ++ sha1_pad(ctxt); ++#if BYTE_ORDER == BIG_ENDIAN ++ bcopy(&ctxt->h.b8[0], digest, 20); ++#else ++ digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; ++ digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; ++ digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; ++ digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; ++ digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; ++ digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; ++ digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; ++ digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; ++ digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; ++ digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; ++#endif ++} ++ ++#endif /*unsupported*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/safe/sha1.h linux-2.6.30/crypto/ocf/safe/sha1.h +--- linux-2.6.30.orig/crypto/ocf/safe/sha1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/safe/sha1.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* $FreeBSD: src/sys/crypto/sha1.h,v 1.8 2002/03/20 05:13:50 alfred Exp $ */ ++/* $KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ ++ ++/* ++ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the project nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++/* ++ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) ++ * based on: http://csrc.nist.gov/fips/fip180-1.txt ++ * implemented by Jun-ichiro itojun Itoh ++ */ ++ ++#ifndef _NETINET6_SHA1_H_ ++#define _NETINET6_SHA1_H_ ++ ++struct sha1_ctxt { ++ union { ++ u_int8_t b8[20]; ++ u_int32_t b32[5]; ++ } h; ++ union { ++ u_int8_t b8[8]; ++ u_int64_t b64[1]; ++ } c; ++ union { ++ u_int8_t b8[64]; ++ u_int32_t b32[16]; ++ } m; ++ u_int8_t count; ++}; ++ ++#ifdef __KERNEL__ ++extern void sha1_init(struct sha1_ctxt *); ++extern void sha1_pad(struct sha1_ctxt *); ++extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t); ++extern void sha1_result(struct sha1_ctxt *, caddr_t); ++ ++/* compatibilty with other SHA1 source codes */ ++typedef struct sha1_ctxt SHA1_CTX; ++#define SHA1Init(x) sha1_init((x)) ++#define SHA1Update(x, y, z) sha1_loop((x), (y), (z)) ++#define SHA1Final(x, y) sha1_result((y), (x)) ++#endif /* __KERNEL__ */ ++ ++#define SHA1_RESULTLEN (160/8) ++ ++#endif /*_NETINET6_SHA1_H_*/ +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/Makefile linux-2.6.30/crypto/ocf/talitos/Makefile +--- linux-2.6.30.orig/crypto/ocf/talitos/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/Makefile 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,12 @@ ++# for SGlinux builds ++-include $(ROOTDIR)/modules/.config ++ ++obj-$(CONFIG_OCF_TALITOS) += talitos.o ++ ++obj ?= . ++EXTRA_CFLAGS += -I$(obj)/.. -I$(obj)/ ++ ++ifdef TOPDIR ++-include $(TOPDIR)/Rules.make ++endif ++ +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos.c linux-2.6.30/crypto/ocf/talitos/talitos.c +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos.c 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,1359 @@ ++/* ++ * crypto/ocf/talitos/talitos.c ++ * ++ * An OCF-Linux module that uses Freescale's SEC to do the crypto. ++ * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * This code written by Kim A. B. Phillips ++ * some code copied from files with the following: ++ * Copyright (C) 2004-2007 David McCullough ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* dma_map_single() */ ++#include ++ ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++#include ++#endif ++ ++#include ++#include ++ ++#define DRV_NAME "talitos" ++ ++#include "talitos_dev.h" ++#include "talitos_soft.h" ++ ++#define read_random(p,l) get_random_bytes(p,l) ++ ++const char talitos_driver_name[] = "Talitos OCF"; ++const char talitos_driver_version[] = "0.2"; ++ ++static int talitos_newsession(device_t dev, u_int32_t *sidp, ++ struct cryptoini *cri); ++static int talitos_freesession(device_t dev, u_int64_t tid); ++static int talitos_process(device_t dev, struct cryptop *crp, int hint); ++static void dump_talitos_status(struct talitos_softc *sc); ++static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td, ++ int chsel); ++static void talitos_doneprocessing(struct talitos_softc *sc); ++static void talitos_init_device(struct talitos_softc *sc); ++static void talitos_reset_device_master(struct talitos_softc *sc); ++static void talitos_reset_device(struct talitos_softc *sc); ++static void talitos_errorprocessing(struct talitos_softc *sc); ++#ifdef CONFIG_PPC_MERGE ++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match); ++static int talitos_remove(struct of_device *ofdev); ++#else ++static int talitos_probe(struct platform_device *pdev); ++static int talitos_remove(struct platform_device *pdev); ++#endif ++#ifdef CONFIG_OCF_RANDOMHARVEST ++static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords); ++static void talitos_rng_init(struct talitos_softc *sc); ++#endif ++ ++static device_method_t talitos_methods = { ++ /* crypto device methods */ ++ DEVMETHOD(cryptodev_newsession, talitos_newsession), ++ DEVMETHOD(cryptodev_freesession,talitos_freesession), ++ DEVMETHOD(cryptodev_process, talitos_process), ++}; ++ ++#define debug talitos_debug ++int talitos_debug = 0; ++module_param(talitos_debug, int, 0644); ++MODULE_PARM_DESC(talitos_debug, "Enable debug"); ++ ++static inline void talitos_write(volatile unsigned *addr, u32 val) ++{ ++ out_be32(addr, val); ++} ++ ++static inline u32 talitos_read(volatile unsigned *addr) ++{ ++ u32 val; ++ val = in_be32(addr); ++ return val; ++} ++ ++static void dump_talitos_status(struct talitos_softc *sc) ++{ ++ unsigned int v, v_hi, i, *ptr; ++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI); ++ printk(KERN_INFO "%s: MCR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); ++ printk(KERN_INFO "%s: IMR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); ++ printk(KERN_INFO "%s: ISR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CDPR); ++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CDPR_HI); ++ printk(KERN_INFO "%s: CDPR ch%d 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), i, v, v_hi); ++ } ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCPSR); ++ v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCPSR_HI); ++ printk(KERN_INFO "%s: CCPSR ch%d 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), i, v, v_hi); ++ } ++ ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF; ++ for (i = 0; i < 16; i++) { ++ v = talitos_read(ptr++); v_hi = talitos_read(ptr++); ++ printk(KERN_INFO "%s: DESCBUF ch0 0x%08x_%08x (tdp%02d)\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi, i); ++ } ++ return; ++} ++ ++ ++#ifdef CONFIG_OCF_RANDOMHARVEST ++/* ++ * pull random numbers off the RNG FIFO, not exceeding amount available ++ */ ++static int ++talitos_read_random(void *arg, u_int32_t *buf, int maxwords) ++{ ++ struct talitos_softc *sc = (struct talitos_softc *) arg; ++ int rc; ++ u_int32_t v; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* check for things like FIFO underflow */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); ++ if (unlikely(v)) { ++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n", ++ device_get_nameunit(sc->sc_cdev), v); ++ return 0; ++ } ++ /* ++ * OFL is number of available 64-bit words, ++ * shift and convert to a 32-bit word count ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI); ++ v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1); ++ if (maxwords > v) ++ maxwords = v; ++ for (rc = 0; rc < maxwords; rc++) { ++ buf[rc] = talitos_read(sc->sc_base_addr + ++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); ++ } ++ if (maxwords & 1) { ++ /* ++ * RNG will complain with an AE in the RNGISR ++ * if we don't complete the pairs of 32-bit reads ++ * to its 64-bit register based FIFO ++ */ ++ v = talitos_read(sc->sc_base_addr + ++ TALITOS_RNG_FIFO + rc*sizeof(u_int32_t)); ++ } ++ ++ return rc; ++} ++ ++static void ++talitos_rng_init(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ /* reset RNG EU */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI); ++ v |= TALITOS_RNGRCR_HI_SR; ++ talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v); ++ while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI) ++ & TALITOS_RNGSR_HI_RD) == 0) ++ cpu_relax(); ++ /* ++ * we tell the RNG to start filling the RNG FIFO ++ * by writing the RNGDSR ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI); ++ talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v); ++ /* ++ * 64 bits of data will be pushed onto the FIFO every ++ * 256 SEC cycles until the FIFO is full. The RNG then ++ * attempts to keep the FIFO full. ++ */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI); ++ if (v) { ++ printk(KERN_ERR "%s: RNGISR_HI error %08x\n", ++ device_get_nameunit(sc->sc_cdev), v); ++ return; ++ } ++ /* ++ * n.b. we need to add a FIPS test here - if the RNG is going ++ * to fail, it's going to fail at reset time ++ */ ++ return; ++} ++#endif /* CONFIG_OCF_RANDOMHARVEST */ ++ ++/* ++ * Generate a new software session. ++ */ ++static int ++talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) ++{ ++ struct cryptoini *c, *encini = NULL, *macini = NULL; ++ struct talitos_softc *sc = device_get_softc(dev); ++ struct talitos_session *ses = NULL; ++ int sesn; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sidp == NULL || cri == NULL || sc == NULL) { ++ DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__); ++ return EINVAL; ++ } ++ for (c = cri; c != NULL; c = c->cri_next) { ++ if (c->cri_alg == CRYPTO_MD5 || ++ c->cri_alg == CRYPTO_MD5_HMAC || ++ c->cri_alg == CRYPTO_SHA1 || ++ c->cri_alg == CRYPTO_SHA1_HMAC || ++ c->cri_alg == CRYPTO_NULL_HMAC) { ++ if (macini) ++ return EINVAL; ++ macini = c; ++ } else if (c->cri_alg == CRYPTO_DES_CBC || ++ c->cri_alg == CRYPTO_3DES_CBC || ++ c->cri_alg == CRYPTO_AES_CBC || ++ c->cri_alg == CRYPTO_NULL_CBC) { ++ if (encini) ++ return EINVAL; ++ encini = c; ++ } else { ++ DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg); ++ return EINVAL; ++ } ++ } ++ if (encini == NULL && macini == NULL) ++ return EINVAL; ++ if (encini) { ++ /* validate key length */ ++ switch (encini->cri_alg) { ++ case CRYPTO_DES_CBC: ++ if (encini->cri_klen != 64) ++ return EINVAL; ++ break; ++ case CRYPTO_3DES_CBC: ++ if (encini->cri_klen != 192) { ++ return EINVAL; ++ } ++ break; ++ case CRYPTO_AES_CBC: ++ if (encini->cri_klen != 128 && ++ encini->cri_klen != 192 && ++ encini->cri_klen != 256) ++ return EINVAL; ++ break; ++ default: ++ DPRINTF("UNKNOWN encini->cri_alg %d\n", ++ encini->cri_alg); ++ return EINVAL; ++ } ++ } ++ ++ if (sc->sc_sessions == NULL) { ++ ses = sc->sc_sessions = (struct talitos_session *) ++ kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC); ++ if (ses == NULL) ++ return ENOMEM; ++ memset(ses, 0, sizeof(struct talitos_session)); ++ sesn = 0; ++ sc->sc_nsessions = 1; ++ } else { ++ for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { ++ if (sc->sc_sessions[sesn].ses_used == 0) { ++ ses = &sc->sc_sessions[sesn]; ++ break; ++ } ++ } ++ ++ if (ses == NULL) { ++ /* allocating session */ ++ sesn = sc->sc_nsessions; ++ ses = (struct talitos_session *) kmalloc( ++ (sesn + 1) * sizeof(struct talitos_session), ++ SLAB_ATOMIC); ++ if (ses == NULL) ++ return ENOMEM; ++ memset(ses, 0, ++ (sesn + 1) * sizeof(struct talitos_session)); ++ memcpy(ses, sc->sc_sessions, ++ sesn * sizeof(struct talitos_session)); ++ memset(sc->sc_sessions, 0, ++ sesn * sizeof(struct talitos_session)); ++ kfree(sc->sc_sessions); ++ sc->sc_sessions = ses; ++ ses = &sc->sc_sessions[sesn]; ++ sc->sc_nsessions++; ++ } ++ } ++ ++ ses->ses_used = 1; ++ ++ if (encini) { ++ /* get an IV */ ++ /* XXX may read fewer than requested */ ++ read_random(ses->ses_iv, sizeof(ses->ses_iv)); ++ ++ ses->ses_klen = (encini->cri_klen + 7) / 8; ++ memcpy(ses->ses_key, encini->cri_key, ses->ses_klen); ++ if (macini) { ++ /* doing hash on top of cipher */ ++ ses->ses_hmac_len = (macini->cri_klen + 7) / 8; ++ memcpy(ses->ses_hmac, macini->cri_key, ++ ses->ses_hmac_len); ++ } ++ } else if (macini) { ++ /* doing hash */ ++ ses->ses_klen = (macini->cri_klen + 7) / 8; ++ memcpy(ses->ses_key, macini->cri_key, ses->ses_klen); ++ } ++ ++ /* back compat way of determining MSC result len */ ++ if (macini) { ++ ses->ses_mlen = macini->cri_mlen; ++ if (ses->ses_mlen == 0) { ++ if (macini->cri_alg == CRYPTO_MD5_HMAC) ++ ses->ses_mlen = MD5_HASH_LEN; ++ else ++ ses->ses_mlen = SHA1_HASH_LEN; ++ } ++ } ++ ++ /* really should make up a template td here, ++ * and only fill things like i/o and direction in process() */ ++ ++ /* assign session ID */ ++ *sidp = TALITOS_SID(sc->sc_num, sesn); ++ return 0; ++} ++ ++/* ++ * Deallocate a session. ++ */ ++static int ++talitos_freesession(device_t dev, u_int64_t tid) ++{ ++ struct talitos_softc *sc = device_get_softc(dev); ++ int session, ret; ++ u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; ++ ++ if (sc == NULL) ++ return EINVAL; ++ session = TALITOS_SESSION(sid); ++ if (session < sc->sc_nsessions) { ++ memset(&sc->sc_sessions[session], 0, ++ sizeof(sc->sc_sessions[session])); ++ ret = 0; ++ } else ++ ret = EINVAL; ++ return ret; ++} ++ ++/* ++ * launch device processing - it will come back with done notification ++ * in the form of an interrupt and/or HDR_DONE_BITS in header ++ */ ++static int ++talitos_submit( ++ struct talitos_softc *sc, ++ struct talitos_desc *td, ++ int chsel) ++{ ++ u_int32_t v; ++ ++ v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE); ++ talitos_write(sc->sc_base_addr + ++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0); ++ talitos_write(sc->sc_base_addr + ++ chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v); ++ return 0; ++} ++ ++static int ++talitos_process(device_t dev, struct cryptop *crp, int hint) ++{ ++ int i, err = 0, ivsize; ++ struct talitos_softc *sc = device_get_softc(dev); ++ struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; ++ caddr_t iv; ++ struct talitos_session *ses; ++ struct talitos_desc *td; ++ unsigned long flags; ++ /* descriptor mappings */ ++ int hmac_key, hmac_data, cipher_iv, cipher_key, ++ in_fifo, out_fifo, cipher_iv_out; ++ static int chsel = -1; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ if (crp == NULL || crp->crp_callback == NULL || sc == NULL) { ++ return EINVAL; ++ } ++ crp->crp_etype = 0; ++ if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) { ++ return EINVAL; ++ } ++ ++ ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)]; ++ ++ /* enter the channel scheduler */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ /* reuse channel that already had/has requests for the required EU */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg) ++ break; ++ } ++ if (i == sc->sc_num_channels) { ++ /* ++ * haven't seen this algo the last sc_num_channels or more ++ * use round robin in this case ++ * nb: sc->sc_num_channels must be power of 2 ++ */ ++ chsel = (chsel + 1) & (sc->sc_num_channels - 1); ++ } else { ++ /* ++ * matches channel with same target execution unit; ++ * use same channel in this case ++ */ ++ chsel = i; ++ } ++ sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg; ++ ++ /* release the channel scheduler lock */ ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ /* acquire the selected channel fifo lock */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags); ++ ++ /* find and reserve next available descriptor-cryptop pair */ ++ for (i = 0; i < sc->sc_chfifo_len; i++) { ++ if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) { ++ /* ++ * ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 for MD/HMAC descs ++ */ ++ memset(&sc->sc_chnfifo[chsel][i].cf_desc, ++ 0, sizeof(*td)); ++ /* reserve it with done notification request bit */ ++ sc->sc_chnfifo[chsel][i].cf_desc.hdr |= ++ TALITOS_DONE_NOTIFY; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags); ++ ++ if (i == sc->sc_chfifo_len) { ++ /* fifo full */ ++ err = ERESTART; ++ goto errout; ++ } ++ ++ td = &sc->sc_chnfifo[chsel][i].cf_desc; ++ sc->sc_chnfifo[chsel][i].cf_crp = crp; ++ ++ crd1 = crp->crp_desc; ++ if (crd1 == NULL) { ++ err = EINVAL; ++ goto errout; ++ } ++ crd2 = crd1->crd_next; ++ /* prevent compiler warning */ ++ hmac_key = 0; ++ hmac_data = 0; ++ if (crd2 == NULL) { ++ td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU; ++ /* assign descriptor dword ptr mappings for this desc. type */ ++ cipher_iv = 1; ++ cipher_key = 2; ++ in_fifo = 3; ++ cipher_iv_out = 5; ++ if (crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1 || ++ crd1->crd_alg == CRYPTO_MD5) { ++ out_fifo = 5; ++ maccrd = crd1; ++ enccrd = NULL; ++ } else if (crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4) { ++ out_fifo = 4; ++ maccrd = NULL; ++ enccrd = crd1; ++ } else { ++ DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg); ++ err = EINVAL; ++ goto errout; ++ } ++ } else { ++ if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) { ++ td->hdr |= TD_TYPE_IPSEC_ESP; ++ } else { ++ DPRINTF("unimplemented: multiple descriptor ipsec\n"); ++ err = EINVAL; ++ goto errout; ++ } ++ /* assign descriptor dword ptr mappings for this desc. type */ ++ hmac_key = 0; ++ hmac_data = 1; ++ cipher_iv = 2; ++ cipher_key = 3; ++ in_fifo = 4; ++ out_fifo = 5; ++ cipher_iv_out = 6; ++ if ((crd1->crd_alg == CRYPTO_MD5_HMAC || ++ crd1->crd_alg == CRYPTO_SHA1_HMAC || ++ crd1->crd_alg == CRYPTO_MD5 || ++ crd1->crd_alg == CRYPTO_SHA1) && ++ (crd2->crd_alg == CRYPTO_DES_CBC || ++ crd2->crd_alg == CRYPTO_3DES_CBC || ++ crd2->crd_alg == CRYPTO_AES_CBC || ++ crd2->crd_alg == CRYPTO_ARC4) && ++ ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { ++ maccrd = crd1; ++ enccrd = crd2; ++ } else if ((crd1->crd_alg == CRYPTO_DES_CBC || ++ crd1->crd_alg == CRYPTO_ARC4 || ++ crd1->crd_alg == CRYPTO_3DES_CBC || ++ crd1->crd_alg == CRYPTO_AES_CBC) && ++ (crd2->crd_alg == CRYPTO_MD5_HMAC || ++ crd2->crd_alg == CRYPTO_SHA1_HMAC || ++ crd2->crd_alg == CRYPTO_MD5 || ++ crd2->crd_alg == CRYPTO_SHA1) && ++ (crd1->crd_flags & CRD_F_ENCRYPT)) { ++ enccrd = crd1; ++ maccrd = crd2; ++ } else { ++ /* We cannot order the SEC as requested */ ++ printk("%s: cannot do the order\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ } ++ /* assign in_fifo and out_fifo based on input/output struct type */ ++ if (crp->crp_flags & CRYPTO_F_SKBUF) { ++ /* using SKB buffers */ ++ struct sk_buff *skb = (struct sk_buff *)crp->crp_buf; ++ if (skb_shinfo(skb)->nr_frags) { ++ printk("%s: skb frags unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = skb->len; ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = skb->len; ++ td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ } else if (crp->crp_flags & CRYPTO_F_IOV) { ++ /* using IOV buffers */ ++ struct uio *uiop = (struct uio *)crp->crp_buf; ++ if (uiop->uio_iovcnt > 1) { ++ printk("%s: iov frags unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, ++ uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = crp->crp_ilen; ++ /* crp_olen is never set; always use crp_ilen */ ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, ++ uiop->uio_iov->iov_base, ++ crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = crp->crp_ilen; ++ } else { ++ /* using contig buffers */ ++ td->ptr[in_fifo].ptr = dma_map_single(NULL, ++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[in_fifo].len = crp->crp_ilen; ++ td->ptr[out_fifo].ptr = dma_map_single(NULL, ++ crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE); ++ td->ptr[out_fifo].len = crp->crp_ilen; ++ } ++ if (enccrd) { ++ switch (enccrd->crd_alg) { ++ case CRYPTO_3DES_CBC: ++ td->hdr |= TALITOS_MODE0_DEU_3DES; ++ /* FALLTHROUGH */ ++ case CRYPTO_DES_CBC: ++ td->hdr |= TALITOS_SEL0_DEU ++ | TALITOS_MODE0_DEU_CBC; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ td->hdr |= TALITOS_MODE0_DEU_ENC; ++ ivsize = 2*sizeof(u_int32_t); ++ DPRINTF("%cDES ses %d ch %d len %d\n", ++ (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1', ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_AES_CBC: ++ td->hdr |= TALITOS_SEL0_AESU ++ | TALITOS_MODE0_AESU_CBC; ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) ++ td->hdr |= TALITOS_MODE0_AESU_ENC; ++ ivsize = 4*sizeof(u_int32_t); ++ DPRINTF("AES ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ default: ++ printk("%s: unimplemented enccrd->crd_alg %d\n", ++ device_get_nameunit(sc->sc_cdev), enccrd->crd_alg); ++ err = EINVAL; ++ goto errout; ++ } ++ /* ++ * Setup encrypt/decrypt state. When using basic ops ++ * we can't use an inline IV because hash/crypt offset ++ * must be from the end of the IV to the start of the ++ * crypt data and this leaves out the preceding header ++ * from the hash calculation. Instead we place the IV ++ * in the state record and set the hash/crypt offset to ++ * copy both the header+IV. ++ */ ++ if (enccrd->crd_flags & CRD_F_ENCRYPT) { ++ td->hdr |= TALITOS_DIR_OUTBOUND; ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) ++ iv = enccrd->crd_iv; ++ else ++ iv = (caddr_t) ses->ses_iv; ++ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { ++ crypto_copyback(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ } else { ++ td->hdr |= TALITOS_DIR_INBOUND; ++ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { ++ iv = enccrd->crd_iv; ++ bcopy(enccrd->crd_iv, iv, ivsize); ++ } else { ++ iv = (caddr_t) ses->ses_iv; ++ crypto_copydata(crp->crp_flags, crp->crp_buf, ++ enccrd->crd_inject, ivsize, iv); ++ } ++ } ++ td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize, ++ DMA_TO_DEVICE); ++ td->ptr[cipher_iv].len = ivsize; ++ /* ++ * we don't need the cipher iv out length/pointer ++ * field to do ESP IPsec. Therefore we set the len field as 0, ++ * which tells the SEC not to do anything with this len/ptr ++ * field. Previously, when length/pointer as pointing to iv, ++ * it gave us corruption of packets. ++ */ ++ td->ptr[cipher_iv_out].len = 0; ++ } ++ if (enccrd && maccrd) { ++ /* this is ipsec only for now */ ++ td->hdr |= TALITOS_SEL1_MDEU ++ | TALITOS_MODE1_MDEU_INIT ++ | TALITOS_MODE1_MDEU_PAD; ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ td->hdr |= TALITOS_MODE1_MDEU_MD5; ++ break; ++ case CRYPTO_MD5_HMAC: ++ td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC; ++ break; ++ case CRYPTO_SHA1: ++ td->hdr |= TALITOS_MODE1_MDEU_SHA1; ++ break; ++ case CRYPTO_SHA1_HMAC: ++ td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC; ++ break; ++ default: ++ /* We cannot order the SEC as requested */ ++ printk("%s: cannot do the order\n", ++ device_get_nameunit(sc->sc_cdev)); ++ err = EINVAL; ++ goto errout; ++ } ++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || ++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { ++ /* ++ * The offset from hash data to the start of ++ * crypt data is the difference in the skips. ++ */ ++ /* ipsec only for now */ ++ td->ptr[hmac_key].ptr = dma_map_single(NULL, ++ ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE); ++ td->ptr[hmac_key].len = ses->ses_hmac_len; ++ td->ptr[in_fifo].ptr += enccrd->crd_skip; ++ td->ptr[in_fifo].len = enccrd->crd_len; ++ td->ptr[out_fifo].ptr += enccrd->crd_skip; ++ td->ptr[out_fifo].len = enccrd->crd_len; ++ /* bytes of HMAC to postpend to ciphertext */ ++ td->ptr[out_fifo].extent = ses->ses_mlen; ++ td->ptr[hmac_data].ptr += maccrd->crd_skip; ++ td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip; ++ } ++ if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { ++ printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n", ++ device_get_nameunit(sc->sc_cdev)); ++ } ++ } ++ if (!enccrd && maccrd) { ++ /* single MD5 or SHA */ ++ td->hdr |= TALITOS_SEL0_MDEU ++ | TALITOS_MODE0_MDEU_INIT ++ | TALITOS_MODE0_MDEU_PAD; ++ switch (maccrd->crd_alg) { ++ case CRYPTO_MD5: ++ td->hdr |= TALITOS_MODE0_MDEU_MD5; ++ DPRINTF("MD5 ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_MD5_HMAC: ++ td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC; ++ break; ++ case CRYPTO_SHA1: ++ td->hdr |= TALITOS_MODE0_MDEU_SHA1; ++ DPRINTF("SHA1 ses %d ch %d len %d\n", ++ (u32)TALITOS_SESSION(crp->crp_sid), ++ chsel, td->ptr[in_fifo].len); ++ break; ++ case CRYPTO_SHA1_HMAC: ++ td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC; ++ break; ++ default: ++ /* We cannot order the SEC as requested */ ++ DPRINTF("cannot do the order\n"); ++ err = EINVAL; ++ goto errout; ++ } ++ ++ if (crp->crp_flags & CRYPTO_F_IOV) ++ td->ptr[out_fifo].ptr += maccrd->crd_inject; ++ ++ if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) || ++ (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) { ++ td->ptr[hmac_key].ptr = dma_map_single(NULL, ++ ses->ses_hmac, ses->ses_hmac_len, ++ DMA_TO_DEVICE); ++ td->ptr[hmac_key].len = ses->ses_hmac_len; ++ } ++ } ++ else { ++ /* using process key (session data has duplicate) */ ++ td->ptr[cipher_key].ptr = dma_map_single(NULL, ++ enccrd->crd_key, (enccrd->crd_klen + 7) / 8, ++ DMA_TO_DEVICE); ++ td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8; ++ } ++ /* descriptor complete - GO! */ ++ return talitos_submit(sc, td, chsel); ++ ++errout: ++ if (err != ERESTART) { ++ crp->crp_etype = err; ++ crypto_done(crp); ++ } ++ return err; ++} ++ ++/* go through all channels descriptors, notifying OCF what has ++ * _and_hasn't_ successfully completed and reset the device ++ * (otherwise it's up to decoding desc hdrs!) ++ */ ++static void talitos_errorprocessing(struct talitos_softc *sc) ++{ ++ unsigned long flags; ++ int i, j; ++ ++ /* disable further scheduling until under control */ ++ spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ if (debug) dump_talitos_status(sc); ++ /* go through descriptors, try and salvage those successfully done, ++ * and EIO those that weren't ++ */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); ++ for (j = 0; j < sc->sc_chfifo_len; j++) { ++ if (sc->sc_chnfifo[i][j].cf_desc.hdr) { ++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr ++ & TALITOS_HDR_DONE_BITS) ++ != TALITOS_HDR_DONE_BITS) { ++ /* this one didn't finish */ ++ /* signify in crp->etype */ ++ sc->sc_chnfifo[i][j].cf_crp->crp_etype ++ = EIO; ++ } ++ } else ++ continue; /* free entry */ ++ /* either way, notify ocf */ ++ crypto_done(sc->sc_chnfifo[i][j].cf_crp); ++ /* and tag it available again ++ * ++ * memset to ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 MD/HMAC processing ++ */ ++ memset(&sc->sc_chnfifo[i][j].cf_desc, ++ 0, sizeof(struct talitos_desc)); ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); ++ } ++ /* reset and initialize the SEC h/w device */ ++ talitos_reset_device(sc); ++ talitos_init_device(sc); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) ++ talitos_rng_init(sc); ++#endif ++ ++ /* Okay. Stand by. */ ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags); ++ ++ return; ++} ++ ++/* go through all channels descriptors, notifying OCF what's been done */ ++static void talitos_doneprocessing(struct talitos_softc *sc) ++{ ++ unsigned long flags; ++ int i, j; ++ ++ /* go through descriptors looking for done bits */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ spin_lock_irqsave(&sc->sc_chnfifolock[i], flags); ++ for (j = 0; j < sc->sc_chfifo_len; j++) { ++ /* descriptor has done bits set? */ ++ if ((sc->sc_chnfifo[i][j].cf_desc.hdr ++ & TALITOS_HDR_DONE_BITS) ++ == TALITOS_HDR_DONE_BITS) { ++ /* notify ocf */ ++ crypto_done(sc->sc_chnfifo[i][j].cf_crp); ++ /* and tag it available again ++ * ++ * memset to ensure correct descriptor formation by ++ * avoiding inadvertently setting "optional" entries ++ * e.g. not using "optional" dptr2 MD/HMAC processing ++ */ ++ memset(&sc->sc_chnfifo[i][j].cf_desc, ++ 0, sizeof(struct talitos_desc)); ++ } ++ } ++ spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags); ++ } ++ return; ++} ++ ++static irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++talitos_intr(int irq, void *arg) ++#else ++talitos_intr(int irq, void *arg, struct pt_regs *regs) ++#endif ++{ ++ struct talitos_softc *sc = arg; ++ u_int32_t v, v_hi; ++ ++ /* ack */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_ISR); ++ v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI); ++ talitos_write(sc->sc_base_addr + TALITOS_ICR, v); ++ talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi); ++ ++ if (unlikely(v & TALITOS_ISR_ERROR)) { ++ /* Okay, Houston, we've had a problem here. */ ++ printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n", ++ device_get_nameunit(sc->sc_cdev), v, v_hi); ++ talitos_errorprocessing(sc); ++ } else ++ if (likely(v & TALITOS_ISR_DONE)) { ++ talitos_doneprocessing(sc); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Initialize registers we need to touch only once. ++ */ ++static void ++talitos_init_device(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* init all channels */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + ++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI); ++ v |= TALITOS_CH_CCCR_HI_CDWE ++ | TALITOS_CH_CCCR_HI_CDIE; /* invoke interrupt if done */ ++ talitos_write(sc->sc_base_addr + ++ i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v); ++ } ++ /* enable all interrupts */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR); ++ v |= TALITOS_IMR_ALL; ++ talitos_write(sc->sc_base_addr + TALITOS_IMR, v); ++ v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI); ++ v |= TALITOS_IMR_HI_ERRONLY; ++ talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v); ++ return; ++} ++ ++/* ++ * set the master reset bit on the device. ++ */ ++static void ++talitos_reset_device_master(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ ++ /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */ ++ v = talitos_read(sc->sc_base_addr + TALITOS_MCR); ++ talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR); ++ ++ while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR) ++ cpu_relax(); ++ ++ return; ++} ++ ++/* ++ * Resets the device. Values in the registers are left as is ++ * from the reset (i.e. initial values are assigned elsewhere). ++ */ ++static void ++talitos_reset_device(struct talitos_softc *sc) ++{ ++ u_int32_t v; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ /* ++ * Master reset ++ * errata documentation: warning: certain SEC interrupts ++ * are not fully cleared by writing the MCR:SWR bit, ++ * set bit twice to completely reset ++ */ ++ talitos_reset_device_master(sc); /* once */ ++ talitos_reset_device_master(sc); /* and once again */ ++ ++ /* reset all channels */ ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCCR); ++ talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET + ++ TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET); ++ } ++} ++ ++/* Set up the crypto device structure, private data, ++ * and anything else we need before we start */ ++#ifdef CONFIG_PPC_MERGE ++static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match) ++#else ++static int talitos_probe(struct platform_device *pdev) ++#endif ++{ ++ struct talitos_softc *sc = NULL; ++ struct resource *r; ++#ifdef CONFIG_PPC_MERGE ++ struct device *device = &ofdev->dev; ++ struct device_node *np = ofdev->node; ++ const unsigned int *prop; ++ int err; ++ struct resource res; ++#endif ++ static int num_chips = 0; ++ int rc; ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ ++ sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); ++ if (!sc) ++ return -ENOMEM; ++ memset(sc, 0, sizeof(*sc)); ++ ++ softc_device_init(sc, DRV_NAME, num_chips, talitos_methods); ++ ++ sc->sc_irq = -1; ++ sc->sc_cid = -1; ++#ifndef CONFIG_PPC_MERGE ++ sc->sc_dev = pdev; ++#endif ++ sc->sc_num = num_chips++; ++ ++#ifdef CONFIG_PPC_MERGE ++ dev_set_drvdata(device, sc); ++#else ++ platform_set_drvdata(sc->sc_dev, sc); ++#endif ++ ++ /* get the irq line */ ++#ifdef CONFIG_PPC_MERGE ++ err = of_address_to_resource(np, 0, &res); ++ if (err) ++ return -EINVAL; ++ r = &res; ++ ++ sc->sc_irq = irq_of_parse_and_map(np, 0); ++#else ++ /* get a pointer to the register memory */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ sc->sc_irq = platform_get_irq(pdev, 0); ++#endif ++ rc = request_irq(sc->sc_irq, talitos_intr, 0, ++ device_get_nameunit(sc->sc_cdev), sc); ++ if (rc) { ++ printk(KERN_ERR "%s: failed to hook irq %d\n", ++ device_get_nameunit(sc->sc_cdev), sc->sc_irq); ++ sc->sc_irq = -1; ++ goto out; ++ } ++ ++ sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start)); ++ if (!sc->sc_base_addr) { ++ printk(KERN_ERR "%s: failed to ioremap\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++ ++ /* figure out our SEC's properties and capabilities */ ++ sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32 ++ | talitos_read(sc->sc_base_addr + TALITOS_ID_HI); ++ DPRINTF("sec id 0x%llx\n", sc->sc_chiprev); ++ ++#ifdef CONFIG_PPC_MERGE ++ /* get SEC properties from device tree, defaulting to SEC 2.0 */ ++ ++ prop = of_get_property(np, "num-channels", NULL); ++ sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0; ++ ++ prop = of_get_property(np, "channel-fifo-len", NULL); ++ sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0; ++ ++ prop = of_get_property(np, "exec-units-mask", NULL); ++ sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0; ++ ++ prop = of_get_property(np, "descriptor-types-mask", NULL); ++ sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0; ++#else ++ /* bulk should go away with openfirmware flat device tree support */ ++ if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) { ++ sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0; ++ sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0; ++ sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0; ++ sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0; ++ } else { ++ printk(KERN_ERR "%s: failed to id device\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++#endif ++ ++ /* + 1 is for the meta-channel lock used by the channel scheduler */ ++ sc->sc_chnfifolock = (spinlock_t *) kmalloc( ++ (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL); ++ if (!sc->sc_chnfifolock) ++ goto out; ++ for (i = 0; i < sc->sc_num_channels + 1; i++) { ++ spin_lock_init(&sc->sc_chnfifolock[i]); ++ } ++ ++ sc->sc_chnlastalg = (int *) kmalloc( ++ sc->sc_num_channels * sizeof(int), GFP_KERNEL); ++ if (!sc->sc_chnlastalg) ++ goto out; ++ memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int)); ++ ++ sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc( ++ sc->sc_num_channels * sizeof(struct desc_cryptop_pair *), ++ GFP_KERNEL); ++ if (!sc->sc_chnfifo) ++ goto out; ++ for (i = 0; i < sc->sc_num_channels; i++) { ++ sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc( ++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair), ++ GFP_KERNEL); ++ if (!sc->sc_chnfifo[i]) ++ goto out; ++ memset(sc->sc_chnfifo[i], 0, ++ sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair)); ++ } ++ ++ /* reset and initialize the SEC h/w device */ ++ talitos_reset_device(sc); ++ talitos_init_device(sc); ++ ++ sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); ++ if (sc->sc_cid < 0) { ++ printk(KERN_ERR "%s: could not get crypto driver id\n", ++ device_get_nameunit(sc->sc_cdev)); ++ goto out; ++ } ++ ++ /* register algorithms with the framework */ ++ printk("%s:", device_get_nameunit(sc->sc_cdev)); ++ ++ if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) { ++ printk(" rng"); ++#ifdef CONFIG_OCF_RANDOMHARVEST ++ talitos_rng_init(sc); ++ crypto_rregister(sc->sc_cid, talitos_read_random, sc); ++#endif ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) { ++ printk(" des/3des"); ++ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); ++ crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) { ++ printk(" aes"); ++ crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); ++ } ++ if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) { ++ printk(" md5"); ++ crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); ++ /* HMAC support only with IPsec for now */ ++ crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); ++ printk(" sha1"); ++ crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); ++ /* HMAC support only with IPsec for now */ ++ crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); ++ } ++ printk("\n"); ++ return 0; ++ ++out: ++#ifndef CONFIG_PPC_MERGE ++ talitos_remove(pdev); ++#endif ++ return -ENOMEM; ++} ++ ++#ifdef CONFIG_PPC_MERGE ++static int talitos_remove(struct of_device *ofdev) ++#else ++static int talitos_remove(struct platform_device *pdev) ++#endif ++{ ++#ifdef CONFIG_PPC_MERGE ++ struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev); ++#else ++ struct talitos_softc *sc = platform_get_drvdata(pdev); ++#endif ++ int i; ++ ++ DPRINTF("%s()\n", __FUNCTION__); ++ if (sc->sc_cid >= 0) ++ crypto_unregister_all(sc->sc_cid); ++ if (sc->sc_chnfifo) { ++ for (i = 0; i < sc->sc_num_channels; i++) ++ if (sc->sc_chnfifo[i]) ++ kfree(sc->sc_chnfifo[i]); ++ kfree(sc->sc_chnfifo); ++ } ++ if (sc->sc_chnlastalg) ++ kfree(sc->sc_chnlastalg); ++ if (sc->sc_chnfifolock) ++ kfree(sc->sc_chnfifolock); ++ if (sc->sc_irq != -1) ++ free_irq(sc->sc_irq, sc); ++ if (sc->sc_base_addr) ++ iounmap((void *) sc->sc_base_addr); ++ kfree(sc); ++ return 0; ++} ++ ++#ifdef CONFIG_PPC_MERGE ++static struct of_device_id talitos_match[] = { ++ { ++ .type = "crypto", ++ .compatible = "talitos", ++ }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, talitos_match); ++ ++static struct of_platform_driver talitos_driver = { ++ .name = DRV_NAME, ++ .match_table = talitos_match, ++ .probe = talitos_probe, ++ .remove = talitos_remove, ++}; ++ ++static int __init talitos_init(void) ++{ ++ return of_register_platform_driver(&talitos_driver); ++} ++ ++static void __exit talitos_exit(void) ++{ ++ of_unregister_platform_driver(&talitos_driver); ++} ++#else ++/* Structure for a platform device driver */ ++static struct platform_driver talitos_driver = { ++ .probe = talitos_probe, ++ .remove = talitos_remove, ++ .driver = { ++ .name = "fsl-sec2", ++ } ++}; ++ ++static int __init talitos_init(void) ++{ ++ return platform_driver_register(&talitos_driver); ++} ++ ++static void __exit talitos_exit(void) ++{ ++ platform_driver_unregister(&talitos_driver); ++} ++#endif ++ ++module_init(talitos_init); ++module_exit(talitos_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("kim.phillips@freescale.com"); ++MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)"); +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos_dev.h linux-2.6.30/crypto/ocf/talitos/talitos_dev.h +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos_dev.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos_dev.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,277 @@ ++/* ++ * Freescale SEC (talitos) device dependent data structures ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++ ++/* device ID register values */ ++#define TALITOS_ID_SEC_2_0 0x40 ++#define TALITOS_ID_SEC_2_1 0x40 /* cross ref with IP block revision reg */ ++ ++/* ++ * following num_channels, channel-fifo-depth, exec-unit-mask, and ++ * descriptor-types-mask are for forward-compatibility with openfirmware ++ * flat device trees ++ */ ++ ++/* ++ * num_channels : the number of channels available in each SEC version. ++ */ ++ ++/* n.b. this driver requires these values be a power of 2 */ ++#define TALITOS_NCHANNELS_SEC_1_0 4 ++#define TALITOS_NCHANNELS_SEC_1_2 1 ++#define TALITOS_NCHANNELS_SEC_2_0 4 ++#define TALITOS_NCHANNELS_SEC_2_01 4 ++#define TALITOS_NCHANNELS_SEC_2_1 4 ++#define TALITOS_NCHANNELS_SEC_2_4 4 ++ ++/* ++ * channel-fifo-depth : The number of descriptor ++ * pointers a channel fetch fifo can hold. ++ */ ++#define TALITOS_CHFIFOLEN_SEC_1_0 1 ++#define TALITOS_CHFIFOLEN_SEC_1_2 1 ++#define TALITOS_CHFIFOLEN_SEC_2_0 24 ++#define TALITOS_CHFIFOLEN_SEC_2_01 24 ++#define TALITOS_CHFIFOLEN_SEC_2_1 24 ++#define TALITOS_CHFIFOLEN_SEC_2_4 24 ++ ++/* ++ * exec-unit-mask : The bitmask representing what Execution Units (EUs) ++ * are available. EU information should be encoded following the SEC's ++ * EU_SEL0 bitfield documentation, i.e. as follows: ++ * ++ * bit 31 = set if SEC permits no-EU selection (should be always set) ++ * bit 30 = set if SEC has the ARC4 EU (AFEU) ++ * bit 29 = set if SEC has the des/3des EU (DEU) ++ * bit 28 = set if SEC has the message digest EU (MDEU) ++ * bit 27 = set if SEC has the random number generator EU (RNG) ++ * bit 26 = set if SEC has the public key EU (PKEU) ++ * bit 25 = set if SEC has the aes EU (AESU) ++ * bit 24 = set if SEC has the Kasumi EU (KEU) ++ * ++ */ ++#define TALITOS_HAS_EU_NONE (1<<0) ++#define TALITOS_HAS_EU_AFEU (1<<1) ++#define TALITOS_HAS_EU_DEU (1<<2) ++#define TALITOS_HAS_EU_MDEU (1<<3) ++#define TALITOS_HAS_EU_RNG (1<<4) ++#define TALITOS_HAS_EU_PKEU (1<<5) ++#define TALITOS_HAS_EU_AESU (1<<6) ++#define TALITOS_HAS_EU_KEU (1<<7) ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_EUS_SEC_1_0 0x7f ++#define TALITOS_HAS_EUS_SEC_1_2 0x4d ++#define TALITOS_HAS_EUS_SEC_2_0 0x7f ++#define TALITOS_HAS_EUS_SEC_2_01 0x7f ++#define TALITOS_HAS_EUS_SEC_2_1 0xff ++#define TALITOS_HAS_EUS_SEC_2_4 0x7f ++ ++/* ++ * descriptor-types-mask : The bitmask representing what descriptors ++ * are available. Descriptor type information should be encoded ++ * following the SEC's Descriptor Header Dword DESC_TYPE field ++ * documentation, i.e. as follows: ++ * ++ * bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type ++ * bit 1 = set if SEC supports the ipsec_esp descriptor type ++ * bit 2 = set if SEC supports the common_nonsnoop desc. type ++ * bit 3 = set if SEC supports the 802.11i AES ccmp desc. type ++ * bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type ++ * bit 5 = set if SEC supports the srtp descriptor type ++ * bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type ++ * bit 7 = set if SEC supports the pkeu_assemble descriptor type ++ * bit 8 = set if SEC supports the aesu_key_expand_output desc.type ++ * bit 9 = set if SEC supports the pkeu_ptmul descriptor type ++ * bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type ++ * bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type ++ * ++ * ..and so on and so forth. ++ */ ++#define TALITOS_HAS_DT_AESU_CTR_NONSNOOP (1<<0) ++#define TALITOS_HAS_DT_IPSEC_ESP (1<<1) ++#define TALITOS_HAS_DT_COMMON_NONSNOOP (1<<2) ++ ++/* the corresponding masks for each SEC version */ ++#define TALITOS_HAS_DESCTYPES_SEC_2_0 0x01010ebf ++#define TALITOS_HAS_DESCTYPES_SEC_2_1 0x012b0ebf ++ ++/* ++ * a TALITOS_xxx_HI address points to the low data bits (32-63) of the register ++ */ ++ ++/* global register offset addresses */ ++#define TALITOS_ID 0x1020 ++#define TALITOS_ID_HI 0x1024 ++#define TALITOS_MCR 0x1030 /* master control register */ ++#define TALITOS_MCR_HI 0x1038 /* master control register */ ++#define TALITOS_MCR_SWR 0x1 ++#define TALITOS_IMR 0x1008 /* interrupt mask register */ ++#define TALITOS_IMR_ALL 0x00010fff /* enable all interrupts mask */ ++#define TALITOS_IMR_ERRONLY 0x00010aaa /* enable error interrupts */ ++#define TALITOS_IMR_HI 0x100C /* interrupt mask register */ ++#define TALITOS_IMR_HI_ALL 0x00323333 /* enable all interrupts mask */ ++#define TALITOS_IMR_HI_ERRONLY 0x00222222 /* enable error interrupts */ ++#define TALITOS_ISR 0x1010 /* interrupt status register */ ++#define TALITOS_ISR_ERROR 0x00010faa /* errors mask */ ++#define TALITOS_ISR_DONE 0x00000055 /* channel(s) done mask */ ++#define TALITOS_ISR_HI 0x1014 /* interrupt status register */ ++#define TALITOS_ICR 0x1018 /* interrupt clear register */ ++#define TALITOS_ICR_HI 0x101C /* interrupt clear register */ ++ ++/* channel register address stride */ ++#define TALITOS_CH_OFFSET 0x100 ++ ++/* channel register offset addresses and bits */ ++#define TALITOS_CH_CCCR 0x1108 /* Crypto-Channel Config Register */ ++#define TALITOS_CH_CCCR_RESET 0x1 /* Channel Reset bit */ ++#define TALITOS_CH_CCCR_HI 0x110c /* Crypto-Channel Config Register */ ++#define TALITOS_CH_CCCR_HI_CDWE 0x10 /* Channel done writeback enable bit */ ++#define TALITOS_CH_CCCR_HI_NT 0x4 /* Notification type bit */ ++#define TALITOS_CH_CCCR_HI_CDIE 0x2 /* Channel Done Interrupt Enable bit */ ++#define TALITOS_CH_CCPSR 0x1110 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_CCPSR_HI 0x1114 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_FF 0x1148 /* Fetch FIFO */ ++#define TALITOS_CH_FF_HI 0x114c /* Fetch FIFO's FETCH_ADRS */ ++#define TALITOS_CH_CDPR 0x1140 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_CDPR_HI 0x1144 /* Crypto-Channel Pointer Status Reg */ ++#define TALITOS_CH_DESCBUF 0x1180 /* (thru 11bf) Crypto-Channel ++ * Descriptor Buffer (debug) */ ++ ++/* execution unit register offset addresses and bits */ ++#define TALITOS_DEUSR 0x2028 /* DEU status register */ ++#define TALITOS_DEUSR_HI 0x202c /* DEU status register */ ++#define TALITOS_DEUISR 0x2030 /* DEU interrupt status register */ ++#define TALITOS_DEUISR_HI 0x2034 /* DEU interrupt status register */ ++#define TALITOS_DEUICR 0x2038 /* DEU interrupt control register */ ++#define TALITOS_DEUICR_HI 0x203c /* DEU interrupt control register */ ++#define TALITOS_AESUISR 0x4030 /* AESU interrupt status register */ ++#define TALITOS_AESUISR_HI 0x4034 /* AESU interrupt status register */ ++#define TALITOS_AESUICR 0x4038 /* AESU interrupt control register */ ++#define TALITOS_AESUICR_HI 0x403c /* AESU interrupt control register */ ++#define TALITOS_MDEUISR 0x6030 /* MDEU interrupt status register */ ++#define TALITOS_MDEUISR_HI 0x6034 /* MDEU interrupt status register */ ++#define TALITOS_RNGSR 0xa028 /* RNG status register */ ++#define TALITOS_RNGSR_HI 0xa02c /* RNG status register */ ++#define TALITOS_RNGSR_HI_RD 0x1 /* RNG Reset done */ ++#define TALITOS_RNGSR_HI_OFL 0xff0000/* number of dwords in RNG output FIFO*/ ++#define TALITOS_RNGDSR 0xa010 /* RNG data size register */ ++#define TALITOS_RNGDSR_HI 0xa014 /* RNG data size register */ ++#define TALITOS_RNG_FIFO 0xa800 /* RNG FIFO - pool of random numbers */ ++#define TALITOS_RNGISR 0xa030 /* RNG Interrupt status register */ ++#define TALITOS_RNGISR_HI 0xa034 /* RNG Interrupt status register */ ++#define TALITOS_RNGRCR 0xa018 /* RNG Reset control register */ ++#define TALITOS_RNGRCR_HI 0xa01c /* RNG Reset control register */ ++#define TALITOS_RNGRCR_HI_SR 0x1 /* RNG RNGRCR:Software Reset */ ++ ++/* descriptor pointer entry */ ++struct talitos_desc_ptr { ++ u16 len; /* length */ ++ u8 extent; /* jump (to s/g link table) and extent */ ++ u8 res; /* reserved */ ++ u32 ptr; /* pointer */ ++}; ++ ++/* descriptor */ ++struct talitos_desc { ++ u32 hdr; /* header */ ++ u32 res; /* reserved */ ++ struct talitos_desc_ptr ptr[7]; /* ptr/len pair array */ ++}; ++ ++/* talitos descriptor header (hdr) bits */ ++ ++/* primary execution unit select */ ++#define TALITOS_SEL0_AFEU 0x10000000 ++#define TALITOS_SEL0_DEU 0x20000000 ++#define TALITOS_SEL0_MDEU 0x30000000 ++#define TALITOS_SEL0_RNG 0x40000000 ++#define TALITOS_SEL0_PKEU 0x50000000 ++#define TALITOS_SEL0_AESU 0x60000000 ++ ++/* primary execution unit mode (MODE0) and derivatives */ ++#define TALITOS_MODE0_AESU_CBC 0x00200000 ++#define TALITOS_MODE0_AESU_ENC 0x00100000 ++#define TALITOS_MODE0_DEU_CBC 0x00400000 ++#define TALITOS_MODE0_DEU_3DES 0x00200000 ++#define TALITOS_MODE0_DEU_ENC 0x00100000 ++#define TALITOS_MODE0_MDEU_INIT 0x01000000 /* init starting regs */ ++#define TALITOS_MODE0_MDEU_HMAC 0x00800000 ++#define TALITOS_MODE0_MDEU_PAD 0x00400000 /* PD */ ++#define TALITOS_MODE0_MDEU_MD5 0x00200000 ++#define TALITOS_MODE0_MDEU_SHA256 0x00100000 ++#define TALITOS_MODE0_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define TALITOS_MODE0_MDEU_MD5_HMAC \ ++ (TALITOS_MODE0_MDEU_MD5 | TALITOS_MODE0_MDEU_HMAC) ++#define TALITOS_MODE0_MDEU_SHA256_HMAC \ ++ (TALITOS_MODE0_MDEU_SHA256 | TALITOS_MODE0_MDEU_HMAC) ++#define TALITOS_MODE0_MDEU_SHA1_HMAC \ ++ (TALITOS_MODE0_MDEU_SHA1 | TALITOS_MODE0_MDEU_HMAC) ++ ++/* secondary execution unit select (SEL1) */ ++/* it's MDEU or nothing */ ++#define TALITOS_SEL1_MDEU 0x00030000 ++ ++/* secondary execution unit mode (MODE1) and derivatives */ ++#define TALITOS_MODE1_MDEU_INIT 0x00001000 /* init starting regs */ ++#define TALITOS_MODE1_MDEU_HMAC 0x00000800 ++#define TALITOS_MODE1_MDEU_PAD 0x00000400 /* PD */ ++#define TALITOS_MODE1_MDEU_MD5 0x00000200 ++#define TALITOS_MODE1_MDEU_SHA256 0x00000100 ++#define TALITOS_MODE1_MDEU_SHA1 0x00000000 /* SHA-160 */ ++#define TALITOS_MODE1_MDEU_MD5_HMAC \ ++ (TALITOS_MODE1_MDEU_MD5 | TALITOS_MODE1_MDEU_HMAC) ++#define TALITOS_MODE1_MDEU_SHA256_HMAC \ ++ (TALITOS_MODE1_MDEU_SHA256 | TALITOS_MODE1_MDEU_HMAC) ++#define TALITOS_MODE1_MDEU_SHA1_HMAC \ ++ (TALITOS_MODE1_MDEU_SHA1 | TALITOS_MODE1_MDEU_HMAC) ++ ++/* direction of overall data flow (DIR) */ ++#define TALITOS_DIR_OUTBOUND 0x00000000 ++#define TALITOS_DIR_INBOUND 0x00000002 ++ ++/* done notification (DN) */ ++#define TALITOS_DONE_NOTIFY 0x00000001 ++ ++/* descriptor types */ ++/* odd numbers here are valid on SEC2 and greater only (e.g. ipsec_esp) */ ++#define TD_TYPE_AESU_CTR_NONSNOOP (0 << 3) ++#define TD_TYPE_IPSEC_ESP (1 << 3) ++#define TD_TYPE_COMMON_NONSNOOP_NO_AFEU (2 << 3) ++#define TD_TYPE_HMAC_SNOOP_NO_AFEU (4 << 3) ++ ++#define TALITOS_HDR_DONE_BITS 0xff000000 ++ ++#define DPRINTF(a...) do { \ ++ if (debug) { \ ++ printk("%s: ", sc ? \ ++ device_get_nameunit(sc->sc_cdev) : "talitos"); \ ++ printk(a); \ ++ } \ ++ } while (0) +diff -Nur linux-2.6.30.orig/crypto/ocf/talitos/talitos_soft.h linux-2.6.30/crypto/ocf/talitos/talitos_soft.h +--- linux-2.6.30.orig/crypto/ocf/talitos/talitos_soft.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/talitos/talitos_soft.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,77 @@ ++/* ++ * Freescale SEC data structures for integration with ocf-linux ++ * ++ * Copyright (c) 2006 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * paired descriptor and associated crypto operation ++ */ ++struct desc_cryptop_pair { ++ struct talitos_desc cf_desc; /* descriptor ptr */ ++ struct cryptop *cf_crp; /* cryptop ptr */ ++}; ++ ++/* ++ * Holds data specific to a single talitos device. ++ */ ++struct talitos_softc { ++ softc_device_decl sc_cdev; ++ struct platform_device *sc_dev; /* device backpointer */ ++ ocf_iomem_t sc_base_addr; ++ int sc_irq; ++ int sc_num; /* if we have multiple chips */ ++ int32_t sc_cid; /* crypto tag */ ++ u64 sc_chiprev; /* major/minor chip revision */ ++ int sc_nsessions; ++ struct talitos_session *sc_sessions; ++ int sc_num_channels;/* number of crypto channels */ ++ int sc_chfifo_len; /* channel fetch fifo len */ ++ int sc_exec_units; /* execution units mask */ ++ int sc_desc_types; /* descriptor types mask */ ++ /* ++ * mutual exclusion for intra-channel resources, e.g. fetch fifos ++ * the last entry is a meta-channel lock used by the channel scheduler ++ */ ++ spinlock_t *sc_chnfifolock; ++ /* sc_chnlastalgo contains last algorithm for that channel */ ++ int *sc_chnlastalg; ++ /* sc_chnfifo holds pending descriptor--crypto operation pairs */ ++ struct desc_cryptop_pair **sc_chnfifo; ++}; ++ ++struct talitos_session { ++ u_int32_t ses_used; ++ u_int32_t ses_klen; /* key length in bits */ ++ u_int32_t ses_key[8]; /* DES/3DES/AES key */ ++ u_int32_t ses_hmac[5]; /* hmac inner state */ ++ u_int32_t ses_hmac_len; /* hmac length */ ++ u_int32_t ses_iv[4]; /* DES/3DES/AES iv */ ++ u_int32_t ses_mlen; /* desired hash result len (12=ipsec or 16) */ ++}; ++ ++#define TALITOS_SESSION(sid) ((sid) & 0x0fffffff) ++#define TALITOS_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) +diff -Nur linux-2.6.30.orig/crypto/ocf/uio.h linux-2.6.30/crypto/ocf/uio.h +--- linux-2.6.30.orig/crypto/ocf/uio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/crypto/ocf/uio.h 2009-06-11 10:55:27.000000000 +0200 +@@ -0,0 +1,54 @@ ++#ifndef _OCF_UIO_H_ ++#define _OCF_UIO_H_ ++ ++#include ++ ++/* ++ * The linux uio.h doesn't have all we need. To be fully api compatible ++ * with the BSD cryptodev, we need to keep this around. Perhaps this can ++ * be moved back into the linux/uio.h ++ * ++ * Linux port done by David McCullough ++ * Copyright (C) 2006-2007 David McCullough ++ * Copyright (C) 2004-2005 Intel Corporation. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ * --------------------------------------------------------------------------- ++ */ ++ ++struct uio { ++ struct iovec *uio_iov; ++ int uio_iovcnt; ++ off_t uio_offset; ++ int uio_resid; ++#if 0 ++ enum uio_seg uio_segflg; ++ enum uio_rw uio_rw; ++ struct thread *uio_td; ++#endif ++}; ++ ++#endif +diff -Nur linux-2.6.30.orig/drivers/char/random.c linux-2.6.30/drivers/char/random.c +--- linux-2.6.30.orig/drivers/char/random.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/char/random.c 2009-06-11 10:55:27.000000000 +0200 +@@ -129,6 +129,9 @@ + * unsigned int value); + * void add_interrupt_randomness(int irq); + * ++ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++ * int random_input_wait(void); ++ * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * +@@ -140,6 +143,13 @@ + * a better measure, since the timing of the disk interrupts are more + * unpredictable. + * ++ * random_input_words() just provides a raw block of entropy to the input ++ * pool, such as from a hardware entropy generator. ++ * ++ * random_input_wait() suspends the caller until such time as the ++ * entropy pool falls below the write threshold, and returns a count of how ++ * much entropy (in bits) is needed to sustain the pool. ++ * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. +@@ -712,6 +722,61 @@ + } + #endif + ++/* ++ * random_input_words - add bulk entropy to pool ++ * ++ * @buf: buffer to add ++ * @wordcount: number of __u32 words to add ++ * @ent_count: total amount of entropy (in bits) to credit ++ * ++ * this provides bulk input of entropy to the input pool ++ * ++ */ ++void random_input_words(__u32 *buf, size_t wordcount, int ent_count) ++{ ++ mix_pool_bytes(&input_pool, buf, wordcount*4); ++ ++ credit_entropy_bits(&input_pool, ent_count); ++ ++ DEBUG_ENT("crediting %d bits => %d\n", ++ ent_count, input_pool.entropy_count); ++ /* ++ * Wake up waiting processes if we have enough ++ * entropy. ++ */ ++ if (input_pool.entropy_count >= random_read_wakeup_thresh) ++ wake_up_interruptible(&random_read_wait); ++} ++EXPORT_SYMBOL(random_input_words); ++ ++/* ++ * random_input_wait - wait until random needs entropy ++ * ++ * this function sleeps until the /dev/random subsystem actually ++ * needs more entropy, and then return the amount of entropy ++ * that it would be nice to have added to the system. ++ */ ++int random_input_wait(void) ++{ ++ int count; ++ ++ wait_event_interruptible(random_write_wait, ++ input_pool.entropy_count < random_write_wakeup_thresh); ++ ++ count = random_write_wakeup_thresh - input_pool.entropy_count; ++ ++ /* likely we got woken up due to a signal */ ++ if (count <= 0) count = random_read_wakeup_thresh; ++ ++ DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n", ++ count, ++ input_pool.entropy_count, random_write_wakeup_thresh); ++ ++ return count; ++} ++EXPORT_SYMBOL(random_input_wait); ++ ++ + #define EXTRACT_SIZE 10 + + /********************************************************************* +diff -Nur linux-2.6.30.orig/fs/fcntl.c linux-2.6.30/fs/fcntl.c +--- linux-2.6.30.orig/fs/fcntl.c 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/fcntl.c 2009-06-11 10:55:27.000000000 +0200 +@@ -142,6 +142,7 @@ + } + return ret; + } ++EXPORT_SYMBOL(sys_dup); + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +diff -Nur linux-2.6.30.orig/include/linux/miscdevice.h linux-2.6.30/include/linux/miscdevice.h +--- linux-2.6.30.orig/include/linux/miscdevice.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/include/linux/miscdevice.h 2009-06-11 10:55:27.000000000 +0200 +@@ -12,6 +12,7 @@ + #define APOLLO_MOUSE_MINOR 7 + #define PC110PAD_MINOR 9 + /*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ ++#define CRYPTODEV_MINOR 70 /* /dev/crypto */ + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 +diff -Nur linux-2.6.30.orig/include/linux/random.h linux-2.6.30/include/linux/random.h +--- linux-2.6.30.orig/include/linux/random.h 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/include/linux/random.h 2009-06-11 10:55:27.000000000 +0200 +@@ -34,6 +34,30 @@ + /* Clear the entropy pool and associated counters. (Superuser only.) */ + #define RNDCLEARPOOL _IO( 'R', 0x06 ) + ++#ifdef CONFIG_FIPS_RNG ++ ++/* Size of seed value - equal to AES blocksize */ ++#define AES_BLOCK_SIZE_BYTES 16 ++#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES ++/* Size of AES key */ ++#define KEY_SIZE_BYTES 16 ++ ++/* ioctl() structure used by FIPS 140-2 Tests */ ++struct rand_fips_test { ++ unsigned char key[KEY_SIZE_BYTES]; /* Input */ ++ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char seed[SEED_SIZE_BYTES]; /* Input */ ++ unsigned char result[SEED_SIZE_BYTES]; /* Output */ ++}; ++ ++/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */ ++#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test) ++ ++/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */ ++#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test) ++ ++#endif /* #ifdef CONFIG_FIPS_RNG */ ++ + struct rand_pool_info { + int entropy_count; + int buf_size; +@@ -50,6 +74,10 @@ + unsigned int value); + extern void add_interrupt_randomness(int irq); + ++extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count); ++extern int random_input_wait(void); ++#define HAS_RANDOM_INPUT_WAIT 1 ++ + extern void get_random_bytes(void *buf, int nbytes); + void generate_random_uuid(unsigned char uuid_out[16]); + diff --git a/target/linux/patches/2.6.30.4/swconfig.patch b/target/linux/patches/2.6.30.4/swconfig.patch new file mode 100644 index 000000000..3297bb116 --- /dev/null +++ b/target/linux/patches/2.6.30.4/swconfig.patch @@ -0,0 +1,1075 @@ +diff -Nur linux-2.6.30.orig/drivers/net/phy/Kconfig linux-2.6.30/drivers/net/phy/Kconfig +--- linux-2.6.30.orig/drivers/net/phy/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/net/phy/Kconfig 2009-06-11 09:22:50.000000000 +0200 +@@ -13,6 +13,12 @@ + + if PHYLIB + ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ + comment "MII PHY device drivers" + + config MARVELL_PHY +diff -Nur linux-2.6.30.orig/drivers/net/phy/Makefile linux-2.6.30/drivers/net/phy/Makefile +--- linux-2.6.30.orig/drivers/net/phy/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/drivers/net/phy/Makefile 2009-06-11 09:22:50.000000000 +0200 +@@ -3,6 +3,7 @@ + libphy-objs := phy.o phy_device.o mdio_bus.o + + obj-$(CONFIG_PHYLIB) += libphy.o ++obj-$(CONFIG_SWCONFIG) += swconfig.o + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o +diff -Nur linux-2.6.30.orig/drivers/net/phy/swconfig.c linux-2.6.30/drivers/net/phy/swconfig.c +--- linux-2.6.30.orig/drivers/net/phy/swconfig.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/drivers/net/phy/swconfig.c 2009-06-11 09:22:50.000000000 +0200 +@@ -0,0 +1,872 @@ ++/* ++ * swconfig.c: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++#ifdef DEBUG ++#define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__) ++#else ++#define DPRINTF(...) do {} while(0) ++#endif ++ ++MODULE_AUTHOR("Felix Fietkau "); ++MODULE_LICENSE("GPL"); ++ ++static int swdev_id = 0; ++static struct list_head swdevs; ++static spinlock_t swdevs_lock = SPIN_LOCK_UNLOCKED; ++struct swconfig_callback; ++ ++struct swconfig_callback ++{ ++ struct sk_buff *msg; ++ struct genlmsghdr *hdr; ++ struct genl_info *info; ++ int cmd; ++ ++ /* callback for filling in the message data */ ++ int (*fill)(struct swconfig_callback *cb, void *arg); ++ ++ /* callback for closing the message before sending it */ ++ int (*close)(struct swconfig_callback *cb, void *arg); ++ ++ struct nlattr *nest[4]; ++ int args[4]; ++}; ++ ++/* defaults */ ++ ++static int ++swconfig_get_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ int ret; ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ if (!dev->get_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ ret = dev->get_vlan_ports(dev, val); ++ printk("SET PORTS %d\n", val->len); ++ return ret; ++} ++ ++static int ++swconfig_set_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ int i; ++ ++ if (val->port_vlan >= dev->vlans) ++ return -EINVAL; ++ ++ /* validate ports */ ++ if (val->len > dev->ports) ++ return -EINVAL; ++ ++ for (i = 0; i < val->len; i++) { ++ if (val->value.ports[i].id >= dev->ports) ++ return -EINVAL; ++ } ++ ++ if (!dev->set_vlan_ports) ++ return -EOPNOTSUPP; ++ ++ printk("SET PORTS %d\n", val->len); ++ return dev->set_vlan_ports(dev, val); ++} ++ ++static int ++swconfig_apply_config(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) ++{ ++ /* don't complain if not supported by the switch driver */ ++ if (!dev->apply_config) ++ return 0; ++ ++ return dev->apply_config(dev); ++} ++ ++ ++enum global_defaults { ++ GLOBAL_APPLY, ++}; ++ ++enum vlan_defaults { ++ VLAN_PORTS, ++}; ++ ++enum port_defaults { ++ PORT_LINK, ++}; ++ ++static struct switch_attr default_global[] = { ++ [GLOBAL_APPLY] = { ++ .type = SWITCH_TYPE_NOVAL, ++ .name = "apply", ++ .description = "Activate changes in the hardware", ++ .set = swconfig_apply_config, ++ } ++}; ++ ++static struct switch_attr default_port[] = { ++ [PORT_LINK] = { ++ .type = SWITCH_TYPE_INT, ++ .name = "link", ++ .description = "Current link speed", ++ } ++}; ++ ++static struct switch_attr default_vlan[] = { ++ [VLAN_PORTS] = { ++ .type = SWITCH_TYPE_PORTS, ++ .name = "ports", ++ .description = "VLAN port mapping", ++ .set = swconfig_set_vlan_ports, ++ .get = swconfig_get_vlan_ports, ++ }, ++}; ++ ++ ++static void swconfig_defaults_init(struct switch_dev *dev) ++{ ++ dev->def_global = 0; ++ dev->def_vlan = 0; ++ dev->def_port = 0; ++ ++ if (dev->get_vlan_ports || dev->set_vlan_ports) ++ set_bit(VLAN_PORTS, &dev->def_vlan); ++ ++ /* always present, can be no-op */ ++ set_bit(GLOBAL_APPLY, &dev->def_global); ++} ++ ++ ++static struct genl_family switch_fam = { ++ .id = GENL_ID_GENERATE, ++ .name = "switch", ++ .hdrsize = 0, ++ .version = 1, ++ .maxattr = SWITCH_ATTR_MAX, ++}; ++ ++static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { ++ [SWITCH_ATTR_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, ++ [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, ++ [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, ++ [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, ++}; ++ ++static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { ++ [SWITCH_PORT_ID] = { .type = NLA_U32 }, ++ [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, ++}; ++ ++static inline void ++swconfig_lock(void) ++{ ++ spin_lock(&swdevs_lock); ++} ++ ++static inline void ++swconfig_unlock(void) ++{ ++ spin_unlock(&swdevs_lock); ++} ++ ++static struct switch_dev * ++swconfig_get_dev(struct genl_info *info) ++{ ++ struct switch_dev *dev = NULL; ++ struct switch_dev *p; ++ int id; ++ ++ if (!info->attrs[SWITCH_ATTR_ID]) ++ goto done; ++ ++ id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); ++ swconfig_lock(); ++ list_for_each_entry(p, &swdevs, dev_list) { ++ if (id != p->id) ++ continue; ++ ++ dev = p; ++ break; ++ } ++ if (dev) ++ spin_lock(&dev->lock); ++ else ++ DPRINTF("device %d not found\n", id); ++ swconfig_unlock(); ++done: ++ return dev; ++} ++ ++static inline void ++swconfig_put_dev(struct switch_dev *dev) ++{ ++ spin_unlock(&dev->lock); ++} ++ ++static int ++swconfig_dump_attr(struct swconfig_callback *cb, void *arg) ++{ ++ struct switch_attr *op = arg; ++ struct genl_info *info = cb->info; ++ struct sk_buff *msg = cb->msg; ++ int id = cb->args[0]; ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id); ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name); ++ if (op->description) ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION, ++ op->description); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++/* spread multipart messages across multiple message buffers */ ++static int ++swconfig_send_multipart(struct swconfig_callback *cb, void *arg) ++{ ++ struct genl_info *info = cb->info; ++ int restart = 0; ++ int err; ++ ++ do { ++ if (!cb->msg) { ++ cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (cb->msg == NULL) ++ goto error; ++ } ++ ++ if (!(cb->fill(cb, arg) < 0)) ++ break; ++ ++ /* fill failed, check if this was already the second attempt */ ++ if (restart) ++ goto error; ++ ++ /* try again in a new message, send the current one */ ++ restart = 1; ++ if (cb->close) { ++ if (cb->close(cb, arg) < 0) ++ goto error; ++ } ++ err = genlmsg_unicast(cb->msg, info->snd_pid); ++ cb->msg = NULL; ++ if (err < 0) ++ goto error; ++ ++ } while (restart); ++ ++ return 0; ++ ++error: ++ if (cb->msg) ++ nlmsg_free(cb->msg); ++ return -1; ++} ++ ++static int ++swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_dev *dev; ++ struct swconfig_callback cb; ++ int err = -EINVAL; ++ int i; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_LIST_GLOBAL: ++ alist = &dev->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_LIST_VLAN: ++ alist = &dev->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ break; ++ case SWITCH_CMD_LIST_PORT: ++ alist = &dev->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ break; ++ default: ++ WARN_ON(1); ++ goto out; ++ } ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.info = info; ++ cb.fill = swconfig_dump_attr; ++ for (i = 0; i < alist->n_attr; i++) { ++ if (alist->attr[i].disabled) ++ continue; ++ cb.args[0] = i; ++ err = swconfig_send_multipart(&cb, &alist->attr[i]); ++ if (err < 0) ++ goto error; ++ } ++ ++ /* defaults */ ++ for (i = 0; i < n_def; i++) { ++ if (!test_bit(i, def_active)) ++ continue; ++ cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; ++ err = swconfig_send_multipart(&cb, &def_list[i]); ++ if (err < 0) ++ goto error; ++ } ++ swconfig_put_dev(dev); ++ ++ if (!cb.msg) ++ return 0; ++ ++ return genlmsg_unicast(cb.msg, info->snd_pid); ++ ++error: ++ if (cb.msg) ++ nlmsg_free(cb.msg); ++out: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static struct switch_attr * ++swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, ++ struct switch_val *val) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ const struct switch_attrlist *alist; ++ struct switch_attr *attr = NULL; ++ int attr_id; ++ ++ /* defaults */ ++ struct switch_attr *def_list; ++ unsigned long *def_active; ++ int n_def; ++ ++ if (!info->attrs[SWITCH_ATTR_OP_ID]) ++ goto done; ++ ++ switch(hdr->cmd) { ++ case SWITCH_CMD_SET_GLOBAL: ++ case SWITCH_CMD_GET_GLOBAL: ++ alist = &dev->attr_global; ++ def_list = default_global; ++ def_active = &dev->def_global; ++ n_def = ARRAY_SIZE(default_global); ++ break; ++ case SWITCH_CMD_SET_VLAN: ++ case SWITCH_CMD_GET_VLAN: ++ alist = &dev->attr_vlan; ++ def_list = default_vlan; ++ def_active = &dev->def_vlan; ++ n_def = ARRAY_SIZE(default_vlan); ++ if (!info->attrs[SWITCH_ATTR_OP_VLAN]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); ++ break; ++ case SWITCH_CMD_SET_PORT: ++ case SWITCH_CMD_GET_PORT: ++ alist = &dev->attr_port; ++ def_list = default_port; ++ def_active = &dev->def_port; ++ n_def = ARRAY_SIZE(default_port); ++ if (!info->attrs[SWITCH_ATTR_OP_PORT]) ++ goto done; ++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); ++ break; ++ default: ++ WARN_ON(1); ++ goto done; ++ } ++ ++ if (!alist) ++ goto done; ++ ++ attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); ++ if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { ++ attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; ++ if (attr_id >= n_def) ++ goto done; ++ if (!test_bit(attr_id, def_active)) ++ goto done; ++ attr = &def_list[attr_id]; ++ } else { ++ if (attr_id >= alist->n_attr) ++ goto done; ++ attr = &alist->attr[attr_id]; ++ } ++ ++ if (attr->disabled) ++ attr = NULL; ++ ++done: ++ if (!attr) ++ DPRINTF("attribute lookup failed\n"); ++ val->attr = attr; ++ return attr; ++} ++ ++static int ++swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, ++ struct switch_val *val, int max) ++{ ++ struct nlattr *nla; ++ int rem; ++ ++ val->len = 0; ++ nla_for_each_nested(nla, head, rem) { ++ struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; ++ struct switch_port *port = &val->value.ports[val->len]; ++ ++ if (val->len >= max) ++ return -EINVAL; ++ ++ if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, ++ port_policy)) ++ return -EINVAL; ++ ++ if (!tb[SWITCH_PORT_ID]) ++ return -EINVAL; ++ ++ port->id = nla_get_u32(tb[SWITCH_PORT_ID]); ++ if (tb[SWITCH_PORT_FLAG_TAGGED]) ++ port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); ++ val->len++; ++ } ++ ++ return 0; ++} ++ ++static int ++swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct switch_val val; ++ int err = -EINVAL; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->set) ++ goto error; ++ ++ val.attr = attr; ++ switch(attr->type) { ++ case SWITCH_TYPE_NOVAL: ++ break; ++ case SWITCH_TYPE_INT: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) ++ goto error; ++ val.value.i = ++ nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); ++ break; ++ case SWITCH_TYPE_STRING: ++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) ++ goto error; ++ val.value.s = ++ nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); ++ break; ++ case SWITCH_TYPE_PORTS: ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ ++ /* TODO: implement multipart? */ ++ if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { ++ err = swconfig_parse_ports(skb, ++ info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports); ++ if (err < 0) ++ goto error; ++ } else { ++ val.len = 0; ++ err = 0; ++ } ++ break; ++ default: ++ goto error; ++ } ++ ++ err = attr->set(dev, attr, &val); ++error: ++ swconfig_put_dev(dev); ++ return err; ++} ++ ++static int ++swconfig_close_portlist(struct swconfig_callback *cb, void *arg) ++{ ++ if (cb->nest[0]) ++ nla_nest_end(cb->msg, cb->nest[0]); ++ return 0; ++} ++ ++static int ++swconfig_send_port(struct swconfig_callback *cb, void *arg) ++{ ++ const struct switch_port *port = arg; ++ struct nlattr *p = NULL; ++ ++ if (!cb->nest[0]) { ++ cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); ++ if (!cb->nest[0]) ++ return -1; ++ } ++ ++ p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); ++ if (!p) ++ goto error; ++ ++ NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id); ++ if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ++ NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED); ++ ++ nla_nest_end(cb->msg, p); ++ return 0; ++ ++nla_put_failure: ++ nla_nest_cancel(cb->msg, p); ++error: ++ nla_nest_cancel(cb->msg, cb->nest[0]); ++ return -1; ++} ++ ++static int ++swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, ++ const struct switch_val *val) ++{ ++ struct swconfig_callback cb; ++ int err = 0; ++ int i; ++ ++ if (!val->value.ports) ++ return -EINVAL; ++ ++ memset(&cb, 0, sizeof(cb)); ++ cb.cmd = attr; ++ cb.msg = *msg; ++ cb.info = info; ++ cb.fill = swconfig_send_port; ++ cb.close = swconfig_close_portlist; ++ ++ cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); ++ for (i = 0; i < val->len; i++) { ++ err = swconfig_send_multipart(&cb, &val->value.ports[i]); ++ if (err) ++ goto done; ++ } ++ err = val->len; ++ swconfig_close_portlist(&cb, NULL); ++ *msg = cb.msg; ++ ++done: ++ return err; ++} ++ ++static int ++swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); ++ struct switch_attr *attr; ++ struct switch_dev *dev; ++ struct sk_buff *msg = NULL; ++ struct switch_val val; ++ int err = -EINVAL; ++ int cmd = hdr->cmd; ++ ++ dev = swconfig_get_dev(info); ++ if (!dev) ++ return -EINVAL; ++ ++ memset(&val, 0, sizeof(val)); ++ attr = swconfig_lookup_attr(dev, info, &val); ++ if (!attr || !attr->get) ++ goto error_dev; ++ ++ if (attr->type == SWITCH_TYPE_PORTS) { ++ val.value.ports = dev->portbuf; ++ memset(dev->portbuf, 0, ++ sizeof(struct switch_port) * dev->ports); ++ } ++ ++ err = attr->get(dev, attr, &val); ++ if (err) ++ goto error; ++ ++ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (!msg) ++ goto error; ++ ++ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, ++ 0, cmd); ++ if (IS_ERR(hdr)) ++ goto nla_put_failure; ++ ++ switch(attr->type) { ++ case SWITCH_TYPE_INT: ++ NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i); ++ break; ++ case SWITCH_TYPE_STRING: ++ NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s); ++ break; ++ case SWITCH_TYPE_PORTS: ++ err = swconfig_send_ports(&msg, info, ++ SWITCH_ATTR_OP_VALUE_PORTS, &val); ++ if (err < 0) ++ goto nla_put_failure; ++ break; ++ default: ++ DPRINTF("invalid type in attribute\n"); ++ err = -EINVAL; ++ goto error; ++ } ++ err = genlmsg_end(msg, hdr); ++ if (err < 0) ++ goto nla_put_failure; ++ ++ swconfig_put_dev(dev); ++ return genlmsg_unicast(msg, info->snd_pid); ++ ++nla_put_failure: ++ if (msg) ++ nlmsg_free(msg); ++error_dev: ++ swconfig_put_dev(dev); ++error: ++ if (!err) ++ err = -ENOMEM; ++ return err; ++} ++ ++static int ++swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, ++ const struct switch_dev *dev) ++{ ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, ++ SWITCH_CMD_NEW_ATTR); ++ if (IS_ERR(hdr)) ++ return -1; ++ ++ NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name); ++ NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname); ++ NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans); ++ NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports); ++ ++ return genlmsg_end(msg, hdr); ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static int swconfig_dump_switches(struct sk_buff *skb, ++ struct netlink_callback *cb) ++{ ++ struct switch_dev *dev; ++ int start = cb->args[0]; ++ int idx = 0; ++ ++ swconfig_lock(); ++ list_for_each_entry(dev, &swdevs, dev_list) { ++ if (++idx <= start) ++ continue; ++ if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid, ++ cb->nlh->nlmsg_seq, NLM_F_MULTI, ++ dev) < 0) ++ break; ++ } ++ swconfig_unlock(); ++ cb->args[0] = idx; ++ ++ return skb->len; ++} ++ ++static int ++swconfig_done(struct netlink_callback *cb) ++{ ++ return 0; ++} ++ ++static struct genl_ops swconfig_ops[] = { ++ { ++ .cmd = SWITCH_CMD_LIST_GLOBAL, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_VLAN, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_LIST_PORT, ++ .doit = swconfig_list_attrs, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_GLOBAL, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_VLAN, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_PORT, ++ .doit = swconfig_get_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_GLOBAL, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_VLAN, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_SET_PORT, ++ .doit = swconfig_set_attr, ++ .policy = switch_policy, ++ }, ++ { ++ .cmd = SWITCH_CMD_GET_SWITCH, ++ .dumpit = swconfig_dump_switches, ++ .policy = switch_policy, ++ .done = swconfig_done, ++ } ++}; ++ ++int ++register_switch(struct switch_dev *dev, struct net_device *netdev) ++{ ++ INIT_LIST_HEAD(&dev->dev_list); ++ if (netdev) { ++ dev->netdev = netdev; ++ if (!dev->devname) ++ dev->devname = netdev->name; ++ } ++ BUG_ON(!dev->devname); ++ ++ if (dev->ports > 0) { ++ dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports, ++ GFP_KERNEL); ++ if (!dev->portbuf) ++ return -ENOMEM; ++ } ++ dev->id = ++swdev_id; ++ swconfig_defaults_init(dev); ++ spin_lock_init(&dev->lock); ++ swconfig_lock(); ++ list_add(&dev->dev_list, &swdevs); ++ swconfig_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(register_switch); ++ ++void ++unregister_switch(struct switch_dev *dev) ++{ ++ kfree(dev->portbuf); ++ spin_lock(&dev->lock); ++ swconfig_lock(); ++ list_del(&dev->dev_list); ++ swconfig_unlock(); ++} ++EXPORT_SYMBOL_GPL(unregister_switch); ++ ++ ++static int __init ++swconfig_init(void) ++{ ++ int i, err; ++ ++ INIT_LIST_HEAD(&swdevs); ++ err = genl_register_family(&switch_fam); ++ if (err) ++ return err; ++ ++ for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) { ++ err = genl_register_ops(&switch_fam, &swconfig_ops[i]); ++ if (err) ++ goto unregister; ++ } ++ ++ return 0; ++ ++unregister: ++ genl_unregister_family(&switch_fam); ++ return err; ++} ++ ++static void __exit ++swconfig_exit(void) ++{ ++ genl_unregister_family(&switch_fam); ++} ++ ++module_init(swconfig_init); ++module_exit(swconfig_exit); ++ +diff -Nur linux-2.6.30.orig/include/linux/switch.h linux-2.6.30/include/linux/switch.h +--- linux-2.6.30.orig/include/linux/switch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/include/linux/switch.h 2009-06-11 09:22:50.000000000 +0200 +@@ -0,0 +1,168 @@ ++/* ++ * switch.h: Switch configuration API ++ * ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * 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. ++ */ ++ ++#ifndef __LINUX_SWITCH_H ++#define __LINUX_SWITCH_H ++ ++#include ++#include ++#include ++#include ++#ifndef __KERNEL__ ++#include ++#include ++#include ++#else ++#include ++#endif ++ ++/* main attributes */ ++enum { ++ SWITCH_ATTR_UNSPEC, ++ /* global */ ++ SWITCH_ATTR_TYPE, ++ /* device */ ++ SWITCH_ATTR_ID, ++ SWITCH_ATTR_NAME, ++ SWITCH_ATTR_DEV_NAME, ++ SWITCH_ATTR_VLANS, ++ SWITCH_ATTR_PORTS, ++ /* attributes */ ++ SWITCH_ATTR_OP_ID, ++ SWITCH_ATTR_OP_TYPE, ++ SWITCH_ATTR_OP_NAME, ++ SWITCH_ATTR_OP_PORT, ++ SWITCH_ATTR_OP_VLAN, ++ SWITCH_ATTR_OP_VALUE_INT, ++ SWITCH_ATTR_OP_VALUE_STR, ++ SWITCH_ATTR_OP_VALUE_PORTS, ++ SWITCH_ATTR_OP_DESCRIPTION, ++ /* port lists */ ++ SWITCH_ATTR_PORT, ++ SWITCH_ATTR_MAX ++}; ++ ++/* commands */ ++enum { ++ SWITCH_CMD_UNSPEC, ++ SWITCH_CMD_GET_SWITCH, ++ SWITCH_CMD_NEW_ATTR, ++ SWITCH_CMD_LIST_GLOBAL, ++ SWITCH_CMD_GET_GLOBAL, ++ SWITCH_CMD_SET_GLOBAL, ++ SWITCH_CMD_LIST_PORT, ++ SWITCH_CMD_GET_PORT, ++ SWITCH_CMD_SET_PORT, ++ SWITCH_CMD_LIST_VLAN, ++ SWITCH_CMD_GET_VLAN, ++ SWITCH_CMD_SET_VLAN ++}; ++ ++/* data types */ ++enum switch_val_type { ++ SWITCH_TYPE_UNSPEC, ++ SWITCH_TYPE_INT, ++ SWITCH_TYPE_STRING, ++ SWITCH_TYPE_PORTS, ++ SWITCH_TYPE_NOVAL, ++}; ++ ++/* port nested attributes */ ++enum { ++ SWITCH_PORT_UNSPEC, ++ SWITCH_PORT_ID, ++ SWITCH_PORT_FLAG_TAGGED, ++ SWITCH_PORT_ATTR_MAX ++}; ++ ++#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 ++ ++#ifdef __KERNEL__ ++ ++struct switch_dev; ++struct switch_op; ++struct switch_val; ++struct switch_attr; ++struct switch_attrlist; ++ ++int register_switch(struct switch_dev *dev, struct net_device *netdev); ++void unregister_switch(struct switch_dev *dev); ++ ++struct switch_attrlist { ++ /* filled in by the driver */ ++ int n_attr; ++ struct switch_attr *attr; ++}; ++ ++ ++struct switch_dev { ++ int id; ++ void *priv; ++ const char *name; ++ ++ /* NB: either devname or netdev must be set */ ++ const char *devname; ++ struct net_device *netdev; ++ ++ int ports; ++ int vlans; ++ int cpu_port; ++ struct switch_attrlist attr_global, attr_port, attr_vlan; ++ ++ spinlock_t lock; ++ struct switch_port *portbuf; ++ struct list_head dev_list; ++ unsigned long def_global, def_port, def_vlan; ++ ++ int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); ++ int (*apply_config)(struct switch_dev *dev); ++}; ++ ++struct switch_port { ++ u32 id; ++ u32 flags; ++}; ++ ++struct switch_val { ++ struct switch_attr *attr; ++ int port_vlan; ++ int len; ++ union { ++ const char *s; ++ u32 i; ++ struct switch_port *ports; ++ } value; ++}; ++ ++struct switch_attr { ++ int disabled; ++ int type; ++ const char *name; ++ const char *description; ++ ++ int (*set)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); ++ int (*get)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val); ++ ++ /* for driver internal use */ ++ int id; ++ int ofs; ++ int max; ++}; ++ ++#endif ++ ++#endif diff --git a/target/linux/patches/2.6.30.4/yaffs2.patch b/target/linux/patches/2.6.30.4/yaffs2.patch new file mode 100644 index 000000000..a19ab9c84 --- /dev/null +++ b/target/linux/patches/2.6.30.4/yaffs2.patch @@ -0,0 +1,15066 @@ +diff -Nur linux-2.6.30.orig/fs/Kconfig linux-2.6.30/fs/Kconfig +--- linux-2.6.30.orig/fs/Kconfig 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/Kconfig 2009-06-11 09:21:04.000000000 +0200 +@@ -162,6 +162,10 @@ + source "fs/befs/Kconfig" + source "fs/bfs/Kconfig" + source "fs/efs/Kconfig" ++ ++# Patched by YAFFS ++source "fs/yaffs2/Kconfig" ++ + source "fs/jffs2/Kconfig" + # UBIFS File system configuration + source "fs/ubifs/Kconfig" +diff -Nur linux-2.6.30.orig/fs/Makefile linux-2.6.30/fs/Makefile +--- linux-2.6.30.orig/fs/Makefile 2009-06-10 05:05:27.000000000 +0200 ++++ linux-2.6.30/fs/Makefile 2009-06-11 09:21:31.000000000 +0200 +@@ -124,3 +124,4 @@ + obj-$(CONFIG_BTRFS_FS) += btrfs/ + obj-$(CONFIG_GFS2_FS) += gfs2/ + obj-$(CONFIG_EXOFS_FS) += exofs/ ++obj-$(CONFIG_YAFFS_FS) += yaffs2/ +diff -Nur linux-2.6.30.orig/fs/Makefile.pre.yaffs linux-2.6.30/fs/Makefile.pre.yaffs +--- linux-2.6.30.orig/fs/Makefile.pre.yaffs 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/Makefile.pre.yaffs 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,126 @@ ++# ++# Makefile for the Linux filesystems. ++# ++# 14 Sep 2000, Christoph Hellwig ++# Rewritten to use lists instead of if-statements. ++# ++ ++obj-y := open.o read_write.o file_table.o super.o \ ++ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ++ ioctl.o readdir.o select.o fifo.o dcache.o inode.o \ ++ attr.o bad_inode.o file.o filesystems.o namespace.o \ ++ seq_file.o xattr.o libfs.o fs-writeback.o \ ++ pnode.o drop_caches.o splice.o sync.o utimes.o \ ++ stack.o ++ ++ifeq ($(CONFIG_BLOCK),y) ++obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o ++else ++obj-y += no-block.o ++endif ++ ++obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o ++obj-y += notify/ ++obj-$(CONFIG_EPOLL) += eventpoll.o ++obj-$(CONFIG_ANON_INODES) += anon_inodes.o ++obj-$(CONFIG_SIGNALFD) += signalfd.o ++obj-$(CONFIG_TIMERFD) += timerfd.o ++obj-$(CONFIG_EVENTFD) += eventfd.o ++obj-$(CONFIG_AIO) += aio.o ++obj-$(CONFIG_FILE_LOCKING) += locks.o ++obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o ++ ++nfsd-$(CONFIG_NFSD) := nfsctl.o ++obj-y += $(nfsd-y) $(nfsd-m) ++ ++obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o ++obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o ++obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o ++ ++# binfmt_script is always there ++obj-y += binfmt_script.o ++ ++obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o ++obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o ++obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o ++obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o ++obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o ++ ++obj-$(CONFIG_FS_MBCACHE) += mbcache.o ++obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o ++obj-$(CONFIG_NFS_COMMON) += nfs_common/ ++obj-$(CONFIG_GENERIC_ACL) += generic_acl.o ++ ++obj-$(CONFIG_QUOTA) += dquot.o ++obj-$(CONFIG_QFMT_V1) += quota_v1.o ++obj-$(CONFIG_QFMT_V2) += quota_v2.o ++obj-$(CONFIG_QUOTA_TREE) += quota_tree.o ++obj-$(CONFIG_QUOTACTL) += quota.o ++ ++obj-$(CONFIG_PROC_FS) += proc/ ++obj-y += partitions/ ++obj-$(CONFIG_SYSFS) += sysfs/ ++obj-$(CONFIG_CONFIGFS_FS) += configfs/ ++obj-y += devpts/ ++ ++obj-$(CONFIG_PROFILING) += dcookies.o ++obj-$(CONFIG_DLM) += dlm/ ++ ++# Do not add any filesystems before this line ++obj-$(CONFIG_REISERFS_FS) += reiserfs/ ++obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 ++obj-$(CONFIG_EXT2_FS) += ext2/ ++# We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2 ++# unless explicitly requested by rootfstype ++obj-$(CONFIG_EXT4_FS) += ext4/ ++obj-$(CONFIG_JBD) += jbd/ ++obj-$(CONFIG_JBD2) += jbd2/ ++obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ ++obj-y += ramfs/ ++obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ ++obj-$(CONFIG_CODA_FS) += coda/ ++obj-$(CONFIG_MINIX_FS) += minix/ ++obj-$(CONFIG_FAT_FS) += fat/ ++obj-$(CONFIG_BFS_FS) += bfs/ ++obj-$(CONFIG_ISO9660_FS) += isofs/ ++obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ ++obj-$(CONFIG_HFS_FS) += hfs/ ++obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ ++obj-$(CONFIG_VXFS_FS) += freevxfs/ ++obj-$(CONFIG_NFS_FS) += nfs/ ++obj-$(CONFIG_EXPORTFS) += exportfs/ ++obj-$(CONFIG_NFSD) += nfsd/ ++obj-$(CONFIG_LOCKD) += lockd/ ++obj-$(CONFIG_NLS) += nls/ ++obj-$(CONFIG_SYSV_FS) += sysv/ ++obj-$(CONFIG_SMB_FS) += smbfs/ ++obj-$(CONFIG_CIFS) += cifs/ ++obj-$(CONFIG_NCP_FS) += ncpfs/ ++obj-$(CONFIG_HPFS_FS) += hpfs/ ++obj-$(CONFIG_NTFS_FS) += ntfs/ ++obj-$(CONFIG_UFS_FS) += ufs/ ++obj-$(CONFIG_EFS_FS) += efs/ ++obj-$(CONFIG_JFFS2_FS) += jffs2/ ++obj-$(CONFIG_UBIFS_FS) += ubifs/ ++obj-$(CONFIG_AFFS_FS) += affs/ ++obj-$(CONFIG_ROMFS_FS) += romfs/ ++obj-$(CONFIG_QNX4FS_FS) += qnx4/ ++obj-$(CONFIG_AUTOFS_FS) += autofs/ ++obj-$(CONFIG_AUTOFS4_FS) += autofs4/ ++obj-$(CONFIG_ADFS_FS) += adfs/ ++obj-$(CONFIG_FUSE_FS) += fuse/ ++obj-$(CONFIG_UDF_FS) += udf/ ++obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ ++obj-$(CONFIG_OMFS_FS) += omfs/ ++obj-$(CONFIG_JFS_FS) += jfs/ ++obj-$(CONFIG_XFS_FS) += xfs/ ++obj-$(CONFIG_9P_FS) += 9p/ ++obj-$(CONFIG_AFS_FS) += afs/ ++obj-$(CONFIG_BEFS_FS) += befs/ ++obj-$(CONFIG_HOSTFS) += hostfs/ ++obj-$(CONFIG_HPPFS) += hppfs/ ++obj-$(CONFIG_DEBUG_FS) += debugfs/ ++obj-$(CONFIG_OCFS2_FS) += ocfs2/ ++obj-$(CONFIG_BTRFS_FS) += btrfs/ ++obj-$(CONFIG_GFS2_FS) += gfs2/ +diff -Nur linux-2.6.30.orig/fs/yaffs2/devextras.h linux-2.6.30/fs/yaffs2/devextras.h +--- linux-2.6.30.orig/fs/yaffs2/devextras.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/devextras.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,196 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This file is just holds extra declarations of macros that would normally ++ * be providesd in the Linux kernel. These macros have been written from ++ * scratch but are functionally equivalent to the Linux ones. ++ * ++ */ ++ ++#ifndef __EXTRAS_H__ ++#define __EXTRAS_H__ ++ ++ ++#if !(defined __KERNEL__) ++ ++/* Definition of types */ ++typedef unsigned char __u8; ++typedef unsigned short __u16; ++typedef unsigned __u32; ++ ++#endif ++ ++/* ++ * This is a simple doubly linked list implementation that matches the ++ * way the Linux kernel doubly linked list implementation works. ++ */ ++ ++struct ylist_head { ++ struct ylist_head *next; /* next in chain */ ++ struct ylist_head *prev; /* previous in chain */ ++}; ++ ++ ++/* Initialise a static list */ ++#define YLIST_HEAD(name) \ ++struct ylist_head name = { &(name), &(name)} ++ ++ ++ ++/* Initialise a list head to an empty list */ ++#define YINIT_LIST_HEAD(p) \ ++do { \ ++ (p)->next = (p);\ ++ (p)->prev = (p); \ ++} while (0) ++ ++ ++/* Add an element to a list */ ++static __inline__ void ylist_add(struct ylist_head *newEntry, ++ struct ylist_head *list) ++{ ++ struct ylist_head *listNext = list->next; ++ ++ list->next = newEntry; ++ newEntry->prev = list; ++ newEntry->next = listNext; ++ listNext->prev = newEntry; ++ ++} ++ ++static __inline__ void ylist_add_tail(struct ylist_head *newEntry, ++ struct ylist_head *list) ++{ ++ struct ylist_head *listPrev = list->prev; ++ ++ list->prev = newEntry; ++ newEntry->next = list; ++ newEntry->prev = listPrev; ++ listPrev->next = newEntry; ++ ++} ++ ++ ++/* Take an element out of its current list, with or without ++ * reinitialising the links.of the entry*/ ++static __inline__ void ylist_del(struct ylist_head *entry) ++{ ++ struct ylist_head *listNext = entry->next; ++ struct ylist_head *listPrev = entry->prev; ++ ++ listNext->prev = listPrev; ++ listPrev->next = listNext; ++ ++} ++ ++static __inline__ void ylist_del_init(struct ylist_head *entry) ++{ ++ ylist_del(entry); ++ entry->next = entry->prev = entry; ++} ++ ++ ++/* Test if the list is empty */ ++static __inline__ int ylist_empty(struct ylist_head *entry) ++{ ++ return (entry->next == entry); ++} ++ ++ ++/* ylist_entry takes a pointer to a list entry and offsets it to that ++ * we can find a pointer to the object it is embedded in. ++ */ ++ ++ ++#define ylist_entry(entry, type, member) \ ++ ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) ++ ++ ++/* ylist_for_each and list_for_each_safe iterate over lists. ++ * ylist_for_each_safe uses temporary storage to make the list delete safe ++ */ ++ ++#define ylist_for_each(itervar, list) \ ++ for (itervar = (list)->next; itervar != (list); itervar = itervar->next) ++ ++#define ylist_for_each_safe(itervar, saveVar, list) \ ++ for (itervar = (list)->next, saveVar = (list)->next->next; \ ++ itervar != (list); itervar = saveVar, saveVar = saveVar->next) ++ ++ ++#if !(defined __KERNEL__) ++ ++ ++#ifndef WIN32 ++#include ++#endif ++ ++ ++#ifdef CONFIG_YAFFS_PROVIDE_DEFS ++/* File types */ ++ ++ ++#define DT_UNKNOWN 0 ++#define DT_FIFO 1 ++#define DT_CHR 2 ++#define DT_DIR 4 ++#define DT_BLK 6 ++#define DT_REG 8 ++#define DT_LNK 10 ++#define DT_SOCK 12 ++#define DT_WHT 14 ++ ++ ++#ifndef WIN32 ++#include ++#endif ++ ++/* ++ * Attribute flags. These should be or-ed together to figure out what ++ * has been changed! ++ */ ++#define ATTR_MODE 1 ++#define ATTR_UID 2 ++#define ATTR_GID 4 ++#define ATTR_SIZE 8 ++#define ATTR_ATIME 16 ++#define ATTR_MTIME 32 ++#define ATTR_CTIME 64 ++ ++struct iattr { ++ unsigned int ia_valid; ++ unsigned ia_mode; ++ unsigned ia_uid; ++ unsigned ia_gid; ++ unsigned ia_size; ++ unsigned ia_atime; ++ unsigned ia_mtime; ++ unsigned ia_ctime; ++ unsigned int ia_attr_flags; ++}; ++ ++#endif ++ ++#else ++ ++#include ++#include ++#include ++ ++#endif ++ ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/Kconfig linux-2.6.30/fs/yaffs2/Kconfig +--- linux-2.6.30.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/Kconfig 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,156 @@ ++# ++# YAFFS file system configurations ++# ++ ++config YAFFS_FS ++ tristate "YAFFS2 file system support" ++ default n ++ depends on MTD_BLOCK ++ select YAFFS_YAFFS1 ++ select YAFFS_YAFFS2 ++ help ++ YAFFS2, or Yet Another Flash Filing System, is a filing system ++ optimised for NAND Flash chips. ++ ++ To compile the YAFFS2 file system support as a module, choose M ++ here: the module will be called yaffs2. ++ ++ If unsure, say N. ++ ++ Further information on YAFFS2 is available at ++ . ++ ++config YAFFS_YAFFS1 ++ bool "512 byte / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable YAFFS1 support -- yaffs for 512 byte / page devices ++ ++ Not needed for 2K-page devices. ++ ++ If unsure, say Y. ++ ++config YAFFS_9BYTE_TAGS ++ bool "Use older-style on-NAND data format with pageStatus byte" ++ depends on YAFFS_YAFFS1 ++ default n ++ help ++ ++ Older-style on-NAND data format has a "pageStatus" byte to record ++ chunk/page state. This byte is zero when the page is discarded. ++ Choose this option if you have existing on-NAND data using this ++ format that you need to continue to support. New data written ++ also uses the older-style format. Note: Use of this option ++ generally requires that MTD's oob layout be adjusted to use the ++ older-style format. See notes on tags formats and MTD versions ++ in yaffs_mtdif1.c. ++ ++ If unsure, say N. ++ ++config YAFFS_DOES_ECC ++ bool "Lets Yaffs do its own ECC" ++ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This enables Yaffs to use its own ECC functions instead of using ++ the ones from the generic MTD-NAND driver. ++ ++ If unsure, say N. ++ ++config YAFFS_ECC_WRONG_ORDER ++ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" ++ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS ++ default n ++ help ++ This makes yaffs_ecc.c use the same ecc byte order as Steven ++ Hill's nand_ecc.c. If not set, then you get the same ecc byte ++ order as SmartMedia. ++ ++ If unsure, say N. ++ ++config YAFFS_YAFFS2 ++ bool "2048 byte (or larger) / page devices" ++ depends on YAFFS_FS ++ default y ++ help ++ Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices ++ ++ If unsure, say Y. ++ ++config YAFFS_AUTO_YAFFS2 ++ bool "Autoselect yaffs2 format" ++ depends on YAFFS_YAFFS2 ++ default y ++ help ++ Without this, you need to explicitely use yaffs2 as the file ++ system type. With this, you can say "yaffs" and yaffs or yaffs2 ++ will be used depending on the device page size (yaffs on ++ 512-byte page devices, yaffs2 on 2K page devices). ++ ++ If unsure, say Y. ++ ++config YAFFS_DISABLE_LAZY_LOAD ++ bool "Disable lazy loading" ++ depends on YAFFS_YAFFS2 ++ default n ++ help ++ "Lazy loading" defers loading file details until they are ++ required. This saves mount time, but makes the first look-up ++ a bit longer. ++ ++ Lazy loading will only happen if enabled by this option being 'n' ++ and if the appropriate tags are available, else yaffs2 will ++ automatically fall back to immediate loading and do the right ++ thing. ++ ++ Lazy laoding will be required by checkpointing. ++ ++ Setting this to 'y' will disable lazy loading. ++ ++ If unsure, say N. ++ ++ ++config YAFFS_DISABLE_WIDE_TNODES ++ bool "Turn off wide tnodes" ++ depends on YAFFS_FS ++ default n ++ help ++ Wide tnodes are only used for NAND arrays >=32MB for 512-byte ++ page devices and >=128MB for 2k page devices. They use slightly ++ more RAM but are faster since they eliminate chunk group ++ searching. ++ ++ Setting this to 'y' will force tnode width to 16 bits and save ++ memory but make large arrays slower. ++ ++ If unsure, say N. ++ ++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bool "Force chunk erase check" ++ depends on YAFFS_FS ++ default n ++ help ++ Normally YAFFS only checks chunks before writing until an erased ++ chunk is found. This helps to detect any partially written ++ chunks that might have happened due to power loss. ++ ++ Enabling this forces on the test that chunks are erased in flash ++ before writing to them. This takes more time but is potentially ++ a bit more secure. ++ ++ Suggest setting Y during development and ironing out driver ++ issues etc. Suggest setting to N if you want faster writing. ++ ++ If unsure, say Y. ++ ++config YAFFS_SHORT_NAMES_IN_RAM ++ bool "Cache short names in RAM" ++ depends on YAFFS_FS ++ default y ++ help ++ If this config is set, then short names are stored with the ++ yaffs_Object. This costs an extra 16 bytes of RAM per object, ++ but makes look-ups faster. ++ ++ If unsure, say Y. +diff -Nur linux-2.6.30.orig/fs/yaffs2/Makefile linux-2.6.30/fs/yaffs2/Makefile +--- linux-2.6.30.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/Makefile 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux YAFFS filesystem routines. ++# ++ ++obj-$(CONFIG_YAFFS_FS) += yaffs.o ++ ++yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o ++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o ++yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o ++yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +diff -Nur linux-2.6.30.orig/fs/yaffs2/moduleconfig.h linux-2.6.30/fs/yaffs2/moduleconfig.h +--- linux-2.6.30.orig/fs/yaffs2/moduleconfig.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/moduleconfig.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Martin Fouts ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CONFIG_H__ ++#define __YAFFS_CONFIG_H__ ++ ++#ifdef YAFFS_OUT_OF_TREE ++ ++/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */ ++#define CONFIG_YAFFS_FS ++#define CONFIG_YAFFS_YAFFS1 ++#define CONFIG_YAFFS_YAFFS2 ++ ++/* These options are independent of each other. Select those that matter. */ ++ ++/* Default: Not selected */ ++/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ ++/* #define CONFIG_YAFFS_DOES_ECC */ ++ ++/* Default: Not selected */ ++/* Meaning: ECC byte order is 'wrong'. Only meaningful if */ ++/* CONFIG_YAFFS_DOES_ECC is set */ ++/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ ++ ++/* Default: Selected */ ++/* Meaning: Disables testing whether chunks are erased before writing to them*/ ++#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK ++ ++/* Default: Selected */ ++/* Meaning: Cache short names, taking more RAM, but faster look-ups */ ++#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ ++/* Default: 10 */ ++/* Meaning: set the count of blocks to reserve for checkpointing */ ++#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 ++ ++/* ++Older-style on-NAND data format has a "pageStatus" byte to record ++chunk/page state. This byte is zeroed when the page is discarded. ++Choose this option if you have existing on-NAND data in this format ++that you need to continue to support. New data written also uses the ++older-style format. ++Note: Use of this option generally requires that MTD's oob layout be ++adjusted to use the older-style format. See notes on tags formats and ++MTD versions in yaffs_mtdif1.c. ++*/ ++/* Default: Not selected */ ++/* Meaning: Use older-style on-NAND data format with pageStatus byte */ ++/* #define CONFIG_YAFFS_9BYTE_TAGS */ ++ ++#endif /* YAFFS_OUT_OF_TREE */ ++ ++#endif /* __YAFFS_CONFIG_H__ */ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,394 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_checkptrw_c_version = ++ "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $"; ++ ++ ++#include "yaffs_checkptrw.h" ++#include "yaffs_getblockinfo.h" ++ ++static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) ++{ ++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; ++ ++ T(YAFFS_TRACE_CHECKPOINT, ++ (TSTR("checkpt blocks available = %d" TENDSTR), ++ blocksAvailable)); ++ ++ return (blocksAvailable <= 0) ? 0 : 1; ++} ++ ++ ++static int yaffs_CheckpointErase(yaffs_Device *dev) ++{ ++ int i; ++ ++ if (!dev->eraseBlockInNAND) ++ return 0; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), ++ dev->internalStartBlock, dev->internalEndBlock)); ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i)); ++ if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { ++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } else { ++ dev->markNANDBlockBad(dev, i); ++ bi->blockState = YAFFS_BLOCK_STATE_DEAD; ++ } ++ } ++ } ++ ++ dev->blocksInCheckpoint = 0; ++ ++ return 1; ++} ++ ++ ++static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) ++{ ++ int i; ++ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; ++ T(YAFFS_TRACE_CHECKPOINT, ++ (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), ++ dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); ++ ++ if (dev->checkpointNextBlock >= 0 && ++ dev->checkpointNextBlock <= dev->internalEndBlock && ++ blocksAvailable > 0) { ++ ++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { ++ dev->checkpointNextBlock = i + 1; ++ dev->checkpointCurrentBlock = i; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i)); ++ return; ++ } ++ } ++ } ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR))); ++ ++ dev->checkpointNextBlock = -1; ++ dev->checkpointCurrentBlock = -1; ++} ++ ++static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) ++{ ++ int i; ++ yaffs_ExtendedTags tags; ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), ++ dev->blocksInCheckpoint, dev->checkpointNextBlock)); ++ ++ if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) ++ for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { ++ int chunk = i * dev->nChunksPerBlock; ++ int realignedChunk = chunk - dev->chunkOffset; ++ ++ dev->readChunkWithTagsFromNAND(dev, realignedChunk, ++ NULL, &tags); ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), ++ i, tags.objectId, tags.sequenceNumber, tags.eccResult)); ++ ++ if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) { ++ /* Right kind of block */ ++ dev->checkpointNextBlock = tags.objectId; ++ dev->checkpointCurrentBlock = i; ++ dev->checkpointBlockList[dev->blocksInCheckpoint] = i; ++ dev->blocksInCheckpoint++; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i)); ++ return; ++ } ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR))); ++ ++ dev->checkpointNextBlock = -1; ++ dev->checkpointCurrentBlock = -1; ++} ++ ++ ++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) ++{ ++ ++ /* Got the functions we need? */ ++ if (!dev->writeChunkWithTagsToNAND || ++ !dev->readChunkWithTagsFromNAND || ++ !dev->eraseBlockInNAND || ++ !dev->markNANDBlockBad) ++ return 0; ++ ++ if (forWriting && !yaffs_CheckpointSpaceOk(dev)) ++ return 0; ++ ++ if (!dev->checkpointBuffer) ++ dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ ++ dev->checkpointPageSequence = 0; ++ ++ dev->checkpointOpenForWrite = forWriting; ++ ++ dev->checkpointByteCount = 0; ++ dev->checkpointSum = 0; ++ dev->checkpointXor = 0; ++ dev->checkpointCurrentBlock = -1; ++ dev->checkpointCurrentChunk = -1; ++ dev->checkpointNextBlock = dev->internalStartBlock; ++ ++ /* Erase all the blocks in the checkpoint area */ ++ if (forWriting) { ++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); ++ dev->checkpointByteOffset = 0; ++ return yaffs_CheckpointErase(dev); ++ } else { ++ int i; ++ /* Set to a value that will kick off a read */ ++ dev->checkpointByteOffset = dev->nDataBytesPerChunk; ++ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) ++ * going to be way more than we need */ ++ dev->blocksInCheckpoint = 0; ++ dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; ++ dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); ++ for (i = 0; i < dev->checkpointMaxBlocks; i++) ++ dev->checkpointBlockList[i] = -1; ++ } ++ ++ return 1; ++} ++ ++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) ++{ ++ __u32 compositeSum; ++ compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); ++ *sum = compositeSum; ++ return 1; ++} ++ ++static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) ++{ ++ int chunk; ++ int realignedChunk; ++ ++ yaffs_ExtendedTags tags; ++ ++ if (dev->checkpointCurrentBlock < 0) { ++ yaffs_CheckpointFindNextErasedBlock(dev); ++ dev->checkpointCurrentChunk = 0; ++ } ++ ++ if (dev->checkpointCurrentBlock < 0) ++ return 0; ++ ++ tags.chunkDeleted = 0; ++ tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ ++ tags.chunkId = dev->checkpointPageSequence + 1; ++ tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA; ++ tags.byteCount = dev->nDataBytesPerChunk; ++ if (dev->checkpointCurrentChunk == 0) { ++ /* First chunk we write for the block? Set block state to ++ checkpoint */ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock); ++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; ++ dev->blocksInCheckpoint++; ++ } ++ ++ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; ++ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), ++ chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId)); ++ ++ realignedChunk = chunk - dev->chunkOffset; ++ ++ dev->writeChunkWithTagsToNAND(dev, realignedChunk, ++ dev->checkpointBuffer, &tags); ++ dev->checkpointByteOffset = 0; ++ dev->checkpointPageSequence++; ++ dev->checkpointCurrentChunk++; ++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { ++ dev->checkpointCurrentChunk = 0; ++ dev->checkpointCurrentBlock = -1; ++ } ++ memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); ++ ++ return 1; ++} ++ ++ ++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) ++{ ++ int i = 0; ++ int ok = 1; ++ ++ ++ __u8 * dataBytes = (__u8 *)data; ++ ++ ++ ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ if (!dev->checkpointOpenForWrite) ++ return -1; ++ ++ while (i < nBytes && ok) { ++ dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes; ++ dev->checkpointSum += *dataBytes; ++ dev->checkpointXor ^= *dataBytes; ++ ++ dev->checkpointByteOffset++; ++ i++; ++ dataBytes++; ++ dev->checkpointByteCount++; ++ ++ ++ if (dev->checkpointByteOffset < 0 || ++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) ++ ok = yaffs_CheckpointFlushBuffer(dev); ++ } ++ ++ return i; ++} ++ ++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) ++{ ++ int i = 0; ++ int ok = 1; ++ yaffs_ExtendedTags tags; ++ ++ ++ int chunk; ++ int realignedChunk; ++ ++ __u8 *dataBytes = (__u8 *)data; ++ ++ if (!dev->checkpointBuffer) ++ return 0; ++ ++ if (dev->checkpointOpenForWrite) ++ return -1; ++ ++ while (i < nBytes && ok) { ++ ++ ++ if (dev->checkpointByteOffset < 0 || ++ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { ++ ++ if (dev->checkpointCurrentBlock < 0) { ++ yaffs_CheckpointFindNextCheckpointBlock(dev); ++ dev->checkpointCurrentChunk = 0; ++ } ++ ++ if (dev->checkpointCurrentBlock < 0) ++ ok = 0; ++ else { ++ chunk = dev->checkpointCurrentBlock * ++ dev->nChunksPerBlock + ++ dev->checkpointCurrentChunk; ++ ++ realignedChunk = chunk - dev->chunkOffset; ++ ++ /* read in the next chunk */ ++ /* printf("read checkpoint page %d\n",dev->checkpointPage); */ ++ dev->readChunkWithTagsFromNAND(dev, ++ realignedChunk, ++ dev->checkpointBuffer, ++ &tags); ++ ++ if (tags.chunkId != (dev->checkpointPageSequence + 1) || ++ tags.eccResult > YAFFS_ECC_RESULT_FIXED || ++ tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ ok = 0; ++ ++ dev->checkpointByteOffset = 0; ++ dev->checkpointPageSequence++; ++ dev->checkpointCurrentChunk++; ++ ++ if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) ++ dev->checkpointCurrentBlock = -1; ++ } ++ } ++ ++ if (ok) { ++ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; ++ dev->checkpointSum += *dataBytes; ++ dev->checkpointXor ^= *dataBytes; ++ dev->checkpointByteOffset++; ++ i++; ++ dataBytes++; ++ dev->checkpointByteCount++; ++ } ++ } ++ ++ return i; ++} ++ ++int yaffs_CheckpointClose(yaffs_Device *dev) ++{ ++ ++ if (dev->checkpointOpenForWrite) { ++ if (dev->checkpointByteOffset != 0) ++ yaffs_CheckpointFlushBuffer(dev); ++ } else { ++ int i; ++ for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]); ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) ++ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; ++ else { ++ /* Todo this looks odd... */ ++ } ++ } ++ YFREE(dev->checkpointBlockList); ++ dev->checkpointBlockList = NULL; ++ } ++ ++ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; ++ dev->nErasedBlocks -= dev->blocksInCheckpoint; ++ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR), ++ dev->checkpointByteCount)); ++ ++ if (dev->checkpointBuffer) { ++ /* free the buffer */ ++ YFREE(dev->checkpointBuffer); ++ dev->checkpointBuffer = NULL; ++ return 1; ++ } else ++ return 0; ++} ++ ++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) ++{ ++ /* Erase the first checksum block */ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR))); ++ ++ if (!yaffs_CheckpointSpaceOk(dev)) ++ return 0; ++ ++ return yaffs_CheckpointErase(dev); ++} ++ ++ ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_checkptrw.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_CHECKPTRW_H__ ++#define __YAFFS_CHECKPTRW_H__ ++ ++#include "yaffs_guts.h" ++ ++int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); ++ ++int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); ++ ++int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); ++ ++int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); ++ ++int yaffs_CheckpointClose(yaffs_Device *dev); ++ ++int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); ++ ++ ++#endif ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.30/fs/yaffs2/yaffs_ecc.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_ecc.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,326 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC ++ * blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++/* Table generated by gen-ecc.c ++ * Using a table means we do not have to calculate p1..p4 and p1'..p4' ++ * for each byte of data. These are instead provided in a table in bits7..2. ++ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore ++ * this bytes influence on the line parity. ++ */ ++ ++const char *yaffs_ecc_c_version = ++ "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++#include "yaffs_ecc.h" ++ ++static const unsigned char column_parity_table[] = { ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, ++ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, ++ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, ++ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, ++ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, ++ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, ++ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, ++ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, ++ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, ++ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, ++ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, ++ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, ++ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, ++ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, ++ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, ++ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, ++}; ++ ++/* Count the bits in an unsigned char or a U32 */ ++ ++static int yaffs_CountBits(unsigned char x) ++{ ++ int r = 0; ++ while (x) { ++ if (x & 1) ++ r++; ++ x >>= 1; ++ } ++ return r; ++} ++ ++static int yaffs_CountBits32(unsigned x) ++{ ++ int r = 0; ++ while (x) { ++ if (x & 1) ++ r++; ++ x >>= 1; ++ } ++ return r; ++} ++ ++/* Calculate the ECC for a 256-byte block of data */ ++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) ++{ ++ unsigned int i; ++ ++ unsigned char col_parity = 0; ++ unsigned char line_parity = 0; ++ unsigned char line_parity_prime = 0; ++ unsigned char t; ++ unsigned char b; ++ ++ for (i = 0; i < 256; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ } ++ ++ ecc[2] = (~col_parity) | 0x03; ++ ++ t = 0; ++ if (line_parity & 0x80) ++ t |= 0x80; ++ if (line_parity_prime & 0x80) ++ t |= 0x40; ++ if (line_parity & 0x40) ++ t |= 0x20; ++ if (line_parity_prime & 0x40) ++ t |= 0x10; ++ if (line_parity & 0x20) ++ t |= 0x08; ++ if (line_parity_prime & 0x20) ++ t |= 0x04; ++ if (line_parity & 0x10) ++ t |= 0x02; ++ if (line_parity_prime & 0x10) ++ t |= 0x01; ++ ecc[1] = ~t; ++ ++ t = 0; ++ if (line_parity & 0x08) ++ t |= 0x80; ++ if (line_parity_prime & 0x08) ++ t |= 0x40; ++ if (line_parity & 0x04) ++ t |= 0x20; ++ if (line_parity_prime & 0x04) ++ t |= 0x10; ++ if (line_parity & 0x02) ++ t |= 0x08; ++ if (line_parity_prime & 0x02) ++ t |= 0x04; ++ if (line_parity & 0x01) ++ t |= 0x02; ++ if (line_parity_prime & 0x01) ++ t |= 0x01; ++ ecc[0] = ~t; ++ ++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER ++ /* Swap the bytes into the wrong order */ ++ t = ecc[0]; ++ ecc[0] = ecc[1]; ++ ecc[1] = t; ++#endif ++} ++ ++ ++/* Correct the ECC on a 256 byte block of data */ ++ ++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc) ++{ ++ unsigned char d0, d1, d2; /* deltas */ ++ ++ d0 = read_ecc[0] ^ test_ecc[0]; ++ d1 = read_ecc[1] ^ test_ecc[1]; ++ d2 = read_ecc[2] ^ test_ecc[2]; ++ ++ if ((d0 | d1 | d2) == 0) ++ return 0; /* no error */ ++ ++ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && ++ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && ++ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { ++ /* Single bit (recoverable) error in data */ ++ ++ unsigned byte; ++ unsigned bit; ++ ++#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER ++ /* swap the bytes to correct for the wrong order */ ++ unsigned char t; ++ ++ t = d0; ++ d0 = d1; ++ d1 = t; ++#endif ++ ++ bit = byte = 0; ++ ++ if (d1 & 0x80) ++ byte |= 0x80; ++ if (d1 & 0x20) ++ byte |= 0x40; ++ if (d1 & 0x08) ++ byte |= 0x20; ++ if (d1 & 0x02) ++ byte |= 0x10; ++ if (d0 & 0x80) ++ byte |= 0x08; ++ if (d0 & 0x20) ++ byte |= 0x04; ++ if (d0 & 0x08) ++ byte |= 0x02; ++ if (d0 & 0x02) ++ byte |= 0x01; ++ ++ if (d2 & 0x80) ++ bit |= 0x04; ++ if (d2 & 0x20) ++ bit |= 0x02; ++ if (d2 & 0x08) ++ bit |= 0x01; ++ ++ data[byte] ^= (1 << bit); ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ if ((yaffs_CountBits(d0) + ++ yaffs_CountBits(d1) + ++ yaffs_CountBits(d2)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ read_ecc[0] = test_ecc[0]; ++ read_ecc[1] = test_ecc[1]; ++ read_ecc[2] = test_ecc[2]; ++ ++ return 1; /* Corrected the error */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++ ++} ++ ++ ++/* ++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data ++ */ ++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *eccOther) ++{ ++ unsigned int i; ++ ++ unsigned char col_parity = 0; ++ unsigned line_parity = 0; ++ unsigned line_parity_prime = 0; ++ unsigned char b; ++ ++ for (i = 0; i < nBytes; i++) { ++ b = column_parity_table[*data++]; ++ col_parity ^= b; ++ ++ if (b & 0x01) { ++ /* odd number of bits in the byte */ ++ line_parity ^= i; ++ line_parity_prime ^= ~i; ++ } ++ ++ } ++ ++ eccOther->colParity = (col_parity >> 2) & 0x3f; ++ eccOther->lineParity = line_parity; ++ eccOther->lineParityPrime = line_parity_prime; ++} ++ ++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *read_ecc, ++ const yaffs_ECCOther *test_ecc) ++{ ++ unsigned char cDelta; /* column parity delta */ ++ unsigned lDelta; /* line parity delta */ ++ unsigned lDeltaPrime; /* line parity delta */ ++ unsigned bit; ++ ++ cDelta = read_ecc->colParity ^ test_ecc->colParity; ++ lDelta = read_ecc->lineParity ^ test_ecc->lineParity; ++ lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime; ++ ++ if ((cDelta | lDelta | lDeltaPrime) == 0) ++ return 0; /* no error */ ++ ++ if (lDelta == ~lDeltaPrime && ++ (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) { ++ /* Single bit (recoverable) error in data */ ++ ++ bit = 0; ++ ++ if (cDelta & 0x20) ++ bit |= 0x04; ++ if (cDelta & 0x08) ++ bit |= 0x02; ++ if (cDelta & 0x02) ++ bit |= 0x01; ++ ++ if (lDelta >= nBytes) ++ return -1; ++ ++ data[lDelta] ^= (1 << bit); ++ ++ return 1; /* corrected */ ++ } ++ ++ if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + ++ yaffs_CountBits(cDelta)) == 1) { ++ /* Reccoverable error in ecc */ ++ ++ *read_ecc = *test_ecc; ++ return 1; /* corrected */ ++ } ++ ++ /* Unrecoverable error */ ++ ++ return -1; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.30/fs/yaffs2/yaffs_ecc.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_ecc.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* ++ * This code implements the ECC algorithm used in SmartMedia. ++ * ++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. ++ * The two unused bit are set to 1. ++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC ++ * blocks are used on a 512-byte NAND page. ++ * ++ */ ++ ++#ifndef __YAFFS_ECC_H__ ++#define __YAFFS_ECC_H__ ++ ++typedef struct { ++ unsigned char colParity; ++ unsigned lineParity; ++ unsigned lineParityPrime; ++} yaffs_ECCOther; ++ ++void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); ++int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, ++ const unsigned char *test_ecc); ++ ++void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *ecc); ++int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, ++ yaffs_ECCOther *read_ecc, ++ const yaffs_ECCOther *test_ecc); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c linux-2.6.30/fs/yaffs2/yaffs_fs.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_fs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_fs.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,2529 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2009 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * Acknowledgements: ++ * Luc van OostenRyck for numerous patches. ++ * Nick Bane for numerous patches. ++ * Nick Bane for 2.5/2.6 integration. ++ * Andras Toth for mknod rdev issue. ++ * Michael Fischer for finding the problem with inode inconsistency. ++ * Some code bodily lifted from JFFS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * ++ * This is the file system front-end to YAFFS that hooks it up to ++ * the VFS. ++ * ++ * Special notes: ++ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with ++ * this superblock ++ * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this ++ * superblock ++ * >> inode->u.generic_ip points to the associated yaffs_Object. ++ */ ++ ++const char *yaffs_fs_c_version = ++ "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $"; ++extern const char *yaffs_guts_c_version; ++ ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "asm/div64.h" ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++#include /* Added NCB 15-8-2003 */ ++#include ++#define UnlockPage(p) unlock_page(p) ++#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) ++ ++/* FIXME: use sb->s_id instead ? */ ++#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) ++ ++#else ++ ++#include ++#define BDEVNAME_SIZE 0 ++#define yaffs_devname(sb, buf) kdevname(sb->s_dev) ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) ++/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ ++#define __user ++#endif ++ ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) ++#define YPROC_ROOT (&proc_root) ++#else ++#define YPROC_ROOT NULL ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++#define WRITE_SIZE_STR "writesize" ++#define WRITE_SIZE(mtd) ((mtd)->writesize) ++#else ++#define WRITE_SIZE_STR "oobblock" ++#define WRITE_SIZE(mtd) ((mtd)->oobblock) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) ++#define YAFFS_USE_WRITE_BEGIN_END 1 ++#else ++#define YAFFS_USE_WRITE_BEGIN_END 0 ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) ++static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) ++{ ++ uint64_t result = partition_size; ++ do_div(result, block_size); ++ return (uint32_t)result; ++} ++#else ++#define YCALCBLOCKS(s, b) ((s)/(b)) ++#endif ++ ++#include ++ ++#include "yportenv.h" ++#include "yaffs_guts.h" ++ ++#include ++#include "yaffs_mtdif.h" ++#include "yaffs_mtdif1.h" ++#include "yaffs_mtdif2.h" ++ ++unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; ++unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; ++unsigned int yaffs_auto_checkpoint = 1; ++ ++/* Module Parameters */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++module_param(yaffs_traceMask, uint, 0644); ++module_param(yaffs_wr_attempts, uint, 0644); ++module_param(yaffs_auto_checkpoint, uint, 0644); ++#else ++MODULE_PARM(yaffs_traceMask, "i"); ++MODULE_PARM(yaffs_wr_attempts, "i"); ++MODULE_PARM(yaffs_auto_checkpoint, "i"); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) ++/* use iget and read_inode */ ++#define Y_IGET(sb, inum) iget((sb), (inum)) ++static void yaffs_read_inode(struct inode *inode); ++ ++#else ++/* Call local equivalent */ ++#define YAFFS_USE_OWN_IGET ++#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); ++#endif ++ ++/*#define T(x) printk x */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) ++#else ++#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip) ++#endif ++ ++#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) ++#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info) ++#else ++#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) ++#endif ++ ++static void yaffs_put_super(struct super_block *sb); ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t *pos); ++static ssize_t yaffs_hold_space(struct file *f); ++static void yaffs_release_space(struct file *f); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id); ++#else ++static int yaffs_file_flush(struct file *file); ++#endif ++ ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync); ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n); ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n); ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); ++#endif ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry); ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry); ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname); ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t dev); ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int dev); ++#endif ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry); ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait); ++static void yaffs_write_super(struct super_block *sb); ++#else ++static int yaffs_sync_fs(struct super_block *sb); ++static int yaffs_write_super(struct super_block *sb); ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf); ++#endif ++ ++#ifdef YAFFS_HAS_PUT_INODE ++static void yaffs_put_inode(struct inode *inode); ++#endif ++ ++static void yaffs_delete_inode(struct inode *); ++static void yaffs_clear_inode(struct inode *); ++ ++static int yaffs_readpage(struct file *file, struct page *page); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc); ++#else ++static int yaffs_writepage(struct page *page); ++#endif ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END != 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata); ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata); ++#else ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to); ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to); ++ ++#endif ++ ++static int yaffs_readlink(struct dentry *dentry, char __user *buffer, ++ int buflen); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); ++#endif ++ ++static struct address_space_operations yaffs_file_address_operations = { ++ .readpage = yaffs_readpage, ++ .writepage = yaffs_writepage, ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++ .write_begin = yaffs_write_begin, ++ .write_end = yaffs_write_end, ++#else ++ .prepare_write = yaffs_prepare_write, ++ .commit_write = yaffs_commit_write, ++#endif ++}; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = generic_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = generic_file_aio_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .sendfile = generic_file_sendfile, ++}; ++ ++#else ++ ++static const struct file_operations yaffs_file_operations = { ++ .read = generic_file_read, ++ .write = generic_file_write, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ .sendfile = generic_file_sendfile, ++#endif ++}; ++#endif ++ ++static const struct inode_operations yaffs_file_inode_operations = { ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct inode_operations yaffs_symlink_inode_operations = { ++ .readlink = yaffs_readlink, ++ .follow_link = yaffs_follow_link, ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct inode_operations yaffs_dir_inode_operations = { ++ .create = yaffs_create, ++ .lookup = yaffs_lookup, ++ .link = yaffs_link, ++ .unlink = yaffs_unlink, ++ .symlink = yaffs_symlink, ++ .mkdir = yaffs_mkdir, ++ .rmdir = yaffs_unlink, ++ .mknod = yaffs_mknod, ++ .rename = yaffs_rename, ++ .setattr = yaffs_setattr, ++}; ++ ++static const struct file_operations yaffs_dir_operations = { ++ .read = generic_read_dir, ++ .readdir = yaffs_readdir, ++ .fsync = yaffs_sync_object, ++}; ++ ++static const struct super_operations yaffs_super_ops = { ++ .statfs = yaffs_statfs, ++ ++#ifndef YAFFS_USE_OWN_IGET ++ .read_inode = yaffs_read_inode, ++#endif ++#ifdef YAFFS_HAS_PUT_INODE ++ .put_inode = yaffs_put_inode, ++#endif ++ .put_super = yaffs_put_super, ++ .delete_inode = yaffs_delete_inode, ++ .clear_inode = yaffs_clear_inode, ++ .sync_fs = yaffs_sync_fs, ++ .write_super = yaffs_write_super, ++}; ++ ++static void yaffs_GrossLock(yaffs_Device *dev) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); ++ down(&dev->grossLock); ++ T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); ++} ++ ++static void yaffs_GrossUnlock(yaffs_Device *dev) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); ++ up(&dev->grossLock); ++} ++ ++static int yaffs_readlink(struct dentry *dentry, char __user *buffer, ++ int buflen) ++{ ++ unsigned char *alias; ++ int ret; ++ ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (!alias) ++ return -ENOMEM; ++ ++ ret = vfs_readlink(dentry, buffer, buflen, alias); ++ kfree(alias); ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++#else ++static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) ++#endif ++{ ++ unsigned char *alias; ++ int ret; ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (!alias) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = vfs_follow_link(nd, alias); ++ kfree(alias); ++out: ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ return ERR_PTR(ret); ++#else ++ return ret; ++#endif ++} ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ yaffs_Object *obj); ++ ++/* ++ * Lookup is used to find objects in the fs ++ */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *n) ++#else ++static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) ++#endif ++{ ++ yaffs_Object *obj; ++ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ ++ ++ yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_lookup for %d:%s\n", ++ yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); ++ ++ obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), ++ dentry->d_name.name); ++ ++ obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ ++ ++ /* Can't hold gross lock when calling yaffs_get_inode() */ ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_lookup found %d\n", obj->objectId)); ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ ++ if (inode) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_loookup dentry \n")); ++/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to ++ * d_add even if NULL inode */ ++#if 0 ++ /*dget(dentry); // try to solve directory bug */ ++ d_add(dentry, inode); ++ ++ /* return dentry; */ ++ return NULL; ++#endif ++ } ++ ++ } else { ++ T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); ++ ++ } ++ ++/* added NCB for 2.5/6 compatability - forces add even if inode is ++ * NULL which creates dentry hash */ ++ d_add(dentry, inode); ++ ++ return NULL; ++} ++ ++ ++#ifdef YAFFS_HAS_PUT_INODE ++ ++/* For now put inode is just for debugging ++ * Put inode is called when the inode **structure** is put. ++ */ ++static void yaffs_put_inode(struct inode *inode) ++{ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count))); ++ ++} ++#endif ++ ++/* clear is called to tell the fs to release any per-inode data it holds */ ++static void yaffs_clear_inode(struct inode *inode) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ obj = yaffs_InodeToObject(inode); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object")); ++ ++ if (obj) { ++ dev = obj->myDev; ++ yaffs_GrossLock(dev); ++ ++ /* Clear the association between the inode and ++ * the yaffs_Object. ++ */ ++ obj->myInode = NULL; ++ yaffs_InodeToObjectLV(inode) = NULL; ++ ++ /* If the object freeing was deferred, then the real ++ * free happens now. ++ * This should fix the inode inconsistency problem. ++ */ ++ ++ yaffs_HandleDeferedFree(obj); ++ ++ yaffs_GrossUnlock(dev); ++ } ++ ++} ++ ++/* delete is called when the link count is zero and the inode ++ * is put (ie. nobody wants to know about it anymore, time to ++ * delete the file). ++ * NB Must call clear_inode() ++ */ ++static void yaffs_delete_inode(struct inode *inode) ++{ ++ yaffs_Object *obj = yaffs_InodeToObject(inode); ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, ++ atomic_read(&inode->i_count), ++ obj ? "object exists" : "null object")); ++ ++ if (obj) { ++ dev = obj->myDev; ++ yaffs_GrossLock(dev); ++ yaffs_DeleteObject(obj); ++ yaffs_GrossUnlock(dev); ++ } ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) ++ truncate_inode_pages(&inode->i_data, 0); ++#endif ++ clear_inode(inode); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_file_flush(struct file *file, fl_owner_t id) ++#else ++static int yaffs_file_flush(struct file *file) ++#endif ++{ ++ yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); ++ ++ yaffs_Device *dev = obj->myDev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_flush object %d (%s)\n", obj->objectId, ++ obj->dirty ? "dirty" : "clean")); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushFile(obj, 1); ++ ++ yaffs_GrossUnlock(dev); ++ ++ return 0; ++} ++ ++static int yaffs_readpage_nolock(struct file *f, struct page *pg) ++{ ++ /* Lifted from jffs2 */ ++ ++ yaffs_Object *obj; ++ unsigned char *pg_buf; ++ int ret; ++ ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n", ++ (unsigned)(pg->index << PAGE_CACHE_SHIFT), ++ (unsigned)PAGE_CACHE_SIZE)); ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ BUG_ON(!PageLocked(pg)); ++#else ++ if (!PageLocked(pg)) ++ PAGE_BUG(pg); ++#endif ++ ++ pg_buf = kmap(pg); ++ /* FIXME: Can kmap fail? */ ++ ++ yaffs_GrossLock(dev); ++ ++ ret = yaffs_ReadDataFromFile(obj, pg_buf, ++ pg->index << PAGE_CACHE_SHIFT, ++ PAGE_CACHE_SIZE); ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (ret >= 0) ++ ret = 0; ++ ++ if (ret) { ++ ClearPageUptodate(pg); ++ SetPageError(pg); ++ } else { ++ SetPageUptodate(pg); ++ ClearPageError(pg); ++ } ++ ++ flush_dcache_page(pg); ++ kunmap(pg); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); ++ return ret; ++} ++ ++static int yaffs_readpage_unlock(struct file *f, struct page *pg) ++{ ++ int ret = yaffs_readpage_nolock(f, pg); ++ UnlockPage(pg); ++ return ret; ++} ++ ++static int yaffs_readpage(struct file *f, struct page *pg) ++{ ++ return yaffs_readpage_unlock(f, pg); ++} ++ ++/* writepage inspired by/stolen from smbfs */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_writepage(struct page *page, struct writeback_control *wbc) ++#else ++static int yaffs_writepage(struct page *page) ++#endif ++{ ++ struct address_space *mapping = page->mapping; ++ loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; ++ struct inode *inode; ++ unsigned long end_index; ++ char *buffer; ++ yaffs_Object *obj; ++ int nWritten = 0; ++ unsigned nBytes; ++ ++ if (!mapping) ++ BUG(); ++ inode = mapping->host; ++ if (!inode) ++ BUG(); ++ ++ if (offset > inode->i_size) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_writepage at %08x, inode size = %08x!!!\n", ++ (unsigned)(page->index << PAGE_CACHE_SHIFT), ++ (unsigned)inode->i_size)); ++ T(YAFFS_TRACE_OS, ++ (" -> don't care!!\n")); ++ unlock_page(page); ++ return 0; ++ } ++ ++ end_index = inode->i_size >> PAGE_CACHE_SHIFT; ++ ++ /* easy case */ ++ if (page->index < end_index) ++ nBytes = PAGE_CACHE_SIZE; ++ else ++ nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); ++ ++ get_page(page); ++ ++ buffer = kmap(page); ++ ++ obj = yaffs_InodeToObject(inode); ++ yaffs_GrossLock(obj->myDev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_writepage at %08x, size %08x\n", ++ (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); ++ T(YAFFS_TRACE_OS, ++ ("writepag0: obj = %05x, ino = %05x\n", ++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); ++ ++ nWritten = yaffs_WriteDataToFile(obj, buffer, ++ page->index << PAGE_CACHE_SHIFT, nBytes, 0); ++ ++ T(YAFFS_TRACE_OS, ++ ("writepag1: obj = %05x, ino = %05x\n", ++ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); ++ ++ yaffs_GrossUnlock(obj->myDev); ++ ++ kunmap(page); ++ SetPageUptodate(page); ++ UnlockPage(page); ++ put_page(page); ++ ++ return (nWritten == nBytes) ? 0 : -ENOSPC; ++} ++ ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_begin(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct page *pg = NULL; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ uint32_t offset = pos & (PAGE_CACHE_SIZE - 1); ++ uint32_t to = offset + len; ++ ++ int ret = 0; ++ int space_held = 0; ++ ++ T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); ++ /* Get a page */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) ++ pg = grab_cache_page_write_begin(mapping, index, flags); ++#else ++ pg = __grab_cache_page(mapping, index); ++#endif ++ ++ *pagep = pg; ++ if (!pg) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ /* Get fs space */ ++ space_held = yaffs_hold_space(filp); ++ ++ if (!space_held) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ /* Update page if required */ ++ ++ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) ++ ret = yaffs_readpage_nolock(filp, pg); ++ ++ if (ret) ++ goto out; ++ ++ /* Happy path return */ ++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); ++ ++ return 0; ++ ++out: ++ T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); ++ if (space_held) ++ yaffs_release_space(filp); ++ if (pg) { ++ unlock_page(pg); ++ page_cache_release(pg); ++ } ++ return ret; ++} ++ ++#else ++ ++static int yaffs_prepare_write(struct file *f, struct page *pg, ++ unsigned offset, unsigned to) ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); ++ ++ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) ++ return yaffs_readpage_nolock(f, pg); ++ return 0; ++} ++#endif ++ ++#if (YAFFS_USE_WRITE_BEGIN_END > 0) ++static int yaffs_write_end(struct file *filp, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *pg, void *fsdadata) ++{ ++ int ret = 0; ++ void *addr, *kva; ++ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); ++ ++ kva = kmap(pg); ++ addr = kva + offset_into_page; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_write_end addr %x pos %x nBytes %d\n", ++ (unsigned) addr, ++ (int)pos, copied)); ++ ++ ret = yaffs_file_write(filp, addr, copied, &pos); ++ ++ if (ret != copied) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_write_end not same size ret %d copied %d\n", ++ ret, copied)); ++ SetPageError(pg); ++ ClearPageUptodate(pg); ++ } else { ++ SetPageUptodate(pg); ++ } ++ ++ kunmap(pg); ++ ++ yaffs_release_space(filp); ++ unlock_page(pg); ++ page_cache_release(pg); ++ return ret; ++} ++#else ++ ++static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, ++ unsigned to) ++{ ++ void *addr, *kva; ++ ++ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; ++ int nBytes = to - offset; ++ int nWritten; ++ ++ unsigned spos = pos; ++ unsigned saddr; ++ ++ kva = kmap(pg); ++ addr = kva + offset; ++ ++ saddr = (unsigned) addr; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write addr %x pos %x nBytes %d\n", ++ saddr, spos, nBytes)); ++ ++ nWritten = yaffs_file_write(f, addr, nBytes, &pos); ++ ++ if (nWritten != nBytes) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write not same size nWritten %d nBytes %d\n", ++ nWritten, nBytes)); ++ SetPageError(pg); ++ ClearPageUptodate(pg); ++ } else { ++ SetPageUptodate(pg); ++ } ++ ++ kunmap(pg); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_commit_write returning %d\n", ++ nWritten == nBytes ? 0 : nWritten)); ++ ++ return nWritten == nBytes ? 0 : nWritten; ++} ++#endif ++ ++ ++static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) ++{ ++ if (inode && obj) { ++ ++ ++ /* Check mode against the variant type and attempt to repair if broken. */ ++ __u32 mode = obj->yst_mode; ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (!S_ISREG(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFREG; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (!S_ISLNK(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFLNK; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ if (!S_ISDIR(mode)) { ++ obj->yst_mode &= ~S_IFMT; ++ obj->yst_mode |= S_IFDIR; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ default: ++ /* TODO? */ ++ break; ++ } ++ ++ inode->i_flags |= S_NOATIME; ++ ++ inode->i_ino = obj->objectId; ++ inode->i_mode = obj->yst_mode; ++ inode->i_uid = obj->yst_uid; ++ inode->i_gid = obj->yst_gid; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++ inode->i_blksize = inode->i_sb->s_blocksize; ++#endif ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ ++ inode->i_rdev = old_decode_dev(obj->yst_rdev); ++ inode->i_atime.tv_sec = (time_t) (obj->yst_atime); ++ inode->i_atime.tv_nsec = 0; ++ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; ++ inode->i_mtime.tv_nsec = 0; ++ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; ++ inode->i_ctime.tv_nsec = 0; ++#else ++ inode->i_rdev = obj->yst_rdev; ++ inode->i_atime = obj->yst_atime; ++ inode->i_mtime = obj->yst_mtime; ++ inode->i_ctime = obj->yst_ctime; ++#endif ++ inode->i_size = yaffs_GetObjectFileLength(obj); ++ inode->i_blocks = (inode->i_size + 511) >> 9; ++ ++ inode->i_nlink = yaffs_GetObjectLinkCount(obj); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", ++ inode->i_mode, inode->i_uid, inode->i_gid, ++ (int)inode->i_size, atomic_read(&inode->i_count))); ++ ++ switch (obj->yst_mode & S_IFMT) { ++ default: /* fifo, device or socket */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ init_special_inode(inode, obj->yst_mode, ++ old_decode_dev(obj->yst_rdev)); ++#else ++ init_special_inode(inode, obj->yst_mode, ++ (dev_t) (obj->yst_rdev)); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ inode->i_op = &yaffs_file_inode_operations; ++ inode->i_fop = &yaffs_file_operations; ++ inode->i_mapping->a_ops = ++ &yaffs_file_address_operations; ++ break; ++ case S_IFDIR: /* directory */ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ break; ++ case S_IFLNK: /* symlink */ ++ inode->i_op = &yaffs_symlink_inode_operations; ++ break; ++ } ++ ++ yaffs_InodeToObjectLV(inode) = obj; ++ ++ obj->myInode = inode; ++ ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_FileInode invalid parameters\n")); ++ } ++ ++} ++ ++struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, ++ yaffs_Object *obj) ++{ ++ struct inode *inode; ++ ++ if (!sb) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for NULL super_block!!\n")); ++ return NULL; ++ ++ } ++ ++ if (!obj) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for NULL object!!\n")); ++ return NULL; ++ ++ } ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_get_inode for object %d\n", obj->objectId)); ++ ++ inode = Y_IGET(sb, obj->objectId); ++ if (IS_ERR(inode)) ++ return NULL; ++ ++ /* NB Side effect: iget calls back to yaffs_read_inode(). */ ++ /* iget also increments the inode's i_count */ ++ /* NB You can't be holding grossLock or deadlock will happen! */ ++ ++ return inode; ++} ++ ++static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, ++ loff_t *pos) ++{ ++ yaffs_Object *obj; ++ int nWritten, ipos; ++ struct inode *inode; ++ yaffs_Device *dev; ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ inode = f->f_dentry->d_inode; ++ ++ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) ++ ipos = inode->i_size; ++ else ++ ipos = *pos; ++ ++ if (!obj) ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write: hey obj is null!\n")); ++ else ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write about to write writing %zu bytes" ++ "to object %d at %d\n", ++ n, obj->objectId, ipos)); ++ ++ nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write writing %zu bytes, %d written at %d\n", ++ n, nWritten, ipos)); ++ ++ if (nWritten > 0) { ++ ipos += nWritten; ++ *pos = ipos; ++ if (ipos > inode->i_size) { ++ inode->i_size = ipos; ++ inode->i_blocks = (ipos + 511) >> 9; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_file_write size updated to %d bytes, " ++ "%d blocks\n", ++ ipos, (int)(inode->i_blocks))); ++ } ++ ++ } ++ yaffs_GrossUnlock(dev); ++ return nWritten == 0 ? -ENOSPC : nWritten; ++} ++ ++/* Space holding and freeing is done to ensure we have space available for write_begin/end */ ++/* For now we just assume few parallel writes and check against a small number. */ ++/* Todo: need to do this with a counter to handle parallel reads better */ ++ ++static ssize_t yaffs_hold_space(struct file *f) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ int nFreeChunks; ++ ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ nFreeChunks = yaffs_GetNumberOfFreeChunks(dev); ++ ++ yaffs_GrossUnlock(dev); ++ ++ return (nFreeChunks > 20) ? 1 : 0; ++} ++ ++static void yaffs_release_space(struct file *f) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ ++ yaffs_GrossUnlock(dev); ++} ++ ++static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ struct inode *inode = f->f_dentry->d_inode; ++ unsigned long offset, curoffs; ++ struct ylist_head *i; ++ yaffs_Object *l; ++ ++ char name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ obj = yaffs_DentryToObject(f->f_dentry); ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ offset = f->f_pos; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); ++ ++ if (offset == 0) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: entry . ino %d \n", ++ (int)inode->i_ino)); ++ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) ++ goto out; ++ offset++; ++ f->f_pos++; ++ } ++ if (offset == 1) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: entry .. ino %d \n", ++ (int)f->f_dentry->d_parent->d_inode->i_ino)); ++ if (filldir(dirent, "..", 2, offset, ++ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) ++ goto out; ++ offset++; ++ f->f_pos++; ++ } ++ ++ curoffs = 1; ++ ++ /* If the directory has changed since the open or last call to ++ readdir, rewind to after the 2 canned entries. */ ++ ++ if (f->f_version != inode->i_version) { ++ offset = 2; ++ f->f_pos = offset; ++ f->f_version = inode->i_version; ++ } ++ ++ ylist_for_each(i, &obj->variant.directoryVariant.children) { ++ curoffs++; ++ if (curoffs >= offset) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ ++ yaffs_GetObjectName(l, name, ++ YAFFS_MAX_NAME_LENGTH + 1); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_readdir: %s inode %d\n", name, ++ yaffs_GetObjectInode(l))); ++ ++ if (filldir(dirent, ++ name, ++ strlen(name), ++ offset, ++ yaffs_GetObjectInode(l), ++ yaffs_GetObjectType(l)) < 0) ++ goto up_and_out; ++ ++ offset++; ++ f->f_pos++; ++ } ++ } ++ ++up_and_out: ++out: ++ yaffs_GrossUnlock(dev); ++ ++ return 0; ++} ++ ++/* ++ * File creation. Allocate an inode, and we're done.. ++ */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define YCRED(x) x ++#else ++#define YCRED(x) (x->cred) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ dev_t rdev) ++#else ++static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, ++ int rdev) ++#endif ++{ ++ struct inode *inode; ++ ++ yaffs_Object *obj = NULL; ++ yaffs_Device *dev; ++ ++ yaffs_Object *parent = yaffs_InodeToObject(dir); ++ ++ int error = -ENOSPC; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) ++ mode |= S_ISGID; ++ ++ if (parent) { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: parent object %d type %d\n", ++ parent->objectId, parent->variantType)); ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: could not get parent object\n")); ++ return -EPERM; ++ } ++ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " ++ "mode %x dev %x\n", ++ dentry->d_name.name, mode, rdev)); ++ ++ dev = parent->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ switch (mode & S_IFMT) { ++ default: ++ /* Special (socket, fifo, device...) */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n")); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, ++ gid, old_encode_dev(rdev)); ++#else ++ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, ++ gid, rdev); ++#endif ++ break; ++ case S_IFREG: /* file */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); ++ obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, ++ gid); ++ break; ++ case S_IFDIR: /* directory */ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod: making directory\n")); ++ obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, ++ uid, gid); ++ break; ++ case S_IFLNK: /* symlink */ ++ T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); ++ obj = NULL; /* Do we ever get here? */ ++ break; ++ } ++ ++ /* Can not call yaffs_get_inode() with gross lock held */ ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); ++ d_instantiate(dentry, inode); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod created object %d count = %d\n", ++ obj->objectId, atomic_read(&inode->i_count))); ++ error = 0; ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_mknod failed making object\n")); ++ error = -ENOMEM; ++ } ++ ++ return error; ++} ++ ++static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ int retVal; ++ T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); ++ retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); ++ return retVal; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *n) ++#else ++static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) ++#endif ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_create\n")); ++ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); ++} ++ ++static int yaffs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int retVal; ++ ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), ++ dentry->d_name.name)); ++ ++ dev = yaffs_InodeToObject(dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); ++ ++ if (retVal == YAFFS_OK) { ++ dentry->d_inode->i_nlink--; ++ dir->i_version++; ++ yaffs_GrossUnlock(dev); ++ mark_inode_dirty(dentry->d_inode); ++ return 0; ++ } ++ yaffs_GrossUnlock(dev); ++ return -ENOTEMPTY; ++} ++ ++/* ++ * Create a link... ++ */ ++static int yaffs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct inode *inode = old_dentry->d_inode; ++ yaffs_Object *obj = NULL; ++ yaffs_Object *link = NULL; ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_link\n")); ++ ++ obj = yaffs_InodeToObject(inode); ++ dev = obj->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ ++ link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, ++ obj); ++ ++ if (link) { ++ old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); ++ d_instantiate(dentry, old_dentry->d_inode); ++ atomic_inc(&old_dentry->d_inode->i_count); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_link link count %d i_count %d\n", ++ old_dentry->d_inode->i_nlink, ++ atomic_read(&old_dentry->d_inode->i_count))); ++ } ++ ++ yaffs_GrossUnlock(dev); ++ ++ if (link) ++ return 0; ++ ++ return -EPERM; ++} ++ ++static int yaffs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ uid_t uid = YCRED(current)->fsuid; ++ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); ++ ++ dev = yaffs_InodeToObject(dir)->myDev; ++ yaffs_GrossLock(dev); ++ obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, ++ S_IFLNK | S_IRWXUGO, uid, gid, symname); ++ yaffs_GrossUnlock(dev); ++ ++ if (obj) { ++ struct inode *inode; ++ ++ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); ++ d_instantiate(dentry, inode); ++ T(YAFFS_TRACE_OS, ("symlink created OK\n")); ++ return 0; ++ } else { ++ T(YAFFS_TRACE_OS, ("symlink not created\n")); ++ } ++ ++ return -ENOMEM; ++} ++ ++static int yaffs_sync_object(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ ++ yaffs_Object *obj; ++ yaffs_Device *dev; ++ ++ obj = yaffs_DentryToObject(dentry); ++ ++ dev = obj->myDev; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); ++ yaffs_GrossLock(dev); ++ yaffs_FlushFile(obj, 1); ++ yaffs_GrossUnlock(dev); ++ return 0; ++} ++ ++/* ++ * The VFS layer already does all the dentry stuff for rename. ++ * ++ * NB: POSIX says you can rename an object over an old object of the same name ++ */ ++static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++{ ++ yaffs_Device *dev; ++ int retVal = YAFFS_FAIL; ++ yaffs_Object *target; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_rename\n")); ++ dev = yaffs_InodeToObject(old_dir)->myDev; ++ ++ yaffs_GrossLock(dev); ++ ++ /* Check if the target is an existing directory that is not empty. */ ++ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), ++ new_dentry->d_name.name); ++ ++ ++ ++ if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !ylist_empty(&target->variant.directoryVariant.children)) { ++ ++ T(YAFFS_TRACE_OS, ("target is non-empty dir\n")); ++ ++ retVal = YAFFS_FAIL; ++ } else { ++ /* Now does unlinking internally using shadowing mechanism */ ++ T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); ++ ++ retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), ++ old_dentry->d_name.name, ++ yaffs_InodeToObject(new_dir), ++ new_dentry->d_name.name); ++ } ++ yaffs_GrossUnlock(dev); ++ ++ if (retVal == YAFFS_OK) { ++ if (target) { ++ new_dentry->d_inode->i_nlink--; ++ mark_inode_dirty(new_dentry->d_inode); ++ } ++ ++ return 0; ++ } else { ++ return -ENOTEMPTY; ++ } ++} ++ ++static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ int error; ++ yaffs_Device *dev; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_setattr of object %d\n", ++ yaffs_InodeToObject(inode)->objectId)); ++ ++ error = inode_change_ok(inode, attr); ++ if (error == 0) { ++ dev = yaffs_InodeToObject(inode)->myDev; ++ yaffs_GrossLock(dev); ++ if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == ++ YAFFS_OK) { ++ error = 0; ++ } else { ++ error = -EPERM; ++ } ++ yaffs_GrossUnlock(dev); ++ if (!error) ++ error = inode_setattr(inode, attr); ++ } ++ return error; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; ++ struct super_block *sb = dentry->d_sb; ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++#else ++static int yaffs_statfs(struct super_block *sb, struct statfs *buf) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++#endif ++ ++ T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); ++ ++ yaffs_GrossLock(dev); ++ ++ buf->f_type = YAFFS_MAGIC; ++ buf->f_bsize = sb->s_blocksize; ++ buf->f_namelen = 255; ++ ++ if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) { ++ /* Do this if chunk size is not a power of 2 */ ++ ++ uint64_t bytesInDev; ++ uint64_t bytesFree; ++ ++ bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) * ++ ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); ++ ++ do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ ++ buf->f_blocks = bytesInDev; ++ ++ bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) * ++ ((uint64_t)(dev->nDataBytesPerChunk)); ++ ++ do_div(bytesFree, sb->s_blocksize); ++ ++ buf->f_bfree = bytesFree; ++ ++ } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { ++ ++ buf->f_blocks = ++ (dev->endBlock - dev->startBlock + 1) * ++ dev->nChunksPerBlock / ++ (sb->s_blocksize / dev->nDataBytesPerChunk); ++ buf->f_bfree = ++ yaffs_GetNumberOfFreeChunks(dev) / ++ (sb->s_blocksize / dev->nDataBytesPerChunk); ++ } else { ++ buf->f_blocks = ++ (dev->endBlock - dev->startBlock + 1) * ++ dev->nChunksPerBlock * ++ (dev->nDataBytesPerChunk / sb->s_blocksize); ++ ++ buf->f_bfree = ++ yaffs_GetNumberOfFreeChunks(dev) * ++ (dev->nDataBytesPerChunk / sb->s_blocksize); ++ } ++ ++ buf->f_files = 0; ++ buf->f_ffree = 0; ++ buf->f_bavail = buf->f_bfree; ++ ++ yaffs_GrossUnlock(dev); ++ return 0; ++} ++ ++ ++static int yaffs_do_sync_fs(struct super_block *sb) ++{ ++ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); ++ ++ if (sb->s_dirt) { ++ yaffs_GrossLock(dev); ++ ++ if (dev) { ++ yaffs_FlushEntireDeviceCache(dev); ++ yaffs_CheckpointSave(dev); ++ } ++ ++ yaffs_GrossUnlock(dev); ++ ++ sb->s_dirt = 0; ++ } ++ return 0; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static void yaffs_write_super(struct super_block *sb) ++#else ++static int yaffs_write_super(struct super_block *sb) ++#endif ++{ ++ ++ T(YAFFS_TRACE_OS, ("yaffs_write_super\n")); ++ if (yaffs_auto_checkpoint >= 2) ++ yaffs_do_sync_fs(sb); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ return 0; ++#endif ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_sync_fs(struct super_block *sb, int wait) ++#else ++static int yaffs_sync_fs(struct super_block *sb) ++#endif ++{ ++ T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); ++ ++ if (yaffs_auto_checkpoint >= 1) ++ yaffs_do_sync_fs(sb); ++ ++ return 0; ++} ++ ++#ifdef YAFFS_USE_OWN_IGET ++ ++static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) ++{ ++ struct inode *inode; ++ yaffs_Object *obj; ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_iget for %lu\n", ino)); ++ ++ inode = iget_locked(sb, ino); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_GrossLock(dev); ++ ++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); ++ ++ yaffs_FillInodeFromObject(inode, obj); ++ ++ yaffs_GrossUnlock(dev); ++ ++ unlock_new_inode(inode); ++ return inode; ++} ++ ++#else ++ ++static void yaffs_read_inode(struct inode *inode) ++{ ++ /* NB This is called as a side effect of other functions, but ++ * we had to release the lock to prevent deadlocks, so ++ * need to lock again. ++ */ ++ ++ yaffs_Object *obj; ++ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_inode for %d\n", (int)inode->i_ino)); ++ ++ yaffs_GrossLock(dev); ++ ++ obj = yaffs_FindObjectByNumber(dev, inode->i_ino); ++ ++ yaffs_FillInodeFromObject(inode, obj); ++ ++ yaffs_GrossUnlock(dev); ++} ++ ++#endif ++ ++static YLIST_HEAD(yaffs_dev_list); ++ ++#if 0 /* not used */ ++static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ if (*flags & MS_RDONLY) { ++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_remount_fs: %s: RO\n", dev->name)); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushEntireDeviceCache(dev); ++ ++ yaffs_CheckpointSave(dev); ++ ++ if (mtd->sync) ++ mtd->sync(mtd); ++ ++ yaffs_GrossUnlock(dev); ++ } else { ++ T(YAFFS_TRACE_OS, ++ ("yaffs_remount_fs: %s: RW\n", dev->name)); ++ } ++ ++ return 0; ++} ++#endif ++ ++static void yaffs_put_super(struct super_block *sb) ++{ ++ yaffs_Device *dev = yaffs_SuperToDevice(sb); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); ++ ++ yaffs_GrossLock(dev); ++ ++ yaffs_FlushEntireDeviceCache(dev); ++ ++ yaffs_CheckpointSave(dev); ++ ++ if (dev->putSuperFunc) ++ dev->putSuperFunc(sb); ++ ++ yaffs_Deinitialise(dev); ++ ++ yaffs_GrossUnlock(dev); ++ ++ /* we assume this is protected by lock_kernel() in mount/umount */ ++ ylist_del(&dev->devList); ++ ++ if (dev->spareBuffer) { ++ YFREE(dev->spareBuffer); ++ dev->spareBuffer = NULL; ++ } ++ ++ kfree(dev); ++} ++ ++ ++static void yaffs_MTDPutSuper(struct super_block *sb) ++{ ++ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; ++ ++ if (mtd->sync) ++ mtd->sync(mtd); ++ ++ put_mtd_device(mtd); ++} ++ ++ ++static void yaffs_MarkSuperBlockDirty(void *vsb) ++{ ++ struct super_block *sb = (struct super_block *)vsb; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); ++ if (sb) ++ sb->s_dirt = 1; ++} ++ ++typedef struct { ++ int inband_tags; ++ int skip_checkpoint_read; ++ int skip_checkpoint_write; ++ int no_cache; ++} yaffs_options; ++ ++#define MAX_OPT_LEN 20 ++static int yaffs_parse_options(yaffs_options *options, const char *options_str) ++{ ++ char cur_opt[MAX_OPT_LEN + 1]; ++ int p; ++ int error = 0; ++ ++ /* Parse through the options which is a comma seperated list */ ++ ++ while (options_str && *options_str && !error) { ++ memset(cur_opt, 0, MAX_OPT_LEN + 1); ++ p = 0; ++ ++ while (*options_str && *options_str != ',') { ++ if (p < MAX_OPT_LEN) { ++ cur_opt[p] = *options_str; ++ p++; ++ } ++ options_str++; ++ } ++ ++ if (!strcmp(cur_opt, "inband-tags")) ++ options->inband_tags = 1; ++ else if (!strcmp(cur_opt, "no-cache")) ++ options->no_cache = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint-read")) ++ options->skip_checkpoint_read = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint-write")) ++ options->skip_checkpoint_write = 1; ++ else if (!strcmp(cur_opt, "no-checkpoint")) { ++ options->skip_checkpoint_read = 1; ++ options->skip_checkpoint_write = 1; ++ } else { ++ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", ++ cur_opt); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++ ++static struct super_block *yaffs_internal_read_super(int yaffsVersion, ++ struct super_block *sb, ++ void *data, int silent) ++{ ++ int nBlocks; ++ struct inode *inode = NULL; ++ struct dentry *root; ++ yaffs_Device *dev = 0; ++ char devname_buf[BDEVNAME_SIZE + 1]; ++ struct mtd_info *mtd; ++ int err; ++ char *data_str = (char *)data; ++ ++ yaffs_options options; ++ ++ sb->s_magic = YAFFS_MAGIC; ++ sb->s_op = &yaffs_super_ops; ++ sb->s_flags |= MS_NOATIME; ++ ++ if (!sb) ++ printk(KERN_INFO "yaffs: sb is NULL\n"); ++ else if (!sb->s_dev) ++ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); ++ else if (!yaffs_devname(sb, devname_buf)) ++ printk(KERN_INFO "yaffs: devname is NULL\n"); ++ else ++ printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", ++ sb->s_dev, ++ yaffs_devname(sb, devname_buf)); ++ ++ if (!data_str) ++ data_str = ""; ++ ++ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); ++ ++ memset(&options, 0, sizeof(options)); ++ ++ if (yaffs_parse_options(&options, data_str)) { ++ /* Option parsing failed */ ++ return NULL; ++ } ++ ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); ++ ++#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY ++ T(YAFFS_TRACE_OS, ++ ("yaffs: Write verification disabled. All guarantees " ++ "null and void\n")); ++#endif ++ ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " ++ "\"%s\"\n", ++ MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ yaffs_devname(sb, devname_buf))); ++ ++ /* Check it's an mtd device..... */ ++ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) ++ return NULL; /* This isn't an mtd device */ ++ ++ /* Get the device */ ++ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); ++ if (!mtd) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device #%u doesn't appear to exist\n", ++ MINOR(sb->s_dev))); ++ return NULL; ++ } ++ /* Check it's NAND */ ++ if (mtd->type != MTD_NANDFLASH) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); ++ return NULL; ++ } ++ ++ T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); ++ T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); ++ T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); ++ T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); ++ T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); ++ T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); ++ T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); ++ T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); ++ T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); ++ T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++ T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); ++#else ++ T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); ++#endif ++ ++#ifdef CONFIG_YAFFS_AUTO_YAFFS2 ++ ++ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); ++ yaffsVersion = 2; ++ } ++ ++ /* Added NCB 26/5/2006 for completeness */ ++ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { ++ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); ++ yaffsVersion = 1; ++ } ++ ++#endif ++ ++ if (yaffsVersion == 2) { ++ /* Check for version 2 style functions */ ++ if (!mtd->erase || ++ !mtd->block_isbad || ++ !mtd->block_markbad || ++ !mtd->read || ++ !mtd->write || ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ !mtd->read_oob || !mtd->write_oob) { ++#else ++ !mtd->write_ecc || ++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { ++#endif ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support required " ++ "functions\n"));; ++ return NULL; ++ } ++ ++ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || ++ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && ++ !options.inband_tags) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not have the " ++ "right page sizes\n")); ++ return NULL; ++ } ++ } else { ++ /* Check for V1 style functions */ ++ if (!mtd->erase || ++ !mtd->read || ++ !mtd->write || ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ !mtd->read_oob || !mtd->write_oob) { ++#else ++ !mtd->write_ecc || ++ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { ++#endif ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support required " ++ "functions\n"));; ++ return NULL; ++ } ++ ++ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || ++ mtd->oobsize != YAFFS_BYTES_PER_SPARE) { ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs: MTD device does not support have the " ++ "right page sizes\n")); ++ return NULL; ++ } ++ } ++ ++ /* OK, so if we got here, we have an MTD that's NAND and looks ++ * like it has the right capabilities ++ * Set the yaffs_Device up for mtd ++ */ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++ sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); ++#else ++ sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); ++#endif ++ if (!dev) { ++ /* Deep shit could not allocate device structure */ ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs_read_super: Failed trying to allocate " ++ "yaffs_Device. \n")); ++ return NULL; ++ } ++ ++ memset(dev, 0, sizeof(yaffs_Device)); ++ dev->genericDevice = mtd; ++ dev->name = mtd->name; ++ ++ /* Set up the memory size parameters.... */ ++ ++ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); ++ ++ dev->startBlock = 0; ++ dev->endBlock = nBlocks - 1; ++ dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; ++ dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; ++ dev->nReservedBlocks = 5; ++ dev->nShortOpCaches = (options.no_cache) ? 0 : 10; ++ dev->inbandTags = options.inband_tags; ++ ++ /* ... and the functions. */ ++ if (yaffsVersion == 2) { ++ dev->writeChunkWithTagsToNAND = ++ nandmtd2_WriteChunkWithTagsToNAND; ++ dev->readChunkWithTagsFromNAND = ++ nandmtd2_ReadChunkWithTagsFromNAND; ++ dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; ++ dev->queryNANDBlock = nandmtd2_QueryNANDBlock; ++ dev->spareBuffer = YMALLOC(mtd->oobsize); ++ dev->isYaffs2 = 1; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ dev->totalBytesPerChunk = mtd->writesize; ++ dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; ++#else ++ dev->totalBytesPerChunk = mtd->oobblock; ++ dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; ++#endif ++ nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); ++ ++ dev->startBlock = 0; ++ dev->endBlock = nBlocks - 1; ++ } else { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ /* use the MTD interface in yaffs_mtdif1.c */ ++ dev->writeChunkWithTagsToNAND = ++ nandmtd1_WriteChunkWithTagsToNAND; ++ dev->readChunkWithTagsFromNAND = ++ nandmtd1_ReadChunkWithTagsFromNAND; ++ dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; ++ dev->queryNANDBlock = nandmtd1_QueryNANDBlock; ++#else ++ dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; ++ dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; ++#endif ++ dev->isYaffs2 = 0; ++ } ++ /* ... and common functions */ ++ dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; ++ dev->initialiseNAND = nandmtd_InitialiseNAND; ++ ++ dev->putSuperFunc = yaffs_MTDPutSuper; ++ ++ dev->superBlock = (void *)sb; ++ dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; ++ ++ ++#ifndef CONFIG_YAFFS_DOES_ECC ++ dev->useNANDECC = 1; ++#endif ++ ++#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES ++ dev->wideTnodesDisabled = 1; ++#endif ++ ++ dev->skipCheckpointRead = options.skip_checkpoint_read; ++ dev->skipCheckpointWrite = options.skip_checkpoint_write; ++ ++ /* we assume this is protected by lock_kernel() in mount/umount */ ++ ylist_add_tail(&dev->devList, &yaffs_dev_list); ++ ++ init_MUTEX(&dev->grossLock); ++ ++ yaffs_GrossLock(dev); ++ ++ err = yaffs_GutsInitialise(dev); ++ ++ T(YAFFS_TRACE_OS, ++ ("yaffs_read_super: guts initialised %s\n", ++ (err == YAFFS_OK) ? "OK" : "FAILED")); ++ ++ /* Release lock before yaffs_get_inode() */ ++ yaffs_GrossUnlock(dev); ++ ++ /* Create root inode */ ++ if (err == YAFFS_OK) ++ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, ++ yaffs_Root(dev)); ++ ++ if (!inode) ++ return NULL; ++ ++ inode->i_op = &yaffs_dir_inode_operations; ++ inode->i_fop = &yaffs_dir_operations; ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); ++ ++ root = d_alloc_root(inode); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); ++ ++ if (!root) { ++ iput(inode); ++ return NULL; ++ } ++ sb->s_root = root; ++ sb->s_dirt = !dev->isCheckpointed; ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); ++ ++ T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); ++ return sb; ++} ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data, struct vfsmount *mnt) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs", ++ .get_sb = yaffs_read_super, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs_read_super(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(1, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, ++ int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++static int yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd, mnt); ++} ++#else ++static struct super_block *yaffs2_read_super(struct file_system_type *fs, ++ int flags, const char *dev_name, ++ void *data) ++{ ++ ++ return get_sb_bdev(fs, flags, dev_name, data, ++ yaffs2_internal_read_super_mtd); ++} ++#endif ++ ++static struct file_system_type yaffs2_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "yaffs2", ++ .get_sb = yaffs2_read_super, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++#else ++static struct super_block *yaffs2_read_super(struct super_block *sb, ++ void *data, int silent) ++{ ++ return yaffs_internal_read_super(2, sb, data, silent); ++} ++ ++static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, ++ FS_REQUIRES_DEV); ++#endif ++ ++#endif /* CONFIG_YAFFS_YAFFS2 */ ++ ++static struct proc_dir_entry *my_proc_entry; ++ ++static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) ++{ ++ buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); ++ buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); ++ buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); ++ buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); ++ buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); ++ buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); ++ buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); ++ buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); ++ buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); ++ buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); ++ buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); ++ buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); ++ buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); ++ buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); ++ buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); ++ buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); ++ buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); ++ buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); ++ buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); ++ buf += sprintf(buf, "passiveGCs......... %d\n", ++ dev->passiveGarbageCollections); ++ buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); ++ buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); ++ buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); ++ buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); ++ buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); ++ buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); ++ buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); ++ buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); ++ buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); ++ buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); ++ buf += ++ sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); ++ buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); ++ buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); ++ buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); ++ ++ return buf; ++} ++ ++static int yaffs_proc_read(char *page, ++ char **start, ++ off_t offset, int count, int *eof, void *data) ++{ ++ struct ylist_head *item; ++ char *buf = page; ++ int step = offset; ++ int n = 0; ++ ++ /* Get proc_file_read() to step 'offset' by one on each sucessive call. ++ * We use 'offset' (*ppos) to indicate where we are in devList. ++ * This also assumes the user has posted a read buffer large ++ * enough to hold the complete output; but that's life in /proc. ++ */ ++ ++ *(int *)start = 1; ++ ++ /* Print header first */ ++ if (step == 0) { ++ buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ ++ "\n%s\n%s\n", yaffs_fs_c_version, ++ yaffs_guts_c_version); ++ } ++ ++ /* hold lock_kernel while traversing yaffs_dev_list */ ++ lock_kernel(); ++ ++ /* Locate and print the Nth entry. Order N-squared but N is small. */ ++ ylist_for_each(item, &yaffs_dev_list) { ++ yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); ++ if (n < step) { ++ n++; ++ continue; ++ } ++ buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); ++ buf = yaffs_dump_dev(buf, dev); ++ break; ++ } ++ unlock_kernel(); ++ ++ return buf - page < count ? buf - page : count; ++} ++ ++/** ++ * Set the verbosity of the warnings and error messages. ++ * ++ * Note that the names can only be a..z or _ with the current code. ++ */ ++ ++static struct { ++ char *mask_name; ++ unsigned mask_bitfield; ++} mask_flags[] = { ++ {"allocate", YAFFS_TRACE_ALLOCATE}, ++ {"always", YAFFS_TRACE_ALWAYS}, ++ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, ++ {"buffers", YAFFS_TRACE_BUFFERS}, ++ {"bug", YAFFS_TRACE_BUG}, ++ {"checkpt", YAFFS_TRACE_CHECKPOINT}, ++ {"deletion", YAFFS_TRACE_DELETION}, ++ {"erase", YAFFS_TRACE_ERASE}, ++ {"error", YAFFS_TRACE_ERROR}, ++ {"gc_detail", YAFFS_TRACE_GC_DETAIL}, ++ {"gc", YAFFS_TRACE_GC}, ++ {"mtd", YAFFS_TRACE_MTD}, ++ {"nandaccess", YAFFS_TRACE_NANDACCESS}, ++ {"os", YAFFS_TRACE_OS}, ++ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, ++ {"scan", YAFFS_TRACE_SCAN}, ++ {"tracing", YAFFS_TRACE_TRACING}, ++ ++ {"verify", YAFFS_TRACE_VERIFY}, ++ {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, ++ {"verify_full", YAFFS_TRACE_VERIFY_FULL}, ++ {"verify_all", YAFFS_TRACE_VERIFY_ALL}, ++ ++ {"write", YAFFS_TRACE_WRITE}, ++ {"all", 0xffffffff}, ++ {"none", 0}, ++ {NULL, 0}, ++}; ++ ++#define MAX_MASK_NAME_LENGTH 40 ++static int yaffs_proc_write(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ unsigned rg = 0, mask_bitfield; ++ char *end; ++ char *mask_name; ++ const char *x; ++ char substring[MAX_MASK_NAME_LENGTH + 1]; ++ int i; ++ int done = 0; ++ int add, len = 0; ++ int pos = 0; ++ ++ rg = yaffs_traceMask; ++ ++ while (!done && (pos < count)) { ++ done = 1; ++ while ((pos < count) && isspace(buf[pos])) ++ pos++; ++ ++ switch (buf[pos]) { ++ case '+': ++ case '-': ++ case '=': ++ add = buf[pos]; ++ pos++; ++ break; ++ ++ default: ++ add = ' '; ++ break; ++ } ++ mask_name = NULL; ++ ++ mask_bitfield = simple_strtoul(buf + pos, &end, 0); ++ ++ if (end > buf + pos) { ++ mask_name = "numeral"; ++ len = end - (buf + pos); ++ pos += len; ++ done = 0; ++ } else { ++ for (x = buf + pos, i = 0; ++ (*x == '_' || (*x >= 'a' && *x <= 'z')) && ++ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) ++ substring[i] = *x; ++ substring[i] = '\0'; ++ ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ if (strcmp(substring, mask_flags[i].mask_name) == 0) { ++ mask_name = mask_flags[i].mask_name; ++ mask_bitfield = mask_flags[i].mask_bitfield; ++ done = 0; ++ break; ++ } ++ } ++ } ++ ++ if (mask_name != NULL) { ++ done = 0; ++ switch (add) { ++ case '-': ++ rg &= ~mask_bitfield; ++ break; ++ case '+': ++ rg |= mask_bitfield; ++ break; ++ case '=': ++ rg = mask_bitfield; ++ break; ++ default: ++ rg |= mask_bitfield; ++ break; ++ } ++ } ++ } ++ ++ yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; ++ ++ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask); ++ ++ if (rg & YAFFS_TRACE_ALWAYS) { ++ for (i = 0; mask_flags[i].mask_name != NULL; i++) { ++ char flag; ++ flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; ++ printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); ++ } ++ } ++ ++ return count; ++} ++ ++/* Stuff to handle installation of file systems */ ++struct file_system_to_install { ++ struct file_system_type *fst; ++ int installed; ++}; ++ ++static struct file_system_to_install fs_to_install[] = { ++ {&yaffs_fs_type, 0}, ++ {&yaffs2_fs_type, 0}, ++ {NULL, 0} ++}; ++ ++static int __init init_yaffs_fs(void) ++{ ++ int error = 0; ++ struct file_system_to_install *fsinst; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); ++ ++ /* Install the proc_fs entry */ ++ my_proc_entry = create_proc_entry("yaffs", ++ S_IRUGO | S_IFREG, ++ YPROC_ROOT); ++ ++ if (my_proc_entry) { ++ my_proc_entry->write_proc = yaffs_proc_write; ++ my_proc_entry->read_proc = yaffs_proc_read; ++ my_proc_entry->data = NULL; ++ } else ++ return -ENOMEM; ++ ++ /* Now add the file system entries */ ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst && !error) { ++ error = register_filesystem(fsinst->fst); ++ if (!error) ++ fsinst->installed = 1; ++ fsinst++; ++ } ++ ++ /* Any errors? uninstall */ ++ if (error) { ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++ } ++ ++ return error; ++} ++ ++static void __exit exit_yaffs_fs(void) ++{ ++ ++ struct file_system_to_install *fsinst; ++ ++ T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ ++ " removing. \n")); ++ ++ remove_proc_entry("yaffs", YPROC_ROOT); ++ ++ fsinst = fs_to_install; ++ ++ while (fsinst->fst) { ++ if (fsinst->installed) { ++ unregister_filesystem(fsinst->fst); ++ fsinst->installed = 0; ++ } ++ fsinst++; ++ } ++} ++ ++module_init(init_yaffs_fs) ++module_exit(exit_yaffs_fs) ++ ++MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); ++MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_getblockinfo.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GETBLOCKINFO_H__ ++#define __YAFFS_GETBLOCKINFO_H__ ++ ++#include "yaffs_guts.h" ++ ++/* Function to manipulate block info */ ++static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), ++ blk)); ++ YBUG(); ++ } ++ return &dev->blockInfo[blk - dev->internalStartBlock]; ++} ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c linux-2.6.30/fs/yaffs2/yaffs_guts.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_guts.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,7552 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_guts_c_version = ++ "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $"; ++ ++#include "yportenv.h" ++ ++#include "yaffsinterface.h" ++#include "yaffs_guts.h" ++#include "yaffs_tagsvalidity.h" ++#include "yaffs_getblockinfo.h" ++ ++#include "yaffs_tagscompat.h" ++#ifndef CONFIG_YAFFS_USE_OWN_SORT ++#include "yaffs_qsort.h" ++#endif ++#include "yaffs_nand.h" ++ ++#include "yaffs_checkptrw.h" ++ ++#include "yaffs_nand.h" ++#include "yaffs_packedtags2.h" ++ ++ ++#define YAFFS_PASSIVE_GC_CHUNKS 2 ++ ++#include "yaffs_ecc.h" ++ ++ ++/* Robustification (if it ever comes about...) */ ++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, ++ int erasedOk); ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_ExtendedTags *tags); ++ ++/* Other local prototypes */ ++static int yaffs_UnlinkObject(yaffs_Object *obj); ++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); ++ ++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); ++ ++static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags, ++ int useReserve); ++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, ++ int chunkInNAND, int inScan); ++ ++static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, ++ yaffs_ObjectType type); ++static void yaffs_AddObjectToDirectory(yaffs_Object *directory, ++ yaffs_Object *obj); ++static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, ++ int force, int isShrink, int shadows); ++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); ++static int yaffs_CheckStructures(void); ++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, ++ int chunkOffset, int *limit); ++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); ++ ++static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); ++ ++ ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND); ++ ++static int yaffs_UnlinkWorker(yaffs_Object *obj); ++ ++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, ++ int chunkInObject); ++ ++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, ++ yaffs_BlockInfo **blockUsedPtr); ++ ++static void yaffs_VerifyFreeChunks(yaffs_Device *dev); ++ ++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); ++ ++static void yaffs_VerifyDirectory(yaffs_Object *directory); ++#ifdef YAFFS_PARANOID ++static int yaffs_CheckFileSanity(yaffs_Object *in); ++#else ++#define yaffs_CheckFileSanity(in) ++#endif ++ ++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); ++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); ++ ++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); ++ ++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags); ++ ++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, ++ unsigned pos); ++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId); ++ ++ ++/* Function to calculate chunk and offset */ ++ ++static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, ++ __u32 *offsetOut) ++{ ++ int chunk; ++ __u32 offset; ++ ++ chunk = (__u32)(addr >> dev->chunkShift); ++ ++ if (dev->chunkDiv == 1) { ++ /* easy power of 2 case */ ++ offset = (__u32)(addr & dev->chunkMask); ++ } else { ++ /* Non power-of-2 case */ ++ ++ loff_t chunkBase; ++ ++ chunk /= dev->chunkDiv; ++ ++ chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; ++ offset = (__u32)(addr - chunkBase); ++ } ++ ++ *chunkOut = chunk; ++ *offsetOut = offset; ++} ++ ++/* Function to return the number of shifts for a power of 2 greater than or ++ * equal to the given number ++ * Note we don't try to cater for all possible numbers and this does not have to ++ * be hellishly efficient. ++ */ ++ ++static __u32 ShiftsGE(__u32 x) ++{ ++ int extraBits; ++ int nShifts; ++ ++ nShifts = extraBits = 0; ++ ++ while (x > 1) { ++ if (x & 1) ++ extraBits++; ++ x >>= 1; ++ nShifts++; ++ } ++ ++ if (extraBits) ++ nShifts++; ++ ++ return nShifts; ++} ++ ++/* Function to return the number of shifts to get a 1 in bit 0 ++ */ ++ ++static __u32 Shifts(__u32 x) ++{ ++ int nShifts; ++ ++ nShifts = 0; ++ ++ if (!x) ++ return 0; ++ ++ while (!(x&1)) { ++ x >>= 1; ++ nShifts++; ++ } ++ ++ return nShifts; ++} ++ ++ ++ ++/* ++ * Temporary buffer manipulations. ++ */ ++ ++static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) ++{ ++ int i; ++ __u8 *buf = (__u8 *)1; ++ ++ memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer)); ++ ++ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { ++ dev->tempBuffer[i].line = 0; /* not in use */ ++ dev->tempBuffer[i].buffer = buf = ++ YMALLOC_DMA(dev->totalBytesPerChunk); ++ } ++ ++ return buf ? YAFFS_OK : YAFFS_FAIL; ++} ++ ++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo) ++{ ++ int i, j; ++ ++ dev->tempInUse++; ++ if (dev->tempInUse > dev->maxTemp) ++ dev->maxTemp = dev->tempInUse; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].line == 0) { ++ dev->tempBuffer[i].line = lineNo; ++ if ((i + 1) > dev->maxTemp) { ++ dev->maxTemp = i + 1; ++ for (j = 0; j <= i; j++) ++ dev->tempBuffer[j].maxLine = ++ dev->tempBuffer[j].line; ++ } ++ ++ return dev->tempBuffer[i].buffer; ++ } ++ } ++ ++ T(YAFFS_TRACE_BUFFERS, ++ (TSTR("Out of temp buffers at line %d, other held by lines:"), ++ lineNo)); ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) ++ T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); ++ ++ T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); ++ ++ /* ++ * If we got here then we have to allocate an unmanaged one ++ * This is not good. ++ */ ++ ++ dev->unmanagedTempAllocations++; ++ return YMALLOC(dev->nDataBytesPerChunk); ++ ++} ++ ++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, ++ int lineNo) ++{ ++ int i; ++ ++ dev->tempInUse--; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].buffer == buffer) { ++ dev->tempBuffer[i].line = 0; ++ return; ++ } ++ } ++ ++ if (buffer) { ++ /* assume it is an unmanaged one. */ ++ T(YAFFS_TRACE_BUFFERS, ++ (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), ++ lineNo)); ++ YFREE(buffer); ++ dev->unmanagedTempDeallocations++; ++ } ++ ++} ++ ++/* ++ * Determine if we have a managed buffer. ++ */ ++int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) ++{ ++ int i; ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { ++ if (dev->tempBuffer[i].buffer == buffer) ++ return 1; ++ } ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].data == buffer) ++ return 1; ++ } ++ ++ if (buffer == dev->checkpointBuffer) ++ return 1; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); ++ return 0; ++} ++ ++ ++ ++/* ++ * Chunk bitmap manipulations ++ */ ++ ++static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), ++ blk)); ++ YBUG(); ++ } ++ return dev->chunkBits + ++ (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); ++} ++ ++static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) ++{ ++ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || ++ chunk < 0 || chunk >= dev->nChunksPerBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), ++ blk, chunk)); ++ YBUG(); ++ } ++} ++ ++static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ memset(blkBits, 0, dev->chunkBitmapStride); ++} ++ ++static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ blkBits[chunk / 8] &= ~(1 << (chunk & 7)); ++} ++ ++static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ blkBits[chunk / 8] |= (1 << (chunk & 7)); ++} ++ ++static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ yaffs_VerifyChunkBitId(dev, blk, chunk); ++ ++ return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; ++} ++ ++static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ int i; ++ for (i = 0; i < dev->chunkBitmapStride; i++) { ++ if (*blkBits) ++ return 1; ++ blkBits++; ++ } ++ return 0; ++} ++ ++static int yaffs_CountChunkBits(yaffs_Device *dev, int blk) ++{ ++ __u8 *blkBits = yaffs_BlockBits(dev, blk); ++ int i; ++ int n = 0; ++ for (i = 0; i < dev->chunkBitmapStride; i++) { ++ __u8 x = *blkBits; ++ while (x) { ++ if (x & 1) ++ n++; ++ x >>= 1; ++ } ++ ++ blkBits++; ++ } ++ return n; ++} ++ ++/* ++ * Verification code ++ */ ++ ++static int yaffs_SkipVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_SkipFullVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); ++} ++ ++static int yaffs_SkipNANDVerification(yaffs_Device *dev) ++{ ++ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); ++} ++ ++static const char *blockStateName[] = { ++"Unknown", ++"Needs scanning", ++"Scanning", ++"Empty", ++"Allocating", ++"Full", ++"Dirty", ++"Checkpoint", ++"Collecting", ++"Dead" ++}; ++ ++static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) ++{ ++ int actuallyUsed; ++ int inUse; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Report illegal runtime states */ ++ if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); ++ ++ switch (bi->blockState) { ++ case YAFFS_BLOCK_STATE_UNKNOWN: ++ case YAFFS_BLOCK_STATE_SCANNING: ++ case YAFFS_BLOCK_STATE_NEEDS_SCANNING: ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), ++ n, blockStateName[bi->blockState])); ++ } ++ ++ /* Check pages in use and soft deletions are legal */ ++ ++ actuallyUsed = bi->pagesInUse - bi->softDeletions; ++ ++ if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || ++ bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || ++ actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), ++ n, bi->pagesInUse, bi->softDeletions)); ++ ++ ++ /* Check chunk bitmap legal */ ++ inUse = yaffs_CountChunkBits(dev, n); ++ if (inUse != bi->pagesInUse) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), ++ n, bi->pagesInUse, inUse)); ++ ++ /* Check that the sequence number is valid. ++ * Ten million is legal, but is very unlikely ++ */ ++ if (dev->isYaffs2 && ++ (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && ++ (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000)) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR), ++ n, bi->sequenceNumber)); ++} ++ ++static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, ++ int n) ++{ ++ yaffs_VerifyBlock(dev, bi, n); ++ ++ /* After collection the block should be in the erased state */ ++ /* This will need to change if we do partial gc */ ++ ++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && ++ bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), ++ n, bi->blockState)); ++ } ++} ++ ++static void yaffs_VerifyBlocks(yaffs_Device *dev) ++{ ++ int i; ++ int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; ++ int nIllegalBlockStates = 0; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); ++ yaffs_VerifyBlock(dev, bi, i); ++ ++ if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) ++ nBlocksPerState[bi->blockState]++; ++ else ++ nIllegalBlockStates++; ++ } ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); ++ T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); ++ if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) ++ T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); ++ ++ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("%s %d blocks"TENDSTR), ++ blockStateName[i], nBlocksPerState[i])); ++ ++ if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), ++ dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); ++ ++ if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Erased block count wrong dev %d count %d"TENDSTR), ++ dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); ++ ++ if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), ++ nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); ++ ++ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); ++ ++} ++ ++/* ++ * Verify the object header. oh must be valid, but obj and tags may be NULL in which ++ * case those tests will not be performed. ++ */ ++static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ if (!(tags && obj && oh)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), ++ (__u32)tags, (__u32)obj, (__u32)oh)); ++ return; ++ } ++ ++ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || ++ oh->type > YAFFS_OBJECT_TYPE_MAX) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), ++ tags->objectId, oh->type)); ++ ++ if (tags->objectId != obj->objectId) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch objectId %d"TENDSTR), ++ tags->objectId, obj->objectId)); ++ ++ ++ /* ++ * Check that the object's parent ids match if parentCheck requested. ++ * ++ * Tests do not apply to the root object. ++ */ ++ ++ if (parentCheck && tags->objectId > 1 && !obj->parent) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), ++ tags->objectId, oh->parentObjectId)); ++ ++ if (parentCheck && obj->parent && ++ oh->parentObjectId != obj->parent->objectId && ++ (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || ++ obj->parent->objectId != YAFFS_OBJECTID_DELETED)) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), ++ tags->objectId, oh->parentObjectId, obj->parent->objectId)); ++ ++ if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */ ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header name is NULL"TENDSTR), ++ obj->objectId)); ++ ++ if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d header name is 0xFF"TENDSTR), ++ obj->objectId)); ++} ++ ++ ++ ++static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ yaffs_Device *dev = obj->myDev; ++ int ok = 1; ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (tn->internal[i]) { ++ ok = yaffs_VerifyTnodeWorker(obj, ++ tn->internal[i], ++ level - 1, ++ (chunkOffset<objectId; ++ ++ chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; ++ ++ for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { ++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ ++ if (theChunk > 0) { ++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); ++ if (tags.objectId != objectId || tags.chunkId != chunkOffset) { ++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), ++ objectId, chunkOffset, theChunk, ++ tags.objectId, tags.chunkId)); ++ } ++ } ++ chunkOffset++; ++ } ++ } ++ } ++ ++ return ok; ++ ++} ++ ++ ++static void yaffs_VerifyFile(yaffs_Object *obj) ++{ ++ int requiredTallness; ++ int actualTallness; ++ __u32 lastChunk; ++ __u32 x; ++ __u32 i; ++ yaffs_Device *dev; ++ yaffs_ExtendedTags tags; ++ yaffs_Tnode *tn; ++ __u32 objectId; ++ ++ if (!obj) ++ return; ++ ++ if (yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ dev = obj->myDev; ++ objectId = obj->objectId; ++ ++ /* Check file size is consistent with tnode depth */ ++ lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; ++ x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (x > 0) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ actualTallness = obj->variant.fileVariant.topLevel; ++ ++ if (requiredTallness > actualTallness) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), ++ obj->objectId, actualTallness, requiredTallness)); ++ ++ ++ /* Check that the chunks in the tnode tree are all correct. ++ * We do this by scanning through the tnode tree and ++ * checking the tags for every chunk match. ++ */ ++ ++ if (yaffs_SkipNANDVerification(dev)) ++ return; ++ ++ for (i = 1; i <= lastChunk; i++) { ++ tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i); ++ ++ if (tn) { ++ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk > 0) { ++ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); ++ if (tags.objectId != objectId || tags.chunkId != i) { ++ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), ++ objectId, i, theChunk, ++ tags.objectId, tags.chunkId)); ++ } ++ } ++ } ++ } ++} ++ ++ ++static void yaffs_VerifyHardLink(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ /* Verify sane equivalent object */ ++} ++ ++static void yaffs_VerifySymlink(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ /* Verify symlink string */ ++} ++ ++static void yaffs_VerifySpecial(yaffs_Object *obj) ++{ ++ if (obj && yaffs_SkipVerification(obj->myDev)) ++ return; ++} ++ ++static void yaffs_VerifyObject(yaffs_Object *obj) ++{ ++ yaffs_Device *dev; ++ ++ __u32 chunkMin; ++ __u32 chunkMax; ++ ++ __u32 chunkIdOk; ++ __u32 chunkInRange; ++ __u32 chunkShouldNotBeDeleted; ++ __u32 chunkValid; ++ ++ if (!obj) ++ return; ++ ++ if (obj->beingCreated) ++ return; ++ ++ dev = obj->myDev; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Check sane object header chunk */ ++ ++ chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; ++ chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; ++ ++ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); ++ chunkIdOk = chunkInRange || obj->hdrChunk == 0; ++ chunkValid = chunkInRange && ++ yaffs_CheckChunkBit(dev, ++ obj->hdrChunk / dev->nChunksPerBlock, ++ obj->hdrChunk % dev->nChunksPerBlock); ++ chunkShouldNotBeDeleted = chunkInRange && !chunkValid; ++ ++ if (!obj->fake && ++ (!chunkIdOk || chunkShouldNotBeDeleted)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), ++ obj->objectId, obj->hdrChunk, ++ chunkIdOk ? "" : ",out of range", ++ chunkShouldNotBeDeleted ? ",marked as deleted" : "")); ++ } ++ ++ if (chunkValid && !yaffs_SkipNANDVerification(dev)) { ++ yaffs_ExtendedTags tags; ++ yaffs_ObjectHeader *oh; ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ oh = (yaffs_ObjectHeader *)buffer; ++ ++ yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer, ++ &tags); ++ ++ yaffs_VerifyObjectHeader(obj, oh, &tags, 1); ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ } ++ ++ /* Verify it has a parent */ ++ if (obj && !obj->fake && ++ (!obj->parent || obj->parent->myDev != dev)) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), ++ obj->objectId, obj->parent)); ++ } ++ ++ /* Verify parent is a directory */ ++ if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), ++ obj->objectId, obj->parent->variantType)); ++ } ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ yaffs_VerifyFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_VerifySymlink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ yaffs_VerifyDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ yaffs_VerifyHardLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ yaffs_VerifySpecial(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Obj %d has illegaltype %d"TENDSTR), ++ obj->objectId, obj->variantType)); ++ break; ++ } ++} ++ ++static void yaffs_VerifyObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ int i; ++ struct ylist_head *lh; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ ylist_for_each(lh, &dev->objectBucket[i].list) { ++ if (lh) { ++ obj = ylist_entry(lh, yaffs_Object, hashLink); ++ yaffs_VerifyObject(obj); ++ } ++ } ++ } ++} ++ ++ ++/* ++ * Simple hash function. Needs to have a reasonable spread ++ */ ++ ++static Y_INLINE int yaffs_HashFunction(int n) ++{ ++ n = abs(n); ++ return n % YAFFS_NOBJECT_BUCKETS; ++} ++ ++/* ++ * Access functions to useful fake objects. ++ * Note that root might have a presence in NAND if permissions are set. ++ */ ++ ++yaffs_Object *yaffs_Root(yaffs_Device *dev) ++{ ++ return dev->rootDir; ++} ++ ++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev) ++{ ++ return dev->lostNFoundDir; ++} ++ ++ ++/* ++ * Erased NAND checking functions ++ */ ++ ++int yaffs_CheckFF(__u8 *buffer, int nBytes) ++{ ++ /* Horrible, slow implementation */ ++ while (nBytes--) { ++ if (*buffer != 0xFF) ++ return 0; ++ buffer++; ++ } ++ return 1; ++} ++ ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND) ++{ ++ int retval = YAFFS_OK; ++ __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); ++ yaffs_ExtendedTags tags; ++ int result; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); ++ ++ if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) ++ retval = YAFFS_FAIL; ++ ++ if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { ++ T(YAFFS_TRACE_NANDACCESS, ++ (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); ++ retval = YAFFS_FAIL; ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, data, __LINE__); ++ ++ return retval; ++ ++} ++ ++static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, ++ const __u8 *data, ++ yaffs_ExtendedTags *tags, ++ int useReserve) ++{ ++ int attempts = 0; ++ int writeOk = 0; ++ int chunk; ++ ++ yaffs_InvalidateCheckpoint(dev); ++ ++ do { ++ yaffs_BlockInfo *bi = 0; ++ int erasedOk = 0; ++ ++ chunk = yaffs_AllocateChunk(dev, useReserve, &bi); ++ if (chunk < 0) { ++ /* no space */ ++ break; ++ } ++ ++ /* First check this chunk is erased, if it needs ++ * checking. The checking policy (unless forced ++ * always on) is as follows: ++ * ++ * Check the first page we try to write in a block. ++ * If the check passes then we don't need to check any ++ * more. If the check fails, we check again... ++ * If the block has been erased, we don't need to check. ++ * ++ * However, if the block has been prioritised for gc, ++ * then we think there might be something odd about ++ * this block and stop using it. ++ * ++ * Rationale: We should only ever see chunks that have ++ * not been erased if there was a partially written ++ * chunk due to power loss. This checking policy should ++ * catch that case with very few checks and thus save a ++ * lot of checks that are most likely not needed. ++ */ ++ if (bi->gcPrioritise) { ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ /* try another chunk */ ++ continue; ++ } ++ ++ /* let's give it a try */ ++ attempts++; ++ ++#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED ++ bi->skipErasedCheck = 0; ++#endif ++ if (!bi->skipErasedCheck) { ++ erasedOk = yaffs_CheckChunkErased(dev, chunk); ++ if (erasedOk != YAFFS_OK) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs chunk %d was not erased" ++ TENDSTR), chunk)); ++ ++ /* try another chunk */ ++ continue; ++ } ++ bi->skipErasedCheck = 1; ++ } ++ ++ writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, ++ data, tags); ++ if (writeOk != YAFFS_OK) { ++ yaffs_HandleWriteChunkError(dev, chunk, erasedOk); ++ /* try another chunk */ ++ continue; ++ } ++ ++ /* Copy the data into the robustification buffer */ ++ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); ++ ++ } while (writeOk != YAFFS_OK && ++ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); ++ ++ if (!writeOk) ++ chunk = -1; ++ ++ if (attempts > 1) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs write required %d attempts" TENDSTR), ++ attempts)); ++ ++ dev->nRetriedWrites += (attempts - 1); ++ } ++ ++ return chunk; ++} ++ ++/* ++ * Block retiring for handling a broken block. ++ */ ++ ++static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) ++{ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); ++ ++ yaffs_InvalidateCheckpoint(dev); ++ ++ if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { ++ if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR( ++ "yaffs: Failed to mark bad and erase block %d" ++ TENDSTR), blockInNAND)); ++ } else { ++ yaffs_ExtendedTags tags; ++ int chunkId = blockInNAND * dev->nChunksPerBlock; ++ ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ memset(buffer, 0xff, dev->nDataBytesPerChunk); ++ yaffs_InitialiseTags(&tags); ++ tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; ++ if (dev->writeChunkWithTagsToNAND(dev, chunkId - ++ dev->chunkOffset, buffer, &tags) != YAFFS_OK) ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " ++ TCONT("write bad block marker to block %d") ++ TENDSTR), blockInNAND)); ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ } ++ } ++ ++ bi->blockState = YAFFS_BLOCK_STATE_DEAD; ++ bi->gcPrioritise = 0; ++ bi->needsRetiring = 0; ++ ++ dev->nRetiredBlocks++; ++} ++ ++/* ++ * Functions for robustisizing TODO ++ * ++ */ ++ ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags) ++{ ++} ++ ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_ExtendedTags *tags) ++{ ++} ++ ++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) ++{ ++ if (!bi->gcPrioritise) { ++ bi->gcPrioritise = 1; ++ dev->hasPendingPrioritisedGCs = 1; ++ bi->chunkErrorStrikes++; ++ ++ if (bi->chunkErrorStrikes > 3) { ++ bi->needsRetiring = 1; /* Too many stikes, so retire this */ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); ++ ++ } ++ } ++} ++ ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, ++ int erasedOk) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); ++ ++ yaffs_HandleChunkError(dev, bi); ++ ++ if (erasedOk) { ++ /* Was an actual write failure, so mark the block for retirement */ ++ bi->needsRetiring = 1; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); ++ } ++ ++ /* Delete the chunk */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++} ++ ++ ++/*---------------- Name handling functions ------------*/ ++ ++static __u16 yaffs_CalcNameSum(const YCHAR *name) ++{ ++ __u16 sum = 0; ++ __u16 i = 1; ++ ++ const YUCHAR *bname = (const YUCHAR *) name; ++ if (bname) { ++ while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ sum += yaffs_toupper(*bname) * i; ++#else ++ sum += (*bname) * i; ++#endif ++ i++; ++ bname++; ++ } ++ } ++ return sum; ++} ++ ++static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) ++{ ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); ++ if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) ++ yaffs_strcpy(obj->shortName, name); ++ else ++ obj->shortName[0] = _Y('\0'); ++#endif ++ obj->sum = yaffs_CalcNameSum(name); ++} ++ ++/*-------------------- TNODES ------------------- ++ ++ * List of spare tnodes ++ * The list is hooked together using the first pointer ++ * in the tnode. ++ */ ++ ++/* yaffs_CreateTnodes creates a bunch more tnodes and ++ * adds them to the tnode free list. ++ * Don't use this function directly ++ */ ++ ++static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) ++{ ++ int i; ++ int tnodeSize; ++ yaffs_Tnode *newTnodes; ++ __u8 *mem; ++ yaffs_Tnode *curr; ++ yaffs_Tnode *next; ++ yaffs_TnodeList *tnl; ++ ++ if (nTnodes < 1) ++ return YAFFS_OK; ++ ++ /* Calculate the tnode size in bytes for variable width tnode support. ++ * Must be a multiple of 32-bits */ ++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ /* make these things */ ++ ++ newTnodes = YMALLOC(nTnodes * tnodeSize); ++ mem = (__u8 *)newTnodes; ++ ++ if (!newTnodes) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++#if 0 ++ for (i = 0; i < nTnodes - 1; i++) { ++ newTnodes[i].internal[0] = &newTnodes[i + 1]; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ } ++ ++ newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ dev->freeTnodes = newTnodes; ++#else ++ /* New hookup for wide tnodes */ ++ for (i = 0; i < nTnodes - 1; i++) { ++ curr = (yaffs_Tnode *) &mem[i * tnodeSize]; ++ next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; ++ curr->internal[0] = next; ++ } ++ ++ curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; ++ curr->internal[0] = dev->freeTnodes; ++ dev->freeTnodes = (yaffs_Tnode *)mem; ++ ++#endif ++ ++ ++ dev->nFreeTnodes += nTnodes; ++ dev->nTnodesCreated += nTnodes; ++ ++ /* Now add this bunch of tnodes to a list for freeing up. ++ * NB If we can't add this to the management list it isn't fatal ++ * but it just means we can't free this bunch of tnodes later. ++ */ ++ ++ tnl = YMALLOC(sizeof(yaffs_TnodeList)); ++ if (!tnl) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs: Could not add tnodes to management list" TENDSTR))); ++ return YAFFS_FAIL; ++ } else { ++ tnl->tnodes = newTnodes; ++ tnl->next = dev->allocatedTnodeList; ++ dev->allocatedTnodeList = tnl; ++ } ++ ++ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); ++ ++ return YAFFS_OK; ++} ++ ++/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ ++ ++static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev) ++{ ++ yaffs_Tnode *tn = NULL; ++ ++ /* If there are none left make more */ ++ if (!dev->freeTnodes) ++ yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); ++ ++ if (dev->freeTnodes) { ++ tn = dev->freeTnodes; ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { ++ /* Hoosterman, this thing looks like it isn't in the list */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: Tnode list bug 1" TENDSTR))); ++ } ++#endif ++ dev->freeTnodes = dev->freeTnodes->internal[0]; ++ dev->nFreeTnodes--; ++ } ++ ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++ ++ return tn; ++} ++ ++static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) ++{ ++ yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ if (tn) ++ memset(tn, 0, tnodeSize); ++ ++ return tn; ++} ++ ++/* FreeTnode frees up a tnode and puts it back on the free list */ ++static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn) ++{ ++ if (tn) { ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { ++ /* Hoosterman, this thing looks like it is already in the list */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: Tnode list bug 2" TENDSTR))); ++ } ++ tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; ++#endif ++ tn->internal[0] = dev->freeTnodes; ++ dev->freeTnodes = tn; ++ dev->nFreeTnodes++; ++ } ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++} ++ ++static void yaffs_DeinitialiseTnodes(yaffs_Device *dev) ++{ ++ /* Free the list of allocated tnodes */ ++ yaffs_TnodeList *tmp; ++ ++ while (dev->allocatedTnodeList) { ++ tmp = dev->allocatedTnodeList->next; ++ ++ YFREE(dev->allocatedTnodeList->tnodes); ++ YFREE(dev->allocatedTnodeList); ++ dev->allocatedTnodeList = tmp; ++ ++ } ++ ++ dev->freeTnodes = NULL; ++ dev->nFreeTnodes = 0; ++} ++ ++static void yaffs_InitialiseTnodes(yaffs_Device *dev) ++{ ++ dev->allocatedTnodeList = NULL; ++ dev->freeTnodes = NULL; ++ dev->nFreeTnodes = 0; ++ dev->nTnodesCreated = 0; ++} ++ ++ ++void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, ++ unsigned val) ++{ ++ __u32 *map = (__u32 *)tn; ++ __u32 bitInMap; ++ __u32 bitInWord; ++ __u32 wordInMap; ++ __u32 mask; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ val >>= dev->chunkGroupBits; ++ ++ bitInMap = pos * dev->tnodeWidth; ++ wordInMap = bitInMap / 32; ++ bitInWord = bitInMap & (32 - 1); ++ ++ mask = dev->tnodeMask << bitInWord; ++ ++ map[wordInMap] &= ~mask; ++ map[wordInMap] |= (mask & (val << bitInWord)); ++ ++ if (dev->tnodeWidth > (32 - bitInWord)) { ++ bitInWord = (32 - bitInWord); ++ wordInMap++;; ++ mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); ++ map[wordInMap] &= ~mask; ++ map[wordInMap] |= (mask & (val >> bitInWord)); ++ } ++} ++ ++static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, ++ unsigned pos) ++{ ++ __u32 *map = (__u32 *)tn; ++ __u32 bitInMap; ++ __u32 bitInWord; ++ __u32 wordInMap; ++ __u32 val; ++ ++ pos &= YAFFS_TNODES_LEVEL0_MASK; ++ ++ bitInMap = pos * dev->tnodeWidth; ++ wordInMap = bitInMap / 32; ++ bitInWord = bitInMap & (32 - 1); ++ ++ val = map[wordInMap] >> bitInWord; ++ ++ if (dev->tnodeWidth > (32 - bitInWord)) { ++ bitInWord = (32 - bitInWord); ++ wordInMap++;; ++ val |= (map[wordInMap] << bitInWord); ++ } ++ ++ val &= dev->tnodeMask; ++ val <<= dev->chunkGroupBits; ++ ++ return val; ++} ++ ++/* ------------------- End of individual tnode manipulation -----------------*/ ++ ++/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ ++ * The look up tree is represented by the top tnode and the number of topLevel ++ * in the tree. 0 means only the level 0 tnode is in the tree. ++ */ ++ ++/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ ++static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId) ++{ ++ yaffs_Tnode *tn = fStruct->top; ++ __u32 i; ++ int requiredTallness; ++ int level = fStruct->topLevel; ++ ++ /* Check sane level and chunk Id */ ++ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunkId > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough topLevel) */ ++ ++ i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (i) { ++ i >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ if (requiredTallness > fStruct->topLevel) ++ return NULL; /* Not tall enough, so we can't find it */ ++ ++ /* Traverse down to level 0 */ ++ while (level > 0 && tn) { ++ tn = tn->internal[(chunkId >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (level - 1) * ++ YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK]; ++ level--; ++ } ++ ++ return tn; ++} ++ ++/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. ++ * This happens in two steps: ++ * 1. If the tree isn't tall enough, then make it taller. ++ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. ++ * ++ * Used when modifying the tree. ++ * ++ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will ++ * be plugged into the ttree. ++ */ ++ ++static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct, ++ __u32 chunkId, ++ yaffs_Tnode *passedTn) ++{ ++ int requiredTallness; ++ int i; ++ int l; ++ yaffs_Tnode *tn; ++ ++ __u32 x; ++ ++ ++ /* Check sane level and page Id */ ++ if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) ++ return NULL; ++ ++ if (chunkId > YAFFS_MAX_CHUNK_ID) ++ return NULL; ++ ++ /* First check we're tall enough (ie enough topLevel) */ ++ ++ x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; ++ requiredTallness = 0; ++ while (x) { ++ x >>= YAFFS_TNODES_INTERNAL_BITS; ++ requiredTallness++; ++ } ++ ++ ++ if (requiredTallness > fStruct->topLevel) { ++ /* Not tall enough, gotta make the tree taller */ ++ for (i = fStruct->topLevel; i < requiredTallness; i++) { ++ ++ tn = yaffs_GetTnode(dev); ++ ++ if (tn) { ++ tn->internal[0] = fStruct->top; ++ fStruct->top = tn; ++ } else { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs: no more tnodes" TENDSTR))); ++ } ++ } ++ ++ fStruct->topLevel = requiredTallness; ++ } ++ ++ /* Traverse down to level 0, adding anything we need */ ++ ++ l = fStruct->topLevel; ++ tn = fStruct->top; ++ ++ if (l > 0) { ++ while (l > 0 && tn) { ++ x = (chunkId >> ++ (YAFFS_TNODES_LEVEL0_BITS + ++ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & ++ YAFFS_TNODES_INTERNAL_MASK; ++ ++ ++ if ((l > 1) && !tn->internal[x]) { ++ /* Add missing non-level-zero tnode */ ++ tn->internal[x] = yaffs_GetTnode(dev); ++ ++ } else if (l == 1) { ++ /* Looking from level 1 at level 0 */ ++ if (passedTn) { ++ /* If we already have one, then release it.*/ ++ if (tn->internal[x]) ++ yaffs_FreeTnode(dev, tn->internal[x]); ++ tn->internal[x] = passedTn; ++ ++ } else if (!tn->internal[x]) { ++ /* Don't have one, none passed in */ ++ tn->internal[x] = yaffs_GetTnode(dev); ++ } ++ } ++ ++ tn = tn->internal[x]; ++ l--; ++ } ++ } else { ++ /* top is level 0 */ ++ if (passedTn) { ++ memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); ++ yaffs_FreeTnode(dev, passedTn); ++ } ++ } ++ ++ return tn; ++} ++ ++static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, ++ yaffs_ExtendedTags *tags, int objectId, ++ int chunkInInode) ++{ ++ int j; ++ ++ for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { ++ if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock, ++ theChunk % dev->nChunksPerBlock)) { ++ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, ++ tags); ++ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { ++ /* found it; */ ++ return theChunk; ++ } ++ } ++ theChunk++; ++ } ++ return -1; ++} ++ ++ ++/* DeleteWorker scans backwards through the tnode tree and deletes all the ++ * chunks and tnodes in the file ++ * Returns 1 if the tree was deleted. ++ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. ++ */ ++ ++static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, ++ int chunkOffset, int *limit) ++{ ++ int i; ++ int chunkInInode; ++ int theChunk; ++ yaffs_ExtendedTags tags; ++ int foundChunk; ++ yaffs_Device *dev = in->myDev; ++ ++ int allDone = 1; ++ ++ if (tn) { ++ if (level > 0) { ++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ if (limit && (*limit) < 0) { ++ allDone = 0; ++ } else { ++ allDone = ++ yaffs_DeleteWorker(in, ++ tn-> ++ internal ++ [i], ++ level - ++ 1, ++ (chunkOffset ++ << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i, ++ limit); ++ } ++ if (allDone) { ++ yaffs_FreeTnode(dev, ++ tn-> ++ internal[i]); ++ tn->internal[i] = NULL; ++ } ++ } ++ } ++ return (allDone) ? 1 : 0; ++ } else if (level == 0) { ++ int hitLimit = 0; ++ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; ++ i--) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk) { ++ ++ chunkInInode = (chunkOffset << ++ YAFFS_TNODES_LEVEL0_BITS) + i; ++ ++ foundChunk = ++ yaffs_FindChunkInGroup(dev, ++ theChunk, ++ &tags, ++ in->objectId, ++ chunkInInode); ++ ++ if (foundChunk > 0) { ++ yaffs_DeleteChunk(dev, ++ foundChunk, 1, ++ __LINE__); ++ in->nDataChunks--; ++ if (limit) { ++ *limit = *limit - 1; ++ if (*limit <= 0) ++ hitLimit = 1; ++ } ++ ++ } ++ ++ yaffs_PutLevel0Tnode(dev, tn, i, 0); ++ } ++ ++ } ++ return (i < 0) ? 1 : 0; ++ ++ } ++ ++ } ++ ++ return 1; ++ ++} ++ ++static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) ++{ ++ yaffs_BlockInfo *theBlock; ++ ++ T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); ++ ++ theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); ++ if (theBlock) { ++ theBlock->softDeletions++; ++ dev->nFreeChunks++; ++ } ++} ++ ++/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. ++ * All soft deleting does is increment the block's softdelete count and pulls the chunk out ++ * of the tnode. ++ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. ++ */ ++ ++static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ int theChunk; ++ int allDone = 1; ++ yaffs_Device *dev = in->myDev; ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; ++ i--) { ++ if (tn->internal[i]) { ++ allDone = ++ yaffs_SoftDeleteWorker(in, ++ tn-> ++ internal[i], ++ level - 1, ++ (chunkOffset ++ << ++ YAFFS_TNODES_INTERNAL_BITS) ++ + i); ++ if (allDone) { ++ yaffs_FreeTnode(dev, ++ tn-> ++ internal[i]); ++ tn->internal[i] = NULL; ++ } else { ++ /* Hoosterman... how could this happen? */ ++ } ++ } ++ } ++ return (allDone) ? 1 : 0; ++ } else if (level == 0) { ++ ++ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, i); ++ if (theChunk) { ++ /* Note this does not find the real chunk, only the chunk group. ++ * We make an assumption that a chunk group is not larger than ++ * a block. ++ */ ++ yaffs_SoftDeleteChunk(dev, theChunk); ++ yaffs_PutLevel0Tnode(dev, tn, i, 0); ++ } ++ ++ } ++ return 1; ++ ++ } ++ ++ } ++ ++ return 1; ++ ++} ++ ++static void yaffs_SoftDeleteFile(yaffs_Object *obj) ++{ ++ if (obj->deleted && ++ obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { ++ if (obj->nDataChunks <= 0) { ++ /* Empty file with no duplicate object headers, just delete it immediately */ ++ yaffs_FreeTnode(obj->myDev, ++ obj->variant.fileVariant.top); ++ obj->variant.fileVariant.top = NULL; ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: Deleting empty file %d" TENDSTR), ++ obj->objectId)); ++ yaffs_DoGenericObjectDeletion(obj); ++ } else { ++ yaffs_SoftDeleteWorker(obj, ++ obj->variant.fileVariant.top, ++ obj->variant.fileVariant. ++ topLevel, 0); ++ obj->softDeleted = 1; ++ } ++ } ++} ++ ++/* Pruning removes any part of the file structure tree that is beyond the ++ * bounds of the file (ie that does not point to chunks). ++ * ++ * A file should only get pruned when its size is reduced. ++ * ++ * Before pruning, the chunks must be pulled from the tree and the ++ * level 0 tnode entries must be zeroed out. ++ * Could also use this for file deletion, but that's probably better handled ++ * by a special case. ++ */ ++ ++static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, ++ __u32 level, int del0) ++{ ++ int i; ++ int hasData; ++ ++ if (tn) { ++ hasData = 0; ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i] && level > 0) { ++ tn->internal[i] = ++ yaffs_PruneWorker(dev, tn->internal[i], ++ level - 1, ++ (i == 0) ? del0 : 1); ++ } ++ ++ if (tn->internal[i]) ++ hasData++; ++ } ++ ++ if (hasData == 0 && del0) { ++ /* Free and return NULL */ ++ ++ yaffs_FreeTnode(dev, tn); ++ tn = NULL; ++ } ++ ++ } ++ ++ return tn; ++ ++} ++ ++static int yaffs_PruneFileStructure(yaffs_Device *dev, ++ yaffs_FileStructure *fStruct) ++{ ++ int i; ++ int hasData; ++ int done = 0; ++ yaffs_Tnode *tn; ++ ++ if (fStruct->topLevel > 0) { ++ fStruct->top = ++ yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); ++ ++ /* Now we have a tree with all the non-zero branches NULL but the height ++ * is the same as it was. ++ * Let's see if we can trim internal tnodes to shorten the tree. ++ * We can do this if only the 0th element in the tnode is in use ++ * (ie all the non-zero are NULL) ++ */ ++ ++ while (fStruct->topLevel && !done) { ++ tn = fStruct->top; ++ ++ hasData = 0; ++ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { ++ if (tn->internal[i]) ++ hasData++; ++ } ++ ++ if (!hasData) { ++ fStruct->top = tn->internal[0]; ++ fStruct->topLevel--; ++ yaffs_FreeTnode(dev, tn); ++ } else { ++ done = 1; ++ } ++ } ++ } ++ ++ return YAFFS_OK; ++} ++ ++/*-------------------- End of File Structure functions.-------------------*/ ++ ++/* yaffs_CreateFreeObjects creates a bunch more objects and ++ * adds them to the object free list. ++ */ ++static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) ++{ ++ int i; ++ yaffs_Object *newObjects; ++ yaffs_ObjectList *list; ++ ++ if (nObjects < 1) ++ return YAFFS_OK; ++ ++ /* make these things */ ++ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); ++ list = YMALLOC(sizeof(yaffs_ObjectList)); ++ ++ if (!newObjects || !list) { ++ if (newObjects) ++ YFREE(newObjects); ++ if (list) ++ YFREE(list); ++ T(YAFFS_TRACE_ALLOCATE, ++ (TSTR("yaffs: Could not allocate more objects" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Hook them into the free list */ ++ for (i = 0; i < nObjects - 1; i++) { ++ newObjects[i].siblings.next = ++ (struct ylist_head *)(&newObjects[i + 1]); ++ } ++ ++ newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; ++ dev->freeObjects = newObjects; ++ dev->nFreeObjects += nObjects; ++ dev->nObjectsCreated += nObjects; ++ ++ /* Now add this bunch of Objects to a list for freeing up. */ ++ ++ list->objects = newObjects; ++ list->next = dev->allocatedObjectList; ++ dev->allocatedObjectList = list; ++ ++ return YAFFS_OK; ++} ++ ++ ++/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ ++static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) ++{ ++ yaffs_Object *tn = NULL; ++ ++#ifdef VALGRIND_TEST ++ tn = YMALLOC(sizeof(yaffs_Object)); ++#else ++ /* If there are none left make more */ ++ if (!dev->freeObjects) ++ yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); ++ ++ if (dev->freeObjects) { ++ tn = dev->freeObjects; ++ dev->freeObjects = ++ (yaffs_Object *) (dev->freeObjects->siblings.next); ++ dev->nFreeObjects--; ++ } ++#endif ++ if (tn) { ++ /* Now sweeten it up... */ ++ ++ memset(tn, 0, sizeof(yaffs_Object)); ++ tn->beingCreated = 1; ++ ++ tn->myDev = dev; ++ tn->hdrChunk = 0; ++ tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; ++ YINIT_LIST_HEAD(&(tn->hardLinks)); ++ YINIT_LIST_HEAD(&(tn->hashLink)); ++ YINIT_LIST_HEAD(&tn->siblings); ++ ++ ++ /* Now make the directory sane */ ++ if (dev->rootDir) { ++ tn->parent = dev->rootDir; ++ ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children); ++ } ++ ++ /* Add it to the lost and found directory. ++ * NB Can't put root or lostNFound in lostNFound so ++ * check if lostNFound exists first ++ */ ++ if (dev->lostNFoundDir) ++ yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); ++ ++ tn->beingCreated = 0; ++ } ++ ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++ ++ return tn; ++} ++ ++static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, ++ __u32 mode) ++{ ++ ++ yaffs_Object *obj = ++ yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (obj) { ++ obj->fake = 1; /* it is fake so it might have no NAND presence... */ ++ obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ ++ obj->unlinkAllowed = 0; /* ... or unlink it */ ++ obj->deleted = 0; ++ obj->unlinked = 0; ++ obj->yst_mode = mode; ++ obj->myDev = dev; ++ obj->hdrChunk = 0; /* Not a valid chunk. */ ++ } ++ ++ return obj; ++ ++} ++ ++static void yaffs_UnhashObject(yaffs_Object *tn) ++{ ++ int bucket; ++ yaffs_Device *dev = tn->myDev; ++ ++ /* If it is still linked into the bucket list, free from the list */ ++ if (!ylist_empty(&tn->hashLink)) { ++ ylist_del_init(&tn->hashLink); ++ bucket = yaffs_HashFunction(tn->objectId); ++ dev->objectBucket[bucket].count--; ++ } ++} ++ ++/* FreeObject frees up a Object and puts it back on the free list */ ++static void yaffs_FreeObject(yaffs_Object *tn) ++{ ++ yaffs_Device *dev = tn->myDev; ++ ++#ifdef __KERNEL__ ++ T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode)); ++#endif ++ ++ if (tn->parent) ++ YBUG(); ++ if (!ylist_empty(&tn->siblings)) ++ YBUG(); ++ ++ ++#ifdef __KERNEL__ ++ if (tn->myInode) { ++ /* We're still hooked up to a cached inode. ++ * Don't delete now, but mark for later deletion ++ */ ++ tn->deferedFree = 1; ++ return; ++ } ++#endif ++ ++ yaffs_UnhashObject(tn); ++ ++#ifdef VALGRIND_TEST ++ YFREE(tn); ++#else ++ /* Link into the free list. */ ++ tn->siblings.next = (struct ylist_head *)(dev->freeObjects); ++ dev->freeObjects = tn; ++ dev->nFreeObjects++; ++#endif ++ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ ++} ++ ++#ifdef __KERNEL__ ++ ++void yaffs_HandleDeferedFree(yaffs_Object *obj) ++{ ++ if (obj->deferedFree) ++ yaffs_FreeObject(obj); ++} ++ ++#endif ++ ++static void yaffs_DeinitialiseObjects(yaffs_Device *dev) ++{ ++ /* Free the list of allocated Objects */ ++ ++ yaffs_ObjectList *tmp; ++ ++ while (dev->allocatedObjectList) { ++ tmp = dev->allocatedObjectList->next; ++ YFREE(dev->allocatedObjectList->objects); ++ YFREE(dev->allocatedObjectList); ++ ++ dev->allocatedObjectList = tmp; ++ } ++ ++ dev->freeObjects = NULL; ++ dev->nFreeObjects = 0; ++} ++ ++static void yaffs_InitialiseObjects(yaffs_Device *dev) ++{ ++ int i; ++ ++ dev->allocatedObjectList = NULL; ++ dev->freeObjects = NULL; ++ dev->nFreeObjects = 0; ++ ++ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { ++ YINIT_LIST_HEAD(&dev->objectBucket[i].list); ++ dev->objectBucket[i].count = 0; ++ } ++} ++ ++static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) ++{ ++ static int x; ++ int i; ++ int l = 999; ++ int lowest = 999999; ++ ++ /* First let's see if we can find one that's empty. */ ++ ++ for (i = 0; i < 10 && lowest > 0; i++) { ++ x++; ++ x %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->objectBucket[x].count < lowest) { ++ lowest = dev->objectBucket[x].count; ++ l = x; ++ } ++ ++ } ++ ++ /* If we didn't find an empty list, then try ++ * looking a bit further for a short one ++ */ ++ ++ for (i = 0; i < 10 && lowest > 3; i++) { ++ x++; ++ x %= YAFFS_NOBJECT_BUCKETS; ++ if (dev->objectBucket[x].count < lowest) { ++ lowest = dev->objectBucket[x].count; ++ l = x; ++ } ++ ++ } ++ ++ return l; ++} ++ ++static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) ++{ ++ int bucket = yaffs_FindNiceObjectBucket(dev); ++ ++ /* Now find an object value that has not already been taken ++ * by scanning the list. ++ */ ++ ++ int found = 0; ++ struct ylist_head *i; ++ ++ __u32 n = (__u32) bucket; ++ ++ /* yaffs_CheckObjectHashSanity(); */ ++ ++ while (!found) { ++ found = 1; ++ n += YAFFS_NOBJECT_BUCKETS; ++ if (1 || dev->objectBucket[bucket].count > 0) { ++ ylist_for_each(i, &dev->objectBucket[bucket].list) { ++ /* If there is already one in the list */ ++ if (i && ylist_entry(i, yaffs_Object, ++ hashLink)->objectId == n) { ++ found = 0; ++ } ++ } ++ } ++ } ++ ++ return n; ++} ++ ++static void yaffs_HashObject(yaffs_Object *in) ++{ ++ int bucket = yaffs_HashFunction(in->objectId); ++ yaffs_Device *dev = in->myDev; ++ ++ ylist_add(&in->hashLink, &dev->objectBucket[bucket].list); ++ dev->objectBucket[bucket].count++; ++} ++ ++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) ++{ ++ int bucket = yaffs_HashFunction(number); ++ struct ylist_head *i; ++ yaffs_Object *in; ++ ++ ylist_for_each(i, &dev->objectBucket[bucket].list) { ++ /* Look if it is in the list */ ++ if (i) { ++ in = ylist_entry(i, yaffs_Object, hashLink); ++ if (in->objectId == number) { ++#ifdef __KERNEL__ ++ /* Don't tell the VFS about this one if it is defered free */ ++ if (in->deferedFree) ++ return NULL; ++#endif ++ ++ return in; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, ++ yaffs_ObjectType type) ++{ ++ yaffs_Object *theObject; ++ yaffs_Tnode *tn = NULL; ++ ++ if (number < 0) ++ number = yaffs_CreateNewObjectNumber(dev); ++ ++ theObject = yaffs_AllocateEmptyObject(dev); ++ if (!theObject) ++ return NULL; ++ ++ if (type == YAFFS_OBJECT_TYPE_FILE) { ++ tn = yaffs_GetTnode(dev); ++ if (!tn) { ++ yaffs_FreeObject(theObject); ++ return NULL; ++ } ++ } ++ ++ if (theObject) { ++ theObject->fake = 0; ++ theObject->renameAllowed = 1; ++ theObject->unlinkAllowed = 1; ++ theObject->objectId = number; ++ yaffs_HashObject(theObject); ++ theObject->variantType = type; ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(theObject->win_atime); ++ theObject->win_ctime[0] = theObject->win_mtime[0] = ++ theObject->win_atime[0]; ++ theObject->win_ctime[1] = theObject->win_mtime[1] = ++ theObject->win_atime[1]; ++ ++#else ++ ++ theObject->yst_atime = theObject->yst_mtime = ++ theObject->yst_ctime = Y_CURRENT_TIME; ++#endif ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ theObject->variant.fileVariant.fileSize = 0; ++ theObject->variant.fileVariant.scannedFileSize = 0; ++ theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ ++ theObject->variant.fileVariant.topLevel = 0; ++ theObject->variant.fileVariant.top = tn; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ YINIT_LIST_HEAD(&theObject->variant.directoryVariant. ++ children); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* No action required */ ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* todo this should not happen */ ++ break; ++ } ++ } ++ ++ return theObject; ++} ++ ++static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, ++ int number, ++ yaffs_ObjectType type) ++{ ++ yaffs_Object *theObject = NULL; ++ ++ if (number > 0) ++ theObject = yaffs_FindObjectByNumber(dev, number); ++ ++ if (!theObject) ++ theObject = yaffs_CreateNewObject(dev, number, type); ++ ++ return theObject; ++ ++} ++ ++ ++static YCHAR *yaffs_CloneString(const YCHAR *str) ++{ ++ YCHAR *newStr = NULL; ++ ++ if (str && *str) { ++ newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); ++ if (newStr) ++ yaffs_strcpy(newStr, str); ++ } ++ ++ return newStr; ++ ++} ++ ++/* ++ * Mknod (create) a new object. ++ * equivalentObject only has meaning for a hard link; ++ * aliasString only has meaning for a sumlink. ++ * rdev only has meaning for devices (a subset of special objects) ++ */ ++ ++static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, ++ yaffs_Object *parent, ++ const YCHAR *name, ++ __u32 mode, ++ __u32 uid, ++ __u32 gid, ++ yaffs_Object *equivalentObject, ++ const YCHAR *aliasString, __u32 rdev) ++{ ++ yaffs_Object *in; ++ YCHAR *str = NULL; ++ ++ yaffs_Device *dev = parent->myDev; ++ ++ /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ ++ if (yaffs_FindObjectByName(parent, name)) ++ return NULL; ++ ++ in = yaffs_CreateNewObject(dev, -1, type); ++ ++ if (!in) ++ return YAFFS_FAIL; ++ ++ if (type == YAFFS_OBJECT_TYPE_SYMLINK) { ++ str = yaffs_CloneString(aliasString); ++ if (!str) { ++ yaffs_FreeObject(in); ++ return NULL; ++ } ++ } ++ ++ ++ ++ if (in) { ++ in->hdrChunk = 0; ++ in->valid = 1; ++ in->variantType = type; ++ ++ in->yst_mode = mode; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(in->win_atime); ++ in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; ++ in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; ++ ++#else ++ in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; ++ ++ in->yst_rdev = rdev; ++ in->yst_uid = uid; ++ in->yst_gid = gid; ++#endif ++ in->nDataChunks = 0; ++ ++ yaffs_SetObjectName(in, name); ++ in->dirty = 1; ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ in->myDev = parent->myDev; ++ ++ switch (type) { ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symLinkVariant.alias = str; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardLinkVariant.equivalentObject = ++ equivalentObject; ++ in->variant.hardLinkVariant.equivalentObjectId = ++ equivalentObject->objectId; ++ ylist_add(&in->hardLinks, &equivalentObject->hardLinks); ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* do nothing */ ++ break; ++ } ++ ++ if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { ++ /* Could not create the object header, fail the creation */ ++ yaffs_DeleteObject(in); ++ in = NULL; ++ } ++ ++ } ++ ++ return in; ++} ++ ++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, ++ uid, gid, NULL, NULL, 0); ++} ++ ++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, ++ mode, uid, gid, NULL, NULL, 0); ++} ++ ++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, ++ uid, gid, NULL, NULL, rdev); ++} ++ ++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, ++ const YCHAR *alias) ++{ ++ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, ++ uid, gid, NULL, alias, 0); ++} ++ ++/* yaffs_Link returns the object id of the equivalent object.*/ ++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, ++ yaffs_Object *equivalentObject) ++{ ++ /* Get the real object in case we were fed a hard link as an equivalent object */ ++ equivalentObject = yaffs_GetEquivalentObject(equivalentObject); ++ ++ if (yaffs_MknodObject ++ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, ++ equivalentObject, NULL, 0)) { ++ return equivalentObject; ++ } else { ++ return NULL; ++ } ++ ++} ++ ++static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, ++ const YCHAR *newName, int force, int shadows) ++{ ++ int unlinkOp; ++ int deleteOp; ++ ++ yaffs_Object *existingTarget; ++ ++ if (newDir == NULL) ++ newDir = obj->parent; /* use the old directory */ ++ ++ if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_ChangeObjectName: newDir is not a directory" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ ++ if (obj->myDev->isYaffs2) ++ unlinkOp = (newDir == obj->myDev->unlinkedDir); ++ else ++ unlinkOp = (newDir == obj->myDev->unlinkedDir ++ && obj->variantType == YAFFS_OBJECT_TYPE_FILE); ++ ++ deleteOp = (newDir == obj->myDev->deletedDir); ++ ++ existingTarget = yaffs_FindObjectByName(newDir, newName); ++ ++ /* If the object is a file going into the unlinked directory, ++ * then it is OK to just stuff it in since duplicate names are allowed. ++ * else only proceed if the new name does not exist and if we're putting ++ * it into a directory. ++ */ ++ if ((unlinkOp || ++ deleteOp || ++ force || ++ (shadows > 0) || ++ !existingTarget) && ++ newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { ++ yaffs_SetObjectName(obj, newName); ++ obj->dirty = 1; ++ ++ yaffs_AddObjectToDirectory(newDir, obj); ++ ++ if (unlinkOp) ++ obj->unlinked = 1; ++ ++ /* If it is a deletion then we mark it as a shrink for gc purposes. */ ++ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0) ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, ++ yaffs_Object *newDir, const YCHAR *newName) ++{ ++ yaffs_Object *obj = NULL; ++ yaffs_Object *existingTarget = NULL; ++ int force = 0; ++ ++ ++ if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) ++ YBUG(); ++ if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) ++ YBUG(); ++ ++#ifdef CONFIG_YAFFS_CASE_INSENSITIVE ++ /* Special case for case insemsitive systems (eg. WinCE). ++ * While look-up is case insensitive, the name isn't. ++ * Therefore we might want to change x.txt to X.txt ++ */ ++ if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) ++ force = 1; ++#endif ++ ++ else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) ++ /* ENAMETOOLONG */ ++ return YAFFS_FAIL; ++ ++ obj = yaffs_FindObjectByName(oldDir, oldName); ++ ++ if (obj && obj->renameAllowed) { ++ ++ /* Now do the handling for an existing target, if there is one */ ++ ++ existingTarget = yaffs_FindObjectByName(newDir, newName); ++ if (existingTarget && ++ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && ++ !ylist_empty(&existingTarget->variant.directoryVariant.children)) { ++ /* There is a target that is a non-empty directory, so we fail */ ++ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ ++ } else if (existingTarget && existingTarget != obj) { ++ /* Nuke the target first, using shadowing, ++ * but only if it isn't the same object ++ */ ++ yaffs_ChangeObjectName(obj, newDir, newName, force, ++ existingTarget->objectId); ++ yaffs_UnlinkObject(existingTarget); ++ } ++ ++ return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); ++ } ++ return YAFFS_FAIL; ++} ++ ++/*------------------------- Block Management and Page Allocation ----------------*/ ++ ++static int yaffs_InitialiseBlocks(yaffs_Device *dev) ++{ ++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; ++ ++ dev->blockInfo = NULL; ++ dev->chunkBits = NULL; ++ ++ dev->allocationBlock = -1; /* force it to get a new one */ ++ ++ /* If the first allocation strategy fails, thry the alternate one */ ++ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); ++ if (!dev->blockInfo) { ++ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); ++ dev->blockInfoAlt = 1; ++ } else ++ dev->blockInfoAlt = 0; ++ ++ if (dev->blockInfo) { ++ /* Set up dynamic blockinfo stuff. */ ++ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ ++ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); ++ if (!dev->chunkBits) { ++ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); ++ dev->chunkBitsAlt = 1; ++ } else ++ dev->chunkBitsAlt = 0; ++ } ++ ++ if (dev->blockInfo && dev->chunkBits) { ++ memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); ++ memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) ++{ ++ if (dev->blockInfoAlt && dev->blockInfo) ++ YFREE_ALT(dev->blockInfo); ++ else if (dev->blockInfo) ++ YFREE(dev->blockInfo); ++ ++ dev->blockInfoAlt = 0; ++ ++ dev->blockInfo = NULL; ++ ++ if (dev->chunkBitsAlt && dev->chunkBits) ++ YFREE_ALT(dev->chunkBits); ++ else if (dev->chunkBits) ++ YFREE(dev->chunkBits); ++ dev->chunkBitsAlt = 0; ++ dev->chunkBits = NULL; ++} ++ ++static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, ++ yaffs_BlockInfo *bi) ++{ ++ int i; ++ __u32 seq; ++ yaffs_BlockInfo *b; ++ ++ if (!dev->isYaffs2) ++ return 1; /* disqualification only applies to yaffs2. */ ++ ++ if (!bi->hasShrinkHeader) ++ return 1; /* can gc */ ++ ++ /* Find the oldest dirty sequence number if we don't know it and save it ++ * so we don't have to keep recomputing it. ++ */ ++ if (!dev->oldestDirtySequence) { ++ seq = dev->sequenceNumber; ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; ++ i++) { ++ b = yaffs_GetBlockInfo(dev, i); ++ if (b->blockState == YAFFS_BLOCK_STATE_FULL && ++ (b->pagesInUse - b->softDeletions) < ++ dev->nChunksPerBlock && b->sequenceNumber < seq) { ++ seq = b->sequenceNumber; ++ } ++ } ++ dev->oldestDirtySequence = seq; ++ } ++ ++ /* Can't do gc of this block if there are any blocks older than this one that have ++ * discarded pages. ++ */ ++ return (bi->sequenceNumber <= dev->oldestDirtySequence); ++} ++ ++/* FindDiretiestBlock is used to select the dirtiest block (or close enough) ++ * for garbage collection. ++ */ ++ ++static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, ++ int aggressive) ++{ ++ int b = dev->currentDirtyChecker; ++ ++ int i; ++ int iterations; ++ int dirtiest = -1; ++ int pagesInUse = 0; ++ int prioritised = 0; ++ yaffs_BlockInfo *bi; ++ int pendingPrioritisedExist = 0; ++ ++ /* First let's see if we need to grab a prioritised block */ ++ if (dev->hasPendingPrioritisedGCs) { ++ for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) { ++ ++ bi = yaffs_GetBlockInfo(dev, i); ++ /* yaffs_VerifyBlock(dev,bi,i); */ ++ ++ if (bi->gcPrioritise) { ++ pendingPrioritisedExist = 1; ++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL && ++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { ++ pagesInUse = (bi->pagesInUse - bi->softDeletions); ++ dirtiest = i; ++ prioritised = 1; ++ aggressive = 1; /* Fool the non-aggressive skip logiv below */ ++ } ++ } ++ } ++ ++ if (!pendingPrioritisedExist) /* None found, so we can clear this */ ++ dev->hasPendingPrioritisedGCs = 0; ++ } ++ ++ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and ++ * search harder. ++ * else (we're doing a leasurely gc), then we only bother to do this if the ++ * block has only a few pages in use. ++ */ ++ ++ dev->nonAggressiveSkip--; ++ ++ if (!aggressive && (dev->nonAggressiveSkip > 0)) ++ return -1; ++ ++ if (!prioritised) ++ pagesInUse = ++ (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; ++ ++ if (aggressive) ++ iterations = ++ dev->internalEndBlock - dev->internalStartBlock + 1; ++ else { ++ iterations = ++ dev->internalEndBlock - dev->internalStartBlock + 1; ++ iterations = iterations / 16; ++ if (iterations > 200) ++ iterations = 200; ++ } ++ ++ for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { ++ b++; ++ if (b < dev->internalStartBlock || b > dev->internalEndBlock) ++ b = dev->internalStartBlock; ++ ++ if (b < dev->internalStartBlock || b > dev->internalEndBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> Block %d is not valid" TENDSTR), b)); ++ YBUG(); ++ } ++ ++ bi = yaffs_GetBlockInfo(dev, b); ++ ++ if (bi->blockState == YAFFS_BLOCK_STATE_FULL && ++ (bi->pagesInUse - bi->softDeletions) < pagesInUse && ++ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { ++ dirtiest = b; ++ pagesInUse = (bi->pagesInUse - bi->softDeletions); ++ } ++ } ++ ++ dev->currentDirtyChecker = b; ++ ++ if (dirtiest > 0) { ++ T(YAFFS_TRACE_GC, ++ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, ++ dev->nChunksPerBlock - pagesInUse, prioritised)); ++ } ++ ++ dev->oldestDirtySequence = 0; ++ ++ if (dirtiest > 0) ++ dev->nonAggressiveSkip = 4; ++ ++ return dirtiest; ++} ++ ++static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) ++{ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); ++ ++ int erasedOk = 0; ++ ++ /* If the block is still healthy erase it and mark as clean. ++ * If the block has had a data failure, then retire it. ++ */ ++ ++ T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, ++ (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), ++ blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); ++ ++ bi->blockState = YAFFS_BLOCK_STATE_DIRTY; ++ ++ if (!bi->needsRetiring) { ++ yaffs_InvalidateCheckpoint(dev); ++ erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); ++ if (!erasedOk) { ++ dev->nErasureFailures++; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); ++ } ++ } ++ ++ if (erasedOk && ++ ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { ++ int i; ++ for (i = 0; i < dev->nChunksPerBlock; i++) { ++ if (!yaffs_CheckChunkErased ++ (dev, blockNo * dev->nChunksPerBlock + i)) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ (">>Block %d erasure supposedly OK, but chunk %d not erased" ++ TENDSTR), blockNo, i)); ++ } ++ } ++ } ++ ++ if (erasedOk) { ++ /* Clean it up... */ ++ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ bi->hasShrinkHeader = 0; ++ bi->skipErasedCheck = 1; /* This is clean, so no need to check */ ++ bi->gcPrioritise = 0; ++ yaffs_ClearChunkBits(dev, blockNo); ++ ++ T(YAFFS_TRACE_ERASE, ++ (TSTR("Erased block %d" TENDSTR), blockNo)); ++ } else { ++ dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ ++ ++ yaffs_RetireBlock(dev, blockNo); ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>> Block %d retired" TENDSTR), blockNo)); ++ } ++} ++ ++static int yaffs_FindBlockForAllocation(yaffs_Device *dev) ++{ ++ int i; ++ ++ yaffs_BlockInfo *bi; ++ ++ if (dev->nErasedBlocks < 1) { ++ /* Hoosterman we've got a problem. ++ * Can't get space to gc ++ */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); ++ ++ return -1; ++ } ++ ++ /* Find an empty block. */ ++ ++ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { ++ dev->allocationBlockFinder++; ++ if (dev->allocationBlockFinder < dev->internalStartBlock ++ || dev->allocationBlockFinder > dev->internalEndBlock) { ++ dev->allocationBlockFinder = dev->internalStartBlock; ++ } ++ ++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); ++ ++ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { ++ bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->sequenceNumber++; ++ bi->sequenceNumber = dev->sequenceNumber; ++ dev->nErasedBlocks--; ++ T(YAFFS_TRACE_ALLOCATE, ++ (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), ++ dev->allocationBlockFinder, dev->sequenceNumber, ++ dev->nErasedBlocks)); ++ return dev->allocationBlockFinder; ++ } ++ } ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs tragedy: no more erased blocks, but there should have been %d" ++ TENDSTR), dev->nErasedBlocks)); ++ ++ return -1; ++} ++ ++ ++ ++static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) ++{ ++ if (!dev->nCheckpointBlocksRequired && ++ dev->isYaffs2) { ++ /* Not a valid value so recalculate */ ++ int nBytes = 0; ++ int nBlocks; ++ int devBlocks = (dev->endBlock - dev->startBlock + 1); ++ int tnodeSize; ++ ++ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ nBytes += sizeof(yaffs_CheckpointValidity); ++ nBytes += sizeof(yaffs_CheckpointDevice); ++ nBytes += devBlocks * sizeof(yaffs_BlockInfo); ++ nBytes += devBlocks * dev->chunkBitmapStride; ++ nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects); ++ nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes); ++ nBytes += sizeof(yaffs_CheckpointValidity); ++ nBytes += sizeof(__u32); /* checksum*/ ++ ++ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ ++ ++ nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3; ++ ++ dev->nCheckpointBlocksRequired = nBlocks; ++ } ++ ++ return dev->nCheckpointBlocksRequired; ++} ++ ++/* ++ * Check if there's space to allocate... ++ * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? ++ */ ++static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) ++{ ++ int reservedChunks; ++ int reservedBlocks = dev->nReservedBlocks; ++ int checkpointBlocks; ++ ++ if (dev->isYaffs2) { ++ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - ++ dev->blocksInCheckpoint; ++ if (checkpointBlocks < 0) ++ checkpointBlocks = 0; ++ } else { ++ checkpointBlocks = 0; ++ } ++ ++ reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); ++ ++ return (dev->nFreeChunks > reservedChunks); ++} ++ ++static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, ++ yaffs_BlockInfo **blockUsedPtr) ++{ ++ int retVal; ++ yaffs_BlockInfo *bi; ++ ++ if (dev->allocationBlock < 0) { ++ /* Get next block to allocate off */ ++ dev->allocationBlock = yaffs_FindBlockForAllocation(dev); ++ dev->allocationPage = 0; ++ } ++ ++ if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { ++ /* Not enough space to allocate unless we're allowed to use the reserve. */ ++ return -1; ++ } ++ ++ if (dev->nErasedBlocks < dev->nReservedBlocks ++ && dev->allocationPage == 0) { ++ T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); ++ } ++ ++ /* Next page please.... */ ++ if (dev->allocationBlock >= 0) { ++ bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); ++ ++ retVal = (dev->allocationBlock * dev->nChunksPerBlock) + ++ dev->allocationPage; ++ bi->pagesInUse++; ++ yaffs_SetChunkBit(dev, dev->allocationBlock, ++ dev->allocationPage); ++ ++ dev->allocationPage++; ++ ++ dev->nFreeChunks--; ++ ++ /* If the block is full set the state to full */ ++ if (dev->allocationPage >= dev->nChunksPerBlock) { ++ bi->blockState = YAFFS_BLOCK_STATE_FULL; ++ dev->allocationBlock = -1; ++ } ++ ++ if (blockUsedPtr) ++ *blockUsedPtr = bi; ++ ++ return retVal; ++ } ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); ++ ++ return -1; ++} ++ ++static int yaffs_GetErasedChunks(yaffs_Device *dev) ++{ ++ int n; ++ ++ n = dev->nErasedBlocks * dev->nChunksPerBlock; ++ ++ if (dev->allocationBlock > 0) ++ n += (dev->nChunksPerBlock - dev->allocationPage); ++ ++ return n; ++ ++} ++ ++static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, ++ int wholeBlock) ++{ ++ int oldChunk; ++ int newChunk; ++ int markNAND; ++ int retVal = YAFFS_OK; ++ int cleanups = 0; ++ int i; ++ int isCheckpointBlock; ++ int matchingChunk; ++ int maxCopies; ++ ++ int chunksBefore = yaffs_GetErasedChunks(dev); ++ int chunksAfter; ++ ++ yaffs_ExtendedTags tags; ++ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); ++ ++ yaffs_Object *object; ++ ++ isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); ++ ++ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; ++ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), ++ block, ++ bi->pagesInUse, ++ bi->hasShrinkHeader, ++ wholeBlock)); ++ ++ /*yaffs_VerifyFreeChunks(dev); */ ++ ++ bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ ++ ++ /* Take off the number of soft deleted entries because ++ * they're going to get really deleted during GC. ++ */ ++ dev->nFreeChunks -= bi->softDeletions; ++ ++ dev->isDoingGC = 1; ++ ++ if (isCheckpointBlock || ++ !yaffs_StillSomeChunkBits(dev, block)) { ++ T(YAFFS_TRACE_TRACING, ++ (TSTR ++ ("Collecting block %d that has no chunks in use" TENDSTR), ++ block)); ++ yaffs_BlockBecameDirty(dev, block); ++ } else { ++ ++ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ yaffs_VerifyBlock(dev, bi, block); ++ ++ maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; ++ oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; ++ ++ for (/* init already done */; ++ retVal == YAFFS_OK && ++ dev->gcChunk < dev->nChunksPerBlock && ++ (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) && ++ maxCopies > 0; ++ dev->gcChunk++, oldChunk++) { ++ if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) { ++ ++ /* This page is in use and might need to be copied off */ ++ ++ maxCopies--; ++ ++ markNAND = 1; ++ ++ yaffs_InitialiseTags(&tags); ++ ++ yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, ++ buffer, &tags); ++ ++ object = ++ yaffs_FindObjectByNumber(dev, ++ tags.objectId); ++ ++ T(YAFFS_TRACE_GC_DETAIL, ++ (TSTR ++ ("Collecting chunk in block %d, %d %d %d " TENDSTR), ++ dev->gcChunk, tags.objectId, tags.chunkId, ++ tags.byteCount)); ++ ++ if (object && !yaffs_SkipVerification(dev)) { ++ if (tags.chunkId == 0) ++ matchingChunk = object->hdrChunk; ++ else if (object->softDeleted) ++ matchingChunk = oldChunk; /* Defeat the test */ ++ else ++ matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL); ++ ++ if (oldChunk != matchingChunk) ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), ++ oldChunk, matchingChunk, tags.objectId, tags.chunkId)); ++ ++ } ++ ++ if (!object) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("page %d in gc has no object: %d %d %d " ++ TENDSTR), oldChunk, ++ tags.objectId, tags.chunkId, tags.byteCount)); ++ } ++ ++ if (object && ++ object->deleted && ++ object->softDeleted && ++ tags.chunkId != 0) { ++ /* Data chunk in a soft deleted file, throw it away ++ * It's a soft deleted data chunk, ++ * No need to copy this, just forget about it and ++ * fix up the object. ++ */ ++ ++ object->nDataChunks--; ++ ++ if (object->nDataChunks <= 0) { ++ /* remeber to clean up the object */ ++ dev->gcCleanupList[cleanups] = ++ tags.objectId; ++ cleanups++; ++ } ++ markNAND = 0; ++ } else if (0) { ++ /* Todo object && object->deleted && object->nDataChunks == 0 */ ++ /* Deleted object header with no data chunks. ++ * Can be discarded and the file deleted. ++ */ ++ object->hdrChunk = 0; ++ yaffs_FreeTnode(object->myDev, ++ object->variant. ++ fileVariant.top); ++ object->variant.fileVariant.top = NULL; ++ yaffs_DoGenericObjectDeletion(object); ++ ++ } else if (object) { ++ /* It's either a data chunk in a live file or ++ * an ObjectHeader, so we're interested in it. ++ * NB Need to keep the ObjectHeaders of deleted files ++ * until the whole file has been deleted off ++ */ ++ tags.serialNumber++; ++ ++ dev->nGCCopies++; ++ ++ if (tags.chunkId == 0) { ++ /* It is an object Id, ++ * We need to nuke the shrinkheader flags first ++ * We no longer want the shrinkHeader flag since its work is done ++ * and if it is left in place it will mess up scanning. ++ */ ++ ++ yaffs_ObjectHeader *oh; ++ oh = (yaffs_ObjectHeader *)buffer; ++ oh->isShrink = 0; ++ tags.extraIsShrinkHeader = 0; ++ ++ yaffs_VerifyObjectHeader(object, oh, &tags, 1); ++ } ++ ++ newChunk = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); ++ ++ if (newChunk < 0) { ++ retVal = YAFFS_FAIL; ++ } else { ++ ++ /* Ok, now fix up the Tnodes etc. */ ++ ++ if (tags.chunkId == 0) { ++ /* It's a header */ ++ object->hdrChunk = newChunk; ++ object->serial = tags.serialNumber; ++ } else { ++ /* It's a data chunk */ ++ yaffs_PutChunkIntoFile ++ (object, ++ tags.chunkId, ++ newChunk, 0); ++ } ++ } ++ } ++ ++ if (retVal == YAFFS_OK) ++ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); ++ ++ } ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ ++ ++ /* Do any required cleanups */ ++ for (i = 0; i < cleanups; i++) { ++ /* Time to delete the file too */ ++ object = ++ yaffs_FindObjectByNumber(dev, ++ dev->gcCleanupList[i]); ++ if (object) { ++ yaffs_FreeTnode(dev, ++ object->variant.fileVariant. ++ top); ++ object->variant.fileVariant.top = NULL; ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: About to finally delete object %d" ++ TENDSTR), object->objectId)); ++ yaffs_DoGenericObjectDeletion(object); ++ object->myDev->nDeletedFiles--; ++ } ++ ++ } ++ ++ } ++ ++ yaffs_VerifyCollectedBlock(dev, bi, block); ++ ++ chunksAfter = yaffs_GetErasedChunks(dev); ++ if (chunksBefore >= chunksAfter) { ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("gc did not increase free chunks before %d after %d" ++ TENDSTR), chunksBefore, chunksAfter)); ++ } ++ ++ /* If the gc completed then clear the current gcBlock so that we find another. */ ++ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->gcBlock = -1; ++ dev->gcChunk = 0; ++ } ++ ++ dev->isDoingGC = 0; ++ ++ return retVal; ++} ++ ++/* New garbage collector ++ * If we're very low on erased blocks then we do aggressive garbage collection ++ * otherwise we do "leasurely" garbage collection. ++ * Aggressive gc looks further (whole array) and will accept less dirty blocks. ++ * Passive gc only inspects smaller areas and will only accept more dirty blocks. ++ * ++ * The idea is to help clear out space in a more spread-out manner. ++ * Dunno if it really does anything useful. ++ */ ++static int yaffs_CheckGarbageCollection(yaffs_Device *dev) ++{ ++ int block; ++ int aggressive; ++ int gcOk = YAFFS_OK; ++ int maxTries = 0; ++ ++ int checkpointBlockAdjust; ++ ++ if (dev->isDoingGC) { ++ /* Bail out so we don't get recursive gc */ ++ return YAFFS_OK; ++ } ++ ++ /* This loop should pass the first time. ++ * We'll only see looping here if the erase of the collected block fails. ++ */ ++ ++ do { ++ maxTries++; ++ ++ checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; ++ if (checkpointBlockAdjust < 0) ++ checkpointBlockAdjust = 0; ++ ++ if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { ++ /* We need a block soon...*/ ++ aggressive = 1; ++ } else { ++ /* We're in no hurry */ ++ aggressive = 0; ++ } ++ ++ if (dev->gcBlock <= 0) { ++ dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); ++ dev->gcChunk = 0; ++ } ++ ++ block = dev->gcBlock; ++ ++ if (block > 0) { ++ dev->garbageCollections++; ++ if (!aggressive) ++ dev->passiveGarbageCollections++; ++ ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), ++ dev->nErasedBlocks, aggressive)); ++ ++ gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); ++ } ++ ++ if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { ++ T(YAFFS_TRACE_GC, ++ (TSTR ++ ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" ++ TENDSTR), dev->nErasedBlocks, maxTries, block)); ++ } ++ } while ((dev->nErasedBlocks < dev->nReservedBlocks) && ++ (block > 0) && ++ (maxTries < 2)); ++ ++ return aggressive ? gcOk : YAFFS_OK; ++} ++ ++/*------------------------- TAGS --------------------------------*/ ++ ++static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, ++ int chunkInObject) ++{ ++ return (tags->chunkId == chunkInObject && ++ tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0; ++ ++} ++ ++ ++/*-------------------- Data file manipulation -----------------*/ ++ ++static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags) ++{ ++ /*Get the Tnode, then get the level 0 offset chunk offset */ ++ yaffs_Tnode *tn; ++ int theChunk = -1; ++ yaffs_ExtendedTags localTags; ++ int retVal = -1; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &localTags; ++ } ++ ++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); ++ ++ if (tn) { ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ retVal = ++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, ++ chunkInInode); ++ } ++ return retVal; ++} ++ ++static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, ++ yaffs_ExtendedTags *tags) ++{ ++ /* Get the Tnode, then get the level 0 offset chunk offset */ ++ yaffs_Tnode *tn; ++ int theChunk = -1; ++ yaffs_ExtendedTags localTags; ++ ++ yaffs_Device *dev = in->myDev; ++ int retVal = -1; ++ ++ if (!tags) { ++ /* Passed a NULL, so use our own tags space */ ++ tags = &localTags; ++ } ++ ++ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); ++ ++ if (tn) { ++ ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ retVal = ++ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, ++ chunkInInode); ++ ++ /* Delete the entry in the filestructure (if found) */ ++ if (retVal != -1) ++ yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); ++ } ++ ++ return retVal; ++} ++ ++#ifdef YAFFS_PARANOID ++ ++static int yaffs_CheckFileSanity(yaffs_Object *in) ++{ ++ int chunk; ++ int nChunks; ++ int fSize; ++ int failed = 0; ++ int objId; ++ yaffs_Tnode *tn; ++ yaffs_Tags localTags; ++ yaffs_Tags *tags = &localTags; ++ int theChunk; ++ int chunkDeleted; ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ objId = in->objectId; ++ fSize = in->variant.fileVariant.fileSize; ++ nChunks = ++ (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; ++ ++ for (chunk = 1; chunk <= nChunks; chunk++) { ++ tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, ++ chunk); ++ ++ if (tn) { ++ ++ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); ++ ++ if (yaffs_CheckChunkBits ++ (dev, theChunk / dev->nChunksPerBlock, ++ theChunk % dev->nChunksPerBlock)) { ++ ++ yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, ++ tags, ++ &chunkDeleted); ++ if (yaffs_TagsMatch ++ (tags, in->objectId, chunk, chunkDeleted)) { ++ /* found it; */ ++ ++ } ++ } else { ++ ++ failed = 1; ++ } ++ ++ } else { ++ /* T(("No level 0 found for %d\n", chunk)); */ ++ } ++ } ++ ++ return failed ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++#endif ++ ++static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, ++ int chunkInNAND, int inScan) ++{ ++ /* NB inScan is zero unless scanning. ++ * For forward scanning, inScan is > 0; ++ * for backward scanning inScan is < 0 ++ */ ++ ++ yaffs_Tnode *tn; ++ yaffs_Device *dev = in->myDev; ++ int existingChunk; ++ yaffs_ExtendedTags existingTags; ++ yaffs_ExtendedTags newTags; ++ unsigned existingSerial, newSerial; ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { ++ /* Just ignore an attempt at putting a chunk into a non-file during scanning ++ * If it is not during Scanning then something went wrong! ++ */ ++ if (!inScan) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy:attempt to put data chunk into a non-file" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++ return YAFFS_OK; ++ } ++ ++ tn = yaffs_AddOrFindLevel0Tnode(dev, ++ &in->variant.fileVariant, ++ chunkInInode, ++ NULL); ++ if (!tn) ++ return YAFFS_FAIL; ++ ++ existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); ++ ++ if (inScan != 0) { ++ /* If we're scanning then we need to test for duplicates ++ * NB This does not need to be efficient since it should only ever ++ * happen when the power fails during a write, then only one ++ * chunk should ever be affected. ++ * ++ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO ++ * Update: For backward scanning we don't need to re-read tags so this is quite cheap. ++ */ ++ ++ if (existingChunk > 0) { ++ /* NB Right now existing chunk will not be real chunkId if the device >= 32MB ++ * thus we have to do a FindChunkInFile to get the real chunk id. ++ * ++ * We have a duplicate now we need to decide which one to use: ++ * ++ * Backwards scanning YAFFS2: The old one is what we use, dump the new one. ++ * Forward scanning YAFFS2: The new one is what we use, dump the old one. ++ * YAFFS1: Get both sets of tags and compare serial numbers. ++ */ ++ ++ if (inScan > 0) { ++ /* Only do this for forward scanning */ ++ yaffs_ReadChunkWithTagsFromNAND(dev, ++ chunkInNAND, ++ NULL, &newTags); ++ ++ /* Do a proper find */ ++ existingChunk = ++ yaffs_FindChunkInFile(in, chunkInInode, ++ &existingTags); ++ } ++ ++ if (existingChunk <= 0) { ++ /*Hoosterman - how did this happen? */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: existing chunk < 0 in scan" ++ TENDSTR))); ++ ++ } ++ ++ /* NB The deleted flags should be false, otherwise the chunks will ++ * not be loaded during a scan ++ */ ++ ++ if (inScan > 0) { ++ newSerial = newTags.serialNumber; ++ existingSerial = existingTags.serialNumber; ++ } ++ ++ if ((inScan > 0) && ++ (in->myDev->isYaffs2 || ++ existingChunk <= 0 || ++ ((existingSerial + 1) & 3) == newSerial)) { ++ /* Forward scanning. ++ * Use new ++ * Delete the old one and drop through to update the tnode ++ */ ++ yaffs_DeleteChunk(dev, existingChunk, 1, ++ __LINE__); ++ } else { ++ /* Backward scanning or we want to use the existing one ++ * Use existing. ++ * Delete the new one and return early so that the tnode isn't changed ++ */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, ++ __LINE__); ++ return YAFFS_OK; ++ } ++ } ++ ++ } ++ ++ if (existingChunk == 0) ++ in->nDataChunks++; ++ ++ yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); ++ ++ return YAFFS_OK; ++} ++ ++static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode, ++ __u8 *buffer) ++{ ++ int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); ++ ++ if (chunkInNAND >= 0) ++ return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, ++ buffer, NULL); ++ else { ++ T(YAFFS_TRACE_NANDACCESS, ++ (TSTR("Chunk %d not found zero instead" TENDSTR), ++ chunkInNAND)); ++ /* get sane (zero) data if you read a hole */ ++ memset(buffer, 0, in->myDev->nDataBytesPerChunk); ++ return 0; ++ } ++ ++} ++ ++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) ++{ ++ int block; ++ int page; ++ yaffs_ExtendedTags tags; ++ yaffs_BlockInfo *bi; ++ ++ if (chunkId <= 0) ++ return; ++ ++ dev->nDeletions++; ++ block = chunkId / dev->nChunksPerBlock; ++ page = chunkId % dev->nChunksPerBlock; ++ ++ ++ if (!yaffs_CheckChunkBit(dev, block, page)) ++ T(YAFFS_TRACE_VERIFY, ++ (TSTR("Deleting invalid chunk %d"TENDSTR), ++ chunkId)); ++ ++ bi = yaffs_GetBlockInfo(dev, block); ++ ++ T(YAFFS_TRACE_DELETION, ++ (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); ++ ++ if (markNAND && ++ bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { ++ ++ yaffs_InitialiseTags(&tags); ++ ++ tags.chunkDeleted = 1; ++ ++ yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags); ++ yaffs_HandleUpdateChunk(dev, chunkId, &tags); ++ } else { ++ dev->nUnmarkedDeletions++; ++ } ++ ++ /* Pull out of the management area. ++ * If the whole block became dirty, this will kick off an erasure. ++ */ ++ if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || ++ bi->blockState == YAFFS_BLOCK_STATE_FULL || ++ bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { ++ dev->nFreeChunks++; ++ ++ yaffs_ClearChunkBit(dev, block, page); ++ ++ bi->pagesInUse--; ++ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && ++ bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ yaffs_BlockBecameDirty(dev, block); ++ } ++ ++ } ++ ++} ++ ++static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, ++ const __u8 *buffer, int nBytes, ++ int useReserve) ++{ ++ /* Find old chunk Need to do this to get serial number ++ * Write new one and patch into tree. ++ * Invalidate old tags. ++ */ ++ ++ int prevChunkId; ++ yaffs_ExtendedTags prevTags; ++ ++ int newChunkId; ++ yaffs_ExtendedTags newTags; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ yaffs_CheckGarbageCollection(dev); ++ ++ /* Get the previous chunk at this location in the file if it exists */ ++ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); ++ ++ /* Set up new tags */ ++ yaffs_InitialiseTags(&newTags); ++ ++ newTags.chunkId = chunkInInode; ++ newTags.objectId = in->objectId; ++ newTags.serialNumber = ++ (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; ++ newTags.byteCount = nBytes; ++ ++ if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); ++ YBUG(); ++ } ++ ++ newChunkId = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, ++ useReserve); ++ ++ if (newChunkId >= 0) { ++ yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); ++ ++ if (prevChunkId >= 0) ++ yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); ++ ++ yaffs_CheckFileSanity(in); ++ } ++ return newChunkId; ++ ++} ++ ++/* UpdateObjectHeader updates the header on NAND for an object. ++ * If name is not NULL, then that new name is used. ++ */ ++int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, ++ int isShrink, int shadows) ++{ ++ ++ yaffs_BlockInfo *bi; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ int prevChunkId; ++ int retVal = 0; ++ int result = 0; ++ ++ int newChunkId; ++ yaffs_ExtendedTags newTags; ++ yaffs_ExtendedTags oldTags; ++ ++ __u8 *buffer = NULL; ++ YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ yaffs_ObjectHeader *oh = NULL; ++ ++ yaffs_strcpy(oldName, _Y("silly old name")); ++ ++ ++ if (!in->fake || ++ in == dev->rootDir || /* The rootDir should also be saved */ ++ force) { ++ ++ yaffs_CheckGarbageCollection(dev); ++ yaffs_CheckObjectDetailsLoaded(in); ++ ++ buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); ++ oh = (yaffs_ObjectHeader *) buffer; ++ ++ prevChunkId = in->hdrChunk; ++ ++ if (prevChunkId > 0) { ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, ++ buffer, &oldTags); ++ ++ yaffs_VerifyObjectHeader(in, oh, &oldTags, 0); ++ ++ memcpy(oldName, oh->name, sizeof(oh->name)); ++ } ++ ++ memset(buffer, 0xFF, dev->nDataBytesPerChunk); ++ ++ oh->type = in->variantType; ++ oh->yst_mode = in->yst_mode; ++ oh->shadowsObject = oh->inbandShadowsObject = shadows; ++ ++#ifdef CONFIG_YAFFS_WINCE ++ oh->win_atime[0] = in->win_atime[0]; ++ oh->win_ctime[0] = in->win_ctime[0]; ++ oh->win_mtime[0] = in->win_mtime[0]; ++ oh->win_atime[1] = in->win_atime[1]; ++ oh->win_ctime[1] = in->win_ctime[1]; ++ oh->win_mtime[1] = in->win_mtime[1]; ++#else ++ oh->yst_uid = in->yst_uid; ++ oh->yst_gid = in->yst_gid; ++ oh->yst_atime = in->yst_atime; ++ oh->yst_mtime = in->yst_mtime; ++ oh->yst_ctime = in->yst_ctime; ++ oh->yst_rdev = in->yst_rdev; ++#endif ++ if (in->parent) ++ oh->parentObjectId = in->parent->objectId; ++ else ++ oh->parentObjectId = 0; ++ ++ if (name && *name) { ++ memset(oh->name, 0, sizeof(oh->name)); ++ yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); ++ } else if (prevChunkId >= 0) ++ memcpy(oh->name, oldName, sizeof(oh->name)); ++ else ++ memset(oh->name, 0, sizeof(oh->name)); ++ ++ oh->isShrink = isShrink; ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Should not happen */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ oh->fileSize = ++ (oh->parentObjectId == YAFFS_OBJECTID_DELETED ++ || oh->parentObjectId == ++ YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. ++ fileVariant.fileSize; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ oh->equivalentObjectId = ++ in->variant.hardLinkVariant.equivalentObjectId; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ yaffs_strncpy(oh->alias, ++ in->variant.symLinkVariant.alias, ++ YAFFS_MAX_ALIAS_LENGTH); ++ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; ++ break; ++ } ++ ++ /* Tags */ ++ yaffs_InitialiseTags(&newTags); ++ in->serial++; ++ newTags.chunkId = 0; ++ newTags.objectId = in->objectId; ++ newTags.serialNumber = in->serial; ++ ++ /* Add extra info for file header */ ++ ++ newTags.extraHeaderInfoAvailable = 1; ++ newTags.extraParentObjectId = oh->parentObjectId; ++ newTags.extraFileLength = oh->fileSize; ++ newTags.extraIsShrinkHeader = oh->isShrink; ++ newTags.extraEquivalentObjectId = oh->equivalentObjectId; ++ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; ++ newTags.extraObjectType = in->variantType; ++ ++ yaffs_VerifyObjectHeader(in, oh, &newTags, 1); ++ ++ /* Create new chunk in NAND */ ++ newChunkId = ++ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, ++ (prevChunkId >= 0) ? 1 : 0); ++ ++ if (newChunkId >= 0) { ++ ++ in->hdrChunk = newChunkId; ++ ++ if (prevChunkId >= 0) { ++ yaffs_DeleteChunk(dev, prevChunkId, 1, ++ __LINE__); ++ } ++ ++ if (!yaffs_ObjectHasCachedWriteData(in)) ++ in->dirty = 0; ++ ++ /* If this was a shrink, then mark the block that the chunk lives on */ ++ if (isShrink) { ++ bi = yaffs_GetBlockInfo(in->myDev, ++ newChunkId / in->myDev->nChunksPerBlock); ++ bi->hasShrinkHeader = 1; ++ } ++ ++ } ++ ++ retVal = newChunkId; ++ ++ } ++ ++ if (buffer) ++ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); ++ ++ return retVal; ++} ++ ++/*------------------------ Short Operations Cache ---------------------------------------- ++ * In many situations where there is no high level buffering (eg WinCE) a lot of ++ * reads might be short sequential reads, and a lot of writes may be short ++ * sequential writes. eg. scanning/writing a jpeg file. ++ * In these cases, a short read/write cache can provide a huge perfomance benefit ++ * with dumb-as-a-rock code. ++ * In Linux, the page cache provides read buffering aand the short op cache provides write ++ * buffering. ++ * ++ * There are a limited number (~10) of cache chunks per device so that we don't ++ * need a very intelligent search. ++ */ ++ ++static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int i; ++ yaffs_ChunkCache *cache; ++ int nCaches = obj->myDev->nShortOpCaches; ++ ++ for (i = 0; i < nCaches; i++) { ++ cache = &dev->srCache[i]; ++ if (cache->object == obj && ++ cache->dirty) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int lowest = -99; /* Stop compiler whining. */ ++ int i; ++ yaffs_ChunkCache *cache; ++ int chunkWritten = 0; ++ int nCaches = obj->myDev->nShortOpCaches; ++ ++ if (nCaches > 0) { ++ do { ++ cache = NULL; ++ ++ /* Find the dirty cache for this object with the lowest chunk id. */ ++ for (i = 0; i < nCaches; i++) { ++ if (dev->srCache[i].object == obj && ++ dev->srCache[i].dirty) { ++ if (!cache ++ || dev->srCache[i].chunkId < ++ lowest) { ++ cache = &dev->srCache[i]; ++ lowest = cache->chunkId; ++ } ++ } ++ } ++ ++ if (cache && !cache->locked) { ++ /* Write it out and free it up */ ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(cache->object, ++ cache->chunkId, ++ cache->data, ++ cache->nBytes, ++ 1); ++ cache->dirty = 0; ++ cache->object = NULL; ++ } ++ ++ } while (cache && chunkWritten > 0); ++ ++ if (cache) { ++ /* Hoosterman, disk full while writing cache out. */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); ++ ++ } ++ } ++ ++} ++ ++/*yaffs_FlushEntireDeviceCache(dev) ++ * ++ * ++ */ ++ ++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ int nCaches = dev->nShortOpCaches; ++ int i; ++ ++ /* Find a dirty object in the cache and flush it... ++ * until there are no further dirty objects. ++ */ ++ do { ++ obj = NULL; ++ for (i = 0; i < nCaches && !obj; i++) { ++ if (dev->srCache[i].object && ++ dev->srCache[i].dirty) ++ obj = dev->srCache[i].object; ++ ++ } ++ if (obj) ++ yaffs_FlushFilesChunkCache(obj); ++ ++ } while (obj); ++ ++} ++ ++ ++/* Grab us a cache chunk for use. ++ * First look for an empty one. ++ * Then look for the least recently used non-dirty one. ++ * Then look for the least recently used dirty one...., flush and look again. ++ */ ++static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) ++{ ++ int i; ++ ++ if (dev->nShortOpCaches > 0) { ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (!dev->srCache[i].object) ++ return &dev->srCache[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) ++{ ++ yaffs_ChunkCache *cache; ++ yaffs_Object *theObj; ++ int usage; ++ int i; ++ int pushout; ++ ++ if (dev->nShortOpCaches > 0) { ++ /* Try find a non-dirty one... */ ++ ++ cache = yaffs_GrabChunkCacheWorker(dev); ++ ++ if (!cache) { ++ /* They were all dirty, find the last recently used object and flush ++ * its cache, then find again. ++ * NB what's here is not very accurate, we actually flush the object ++ * the last recently used page. ++ */ ++ ++ /* With locking we can't assume we can use entry zero */ ++ ++ theObj = NULL; ++ usage = -1; ++ cache = NULL; ++ pushout = -1; ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object && ++ !dev->srCache[i].locked && ++ (dev->srCache[i].lastUse < usage || !cache)) { ++ usage = dev->srCache[i].lastUse; ++ theObj = dev->srCache[i].object; ++ cache = &dev->srCache[i]; ++ pushout = i; ++ } ++ } ++ ++ if (!cache || cache->dirty) { ++ /* Flush and try again */ ++ yaffs_FlushFilesChunkCache(theObj); ++ cache = yaffs_GrabChunkCacheWorker(dev); ++ } ++ ++ } ++ return cache; ++ } else ++ return NULL; ++ ++} ++ ++/* Find a cached chunk */ ++static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, ++ int chunkId) ++{ ++ yaffs_Device *dev = obj->myDev; ++ int i; ++ if (dev->nShortOpCaches > 0) { ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object == obj && ++ dev->srCache[i].chunkId == chunkId) { ++ dev->cacheHits++; ++ ++ return &dev->srCache[i]; ++ } ++ } ++ } ++ return NULL; ++} ++ ++/* Mark the chunk for the least recently used algorithym */ ++static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, ++ int isAWrite) ++{ ++ ++ if (dev->nShortOpCaches > 0) { ++ if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { ++ /* Reset the cache usages */ ++ int i; ++ for (i = 1; i < dev->nShortOpCaches; i++) ++ dev->srCache[i].lastUse = 0; ++ ++ dev->srLastUse = 0; ++ } ++ ++ dev->srLastUse++; ++ ++ cache->lastUse = dev->srLastUse; ++ ++ if (isAWrite) ++ cache->dirty = 1; ++ } ++} ++ ++/* Invalidate a single cache page. ++ * Do this when a whole page gets written, ++ * ie the short cache for this page is no longer valid. ++ */ ++static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) ++{ ++ if (object->myDev->nShortOpCaches > 0) { ++ yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); ++ ++ if (cache) ++ cache->object = NULL; ++ } ++} ++ ++/* Invalidate all the cache pages associated with this object ++ * Do this whenever ther file is deleted or resized. ++ */ ++static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) ++{ ++ int i; ++ yaffs_Device *dev = in->myDev; ++ ++ if (dev->nShortOpCaches > 0) { ++ /* Invalidate it. */ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].object == in) ++ dev->srCache[i].object = NULL; ++ } ++ } ++} ++ ++/*--------------------- Checkpointing --------------------*/ ++ ++ ++static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head) ++{ ++ yaffs_CheckpointValidity cp; ++ ++ memset(&cp, 0, sizeof(cp)); ++ ++ cp.structType = sizeof(cp); ++ cp.magic = YAFFS_MAGIC; ++ cp.version = YAFFS_CHECKPOINT_VERSION; ++ cp.head = (head) ? 1 : 0; ++ ++ return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ? ++ 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) ++{ ++ yaffs_CheckpointValidity cp; ++ int ok; ++ ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ if (ok) ++ ok = (cp.structType == sizeof(cp)) && ++ (cp.magic == YAFFS_MAGIC) && ++ (cp.version == YAFFS_CHECKPOINT_VERSION) && ++ (cp.head == ((head) ? 1 : 0)); ++ return ok ? 1 : 0; ++} ++ ++static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, ++ yaffs_Device *dev) ++{ ++ cp->nErasedBlocks = dev->nErasedBlocks; ++ cp->allocationBlock = dev->allocationBlock; ++ cp->allocationPage = dev->allocationPage; ++ cp->nFreeChunks = dev->nFreeChunks; ++ ++ cp->nDeletedFiles = dev->nDeletedFiles; ++ cp->nUnlinkedFiles = dev->nUnlinkedFiles; ++ cp->nBackgroundDeletions = dev->nBackgroundDeletions; ++ cp->sequenceNumber = dev->sequenceNumber; ++ cp->oldestDirtySequence = dev->oldestDirtySequence; ++ ++} ++ ++static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, ++ yaffs_CheckpointDevice *cp) ++{ ++ dev->nErasedBlocks = cp->nErasedBlocks; ++ dev->allocationBlock = cp->allocationBlock; ++ dev->allocationPage = cp->allocationPage; ++ dev->nFreeChunks = cp->nFreeChunks; ++ ++ dev->nDeletedFiles = cp->nDeletedFiles; ++ dev->nUnlinkedFiles = cp->nUnlinkedFiles; ++ dev->nBackgroundDeletions = cp->nBackgroundDeletions; ++ dev->sequenceNumber = cp->sequenceNumber; ++ dev->oldestDirtySequence = cp->oldestDirtySequence; ++} ++ ++ ++static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) ++{ ++ yaffs_CheckpointDevice cp; ++ __u32 nBytes; ++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); ++ ++ int ok; ++ ++ /* Write device runtime values*/ ++ yaffs_DeviceToCheckpointDevice(&cp, dev); ++ cp.structType = sizeof(cp); ++ ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ /* Write block info */ ++ if (ok) { ++ nBytes = nBlocks * sizeof(yaffs_BlockInfo); ++ ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes); ++ } ++ ++ /* Write chunk bits */ ++ if (ok) { ++ nBytes = nBlocks * dev->chunkBitmapStride; ++ ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes); ++ } ++ return ok ? 1 : 0; ++ ++} ++ ++static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) ++{ ++ yaffs_CheckpointDevice cp; ++ __u32 nBytes; ++ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); ++ ++ int ok; ++ ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (!ok) ++ return 0; ++ ++ if (cp.structType != sizeof(cp)) ++ return 0; ++ ++ ++ yaffs_CheckpointDeviceToDevice(dev, &cp); ++ ++ nBytes = nBlocks * sizeof(yaffs_BlockInfo); ++ ++ ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes); ++ ++ if (!ok) ++ return 0; ++ nBytes = nBlocks * dev->chunkBitmapStride; ++ ++ ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes); ++ ++ return ok ? 1 : 0; ++} ++ ++static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, ++ yaffs_Object *obj) ++{ ++ ++ cp->objectId = obj->objectId; ++ cp->parentId = (obj->parent) ? obj->parent->objectId : 0; ++ cp->hdrChunk = obj->hdrChunk; ++ cp->variantType = obj->variantType; ++ cp->deleted = obj->deleted; ++ cp->softDeleted = obj->softDeleted; ++ cp->unlinked = obj->unlinked; ++ cp->fake = obj->fake; ++ cp->renameAllowed = obj->renameAllowed; ++ cp->unlinkAllowed = obj->unlinkAllowed; ++ cp->serial = obj->serial; ++ cp->nDataChunks = obj->nDataChunks; ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; ++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) ++ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; ++} ++ ++static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp) ++{ ++ ++ yaffs_Object *parent; ++ ++ if (obj->variantType != cp->variantType) { ++ T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " ++ TCONT("chunk %d does not match existing object type %d") ++ TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, ++ obj->variantType)); ++ return 0; ++ } ++ ++ obj->objectId = cp->objectId; ++ ++ if (cp->parentId) ++ parent = yaffs_FindOrCreateObjectByNumber( ++ obj->myDev, ++ cp->parentId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ else ++ parent = NULL; ++ ++ if (parent) { ++ if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" ++ TCONT(" chunk %d Parent type, %d, not directory") ++ TENDSTR), ++ cp->objectId, cp->parentId, cp->variantType, ++ cp->hdrChunk, parent->variantType)); ++ return 0; ++ } ++ yaffs_AddObjectToDirectory(parent, obj); ++ } ++ ++ obj->hdrChunk = cp->hdrChunk; ++ obj->variantType = cp->variantType; ++ obj->deleted = cp->deleted; ++ obj->softDeleted = cp->softDeleted; ++ obj->unlinked = cp->unlinked; ++ obj->fake = cp->fake; ++ obj->renameAllowed = cp->renameAllowed; ++ obj->unlinkAllowed = cp->unlinkAllowed; ++ obj->serial = cp->serial; ++ obj->nDataChunks = cp->nDataChunks; ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; ++ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) ++ obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; ++ ++ if (obj->hdrChunk > 0) ++ obj->lazyLoaded = 1; ++ return 1; ++} ++ ++ ++ ++static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn, ++ __u32 level, int chunkOffset) ++{ ++ int i; ++ yaffs_Device *dev = in->myDev; ++ int ok = 1; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ ++ if (tn) { ++ if (level > 0) { ++ ++ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { ++ if (tn->internal[i]) { ++ ok = yaffs_CheckpointTnodeWorker(in, ++ tn->internal[i], ++ level - 1, ++ (chunkOffset<variantType == YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs_CheckpointTnodeWorker(obj, ++ obj->variant.fileVariant.top, ++ obj->variant.fileVariant.topLevel, ++ 0); ++ if (ok) ++ ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) == ++ sizeof(endMarker)); ++ } ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) ++{ ++ __u32 baseChunk; ++ int ok = 1; ++ yaffs_Device *dev = obj->myDev; ++ yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; ++ yaffs_Tnode *tn; ++ int nread = 0; ++ int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; ++ ++ if (tnodeSize < sizeof(yaffs_Tnode)) ++ tnodeSize = sizeof(yaffs_Tnode); ++ ++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); ++ ++ while (ok && (~baseChunk)) { ++ nread++; ++ /* Read level 0 tnode */ ++ ++ ++ tn = yaffs_GetTnodeRaw(dev); ++ if (tn) ++ ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize); ++ else ++ ok = 0; ++ ++ if (tn && ok) ++ ok = yaffs_AddOrFindLevel0Tnode(dev, ++ fileStructPtr, ++ baseChunk, ++ tn) ? 1 : 0; ++ ++ if (ok) ++ ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); ++ ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, ( ++ TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), ++ nread, baseChunk, ok)); ++ ++ return ok ? 1 : 0; ++} ++ ++ ++static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ yaffs_CheckpointObject cp; ++ int i; ++ int ok = 1; ++ struct ylist_head *lh; ++ ++ ++ /* Iterate through the objects in each hash entry, ++ * dumping them to the checkpointing stream. ++ */ ++ ++ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { ++ ylist_for_each(lh, &dev->objectBucket[i].list) { ++ if (lh) { ++ obj = ylist_entry(lh, yaffs_Object, hashLink); ++ if (!obj->deferedFree) { ++ yaffs_ObjectToCheckpointObject(&cp, obj); ++ cp.structType = sizeof(cp); ++ ++ T(YAFFS_TRACE_CHECKPOINT, ( ++ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), ++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj)); ++ ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ ok = yaffs_WriteCheckpointTnodes(obj); ++ } ++ } ++ } ++ } ++ ++ /* Dump end of list */ ++ memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject)); ++ cp.structType = sizeof(cp); ++ ++ if (ok) ++ ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) ++{ ++ yaffs_Object *obj; ++ yaffs_CheckpointObject cp; ++ int ok = 1; ++ int done = 0; ++ yaffs_Object *hardList = NULL; ++ ++ while (ok && !done) { ++ ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); ++ if (cp.structType != sizeof(cp)) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), ++ cp.structType, sizeof(cp), ok)); ++ ok = 0; ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), ++ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk)); ++ ++ if (ok && cp.objectId == ~0) ++ done = 1; ++ else if (ok) { ++ obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType); ++ if (obj) { ++ ok = yaffs_CheckpointObjectToObject(obj, &cp); ++ if (!ok) ++ break; ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { ++ ok = yaffs_ReadCheckpointTnodes(obj); ++ } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ obj->hardLinks.next = ++ (struct ylist_head *) hardList; ++ hardList = obj; ++ } ++ } else ++ ok = 0; ++ } ++ } ++ ++ if (ok) ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ return ok ? 1 : 0; ++} ++ ++static int yaffs_WriteCheckpointSum(yaffs_Device *dev) ++{ ++ __u32 checkpointSum; ++ int ok; ++ ++ yaffs_GetCheckpointSum(dev, &checkpointSum); ++ ++ ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum)); ++ ++ if (!ok) ++ return 0; ++ ++ return 1; ++} ++ ++static int yaffs_ReadCheckpointSum(yaffs_Device *dev) ++{ ++ __u32 checkpointSum0; ++ __u32 checkpointSum1; ++ int ok; ++ ++ yaffs_GetCheckpointSum(dev, &checkpointSum0); ++ ++ ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1)); ++ ++ if (!ok) ++ return 0; ++ ++ if (checkpointSum0 != checkpointSum1) ++ return 0; ++ ++ return 1; ++} ++ ++ ++static int yaffs_WriteCheckpointData(yaffs_Device *dev) ++{ ++ int ok = 1; ++ ++ if (dev->skipCheckpointWrite || !dev->isYaffs2) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs_CheckpointOpen(dev, 1); ++ ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); ++ ok = yaffs_WriteCheckpointValidityMarker(dev, 1); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); ++ ok = yaffs_WriteCheckpointDevice(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); ++ ok = yaffs_WriteCheckpointObjects(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); ++ ok = yaffs_WriteCheckpointValidityMarker(dev, 0); ++ } ++ ++ if (ok) ++ ok = yaffs_WriteCheckpointSum(dev); ++ ++ if (!yaffs_CheckpointClose(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->isCheckpointed = 1; ++ else ++ dev->isCheckpointed = 0; ++ ++ return dev->isCheckpointed; ++} ++ ++static int yaffs_ReadCheckpointData(yaffs_Device *dev) ++{ ++ int ok = 1; ++ ++ if (dev->skipCheckpointRead || !dev->isYaffs2) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); ++ ok = 0; ++ } ++ ++ if (ok) ++ ok = yaffs_CheckpointOpen(dev, 0); /* open for read */ ++ ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); ++ ok = yaffs_ReadCheckpointValidityMarker(dev, 1); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); ++ ok = yaffs_ReadCheckpointDevice(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); ++ ok = yaffs_ReadCheckpointObjects(dev); ++ } ++ if (ok) { ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); ++ ok = yaffs_ReadCheckpointValidityMarker(dev, 0); ++ } ++ ++ if (ok) { ++ ok = yaffs_ReadCheckpointSum(dev); ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); ++ } ++ ++ if (!yaffs_CheckpointClose(dev)) ++ ok = 0; ++ ++ if (ok) ++ dev->isCheckpointed = 1; ++ else ++ dev->isCheckpointed = 0; ++ ++ return ok ? 1 : 0; ++ ++} ++ ++static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) ++{ ++ if (dev->isCheckpointed || ++ dev->blocksInCheckpoint > 0) { ++ dev->isCheckpointed = 0; ++ yaffs_CheckpointInvalidateStream(dev); ++ if (dev->superBlock && dev->markSuperBlockDirty) ++ dev->markSuperBlockDirty(dev->superBlock); ++ } ++} ++ ++ ++int yaffs_CheckpointSave(yaffs_Device *dev) ++{ ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ yaffs_VerifyObjects(dev); ++ yaffs_VerifyBlocks(dev); ++ yaffs_VerifyFreeChunks(dev); ++ ++ if (!dev->isCheckpointed) { ++ yaffs_InvalidateCheckpoint(dev); ++ yaffs_WriteCheckpointData(dev); ++ } ++ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ return dev->isCheckpointed; ++} ++ ++int yaffs_CheckpointRestore(yaffs_Device *dev) ++{ ++ int retval; ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ retval = yaffs_ReadCheckpointData(dev); ++ ++ if (dev->isCheckpointed) { ++ yaffs_VerifyObjects(dev); ++ yaffs_VerifyBlocks(dev); ++ yaffs_VerifyFreeChunks(dev); ++ } ++ ++ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); ++ ++ return retval; ++} ++ ++/*--------------------- File read/write ------------------------ ++ * Read and write have very similar structures. ++ * In general the read/write has three parts to it ++ * An incomplete chunk to start with (if the read/write is not chunk-aligned) ++ * Some complete chunks ++ * An incomplete chunk to end off with ++ * ++ * Curve-balls: the first chunk might also be the last chunk. ++ */ ++ ++int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, ++ int nBytes) ++{ ++ ++ int chunk; ++ __u32 start; ++ int nToCopy; ++ int n = nBytes; ++ int nDone = 0; ++ yaffs_ChunkCache *cache; ++ ++ yaffs_Device *dev; ++ ++ dev = in->myDev; ++ ++ while (n > 0) { ++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */ ++ /* start = offset % dev->nDataBytesPerChunk; */ ++ yaffs_AddrToChunk(dev, offset, &chunk, &start); ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ if ((start + n) < dev->nDataBytesPerChunk) ++ nToCopy = n; ++ else ++ nToCopy = dev->nDataBytesPerChunk - start; ++ ++ cache = yaffs_FindChunkCache(in, chunk); ++ ++ /* If the chunk is already in the cache or it is less than a whole chunk ++ * or we're using inband tags then use the cache (if there is caching) ++ * else bypass the cache. ++ */ ++ if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { ++ if (dev->nShortOpCaches > 0) { ++ ++ /* If we can't find the data in the cache, then load it up. */ ++ ++ if (!cache) { ++ cache = yaffs_GrabChunkCache(in->myDev); ++ cache->object = in; ++ cache->chunkId = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ cache-> ++ data); ++ cache->nBytes = 0; ++ } ++ ++ yaffs_UseChunkCache(dev, cache, 0); ++ ++ cache->locked = 1; ++ ++ ++ memcpy(buffer, &cache->data[start], nToCopy); ++ ++ cache->locked = 0; ++ } else { ++ /* Read into the local buffer then copy..*/ ++ ++ __u8 *localBuffer = ++ yaffs_GetTempBuffer(dev, __LINE__); ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ localBuffer); ++ ++ memcpy(buffer, &localBuffer[start], nToCopy); ++ ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, ++ __LINE__); ++ } ++ ++ } else { ++ ++ /* A full chunk. Read directly into the supplied buffer. */ ++ yaffs_ReadChunkDataFromObject(in, chunk, buffer); ++ ++ } ++ ++ n -= nToCopy; ++ offset += nToCopy; ++ buffer += nToCopy; ++ nDone += nToCopy; ++ ++ } ++ ++ return nDone; ++} ++ ++int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, ++ int nBytes, int writeThrough) ++{ ++ ++ int chunk; ++ __u32 start; ++ int nToCopy; ++ int n = nBytes; ++ int nDone = 0; ++ int nToWriteBack; ++ int startOfWrite = offset; ++ int chunkWritten = 0; ++ __u32 nBytesRead; ++ __u32 chunkStart; ++ ++ yaffs_Device *dev; ++ ++ dev = in->myDev; ++ ++ while (n > 0 && chunkWritten >= 0) { ++ /* chunk = offset / dev->nDataBytesPerChunk + 1; */ ++ /* start = offset % dev->nDataBytesPerChunk; */ ++ yaffs_AddrToChunk(dev, offset, &chunk, &start); ++ ++ if (chunk * dev->nDataBytesPerChunk + start != offset || ++ start >= dev->nDataBytesPerChunk) { ++ T(YAFFS_TRACE_ERROR, ( ++ TSTR("AddrToChunk of offset %d gives chunk %d start %d" ++ TENDSTR), ++ (int)offset, chunk, start)); ++ } ++ chunk++; ++ ++ /* OK now check for the curveball where the start and end are in ++ * the same chunk. ++ */ ++ ++ if ((start + n) < dev->nDataBytesPerChunk) { ++ nToCopy = n; ++ ++ /* Now folks, to calculate how many bytes to write back.... ++ * If we're overwriting and not writing to then end of file then ++ * we need to write back as much as was there before. ++ */ ++ ++ chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk); ++ ++ if (chunkStart > in->variant.fileVariant.fileSize) ++ nBytesRead = 0; /* Past end of file */ ++ else ++ nBytesRead = in->variant.fileVariant.fileSize - chunkStart; ++ ++ if (nBytesRead > dev->nDataBytesPerChunk) ++ nBytesRead = dev->nDataBytesPerChunk; ++ ++ nToWriteBack = ++ (nBytesRead > ++ (start + n)) ? nBytesRead : (start + n); ++ ++ if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk) ++ YBUG(); ++ ++ } else { ++ nToCopy = dev->nDataBytesPerChunk - start; ++ nToWriteBack = dev->nDataBytesPerChunk; ++ } ++ ++ if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { ++ /* An incomplete start or end chunk (or maybe both start and end chunk), ++ * or we're using inband tags, so we want to use the cache buffers. ++ */ ++ if (dev->nShortOpCaches > 0) { ++ yaffs_ChunkCache *cache; ++ /* If we can't find the data in the cache, then load the cache */ ++ cache = yaffs_FindChunkCache(in, chunk); ++ ++ if (!cache ++ && yaffs_CheckSpaceForAllocation(in-> ++ myDev)) { ++ cache = yaffs_GrabChunkCache(in->myDev); ++ cache->object = in; ++ cache->chunkId = chunk; ++ cache->dirty = 0; ++ cache->locked = 0; ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ cache-> ++ data); ++ } else if (cache && ++ !cache->dirty && ++ !yaffs_CheckSpaceForAllocation(in->myDev)) { ++ /* Drop the cache if it was a read cache item and ++ * no space check has been made for it. ++ */ ++ cache = NULL; ++ } ++ ++ if (cache) { ++ yaffs_UseChunkCache(dev, cache, 1); ++ cache->locked = 1; ++ ++ ++ memcpy(&cache->data[start], buffer, ++ nToCopy); ++ ++ ++ cache->locked = 0; ++ cache->nBytes = nToWriteBack; ++ ++ if (writeThrough) { ++ chunkWritten = ++ yaffs_WriteChunkDataToObject ++ (cache->object, ++ cache->chunkId, ++ cache->data, cache->nBytes, ++ 1); ++ cache->dirty = 0; ++ } ++ ++ } else { ++ chunkWritten = -1; /* fail the write */ ++ } ++ } else { ++ /* An incomplete start or end chunk (or maybe both start and end chunk) ++ * Read into the local buffer then copy, then copy over and write back. ++ */ ++ ++ __u8 *localBuffer = ++ yaffs_GetTempBuffer(dev, __LINE__); ++ ++ yaffs_ReadChunkDataFromObject(in, chunk, ++ localBuffer); ++ ++ ++ ++ memcpy(&localBuffer[start], buffer, nToCopy); ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(in, chunk, ++ localBuffer, ++ nToWriteBack, ++ 0); ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, ++ __LINE__); ++ ++ } ++ ++ } else { ++ /* A full chunk. Write directly from the supplied buffer. */ ++ ++ ++ ++ chunkWritten = ++ yaffs_WriteChunkDataToObject(in, chunk, buffer, ++ dev->nDataBytesPerChunk, ++ 0); ++ ++ /* Since we've overwritten the cached data, we better invalidate it. */ ++ yaffs_InvalidateChunkCache(in, chunk); ++ } ++ ++ if (chunkWritten >= 0) { ++ n -= nToCopy; ++ offset += nToCopy; ++ buffer += nToCopy; ++ nDone += nToCopy; ++ } ++ ++ } ++ ++ /* Update file object */ ++ ++ if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) ++ in->variant.fileVariant.fileSize = (startOfWrite + nDone); ++ ++ in->dirty = 1; ++ ++ return nDone; ++} ++ ++ ++/* ---------------------- File resizing stuff ------------------ */ ++ ++static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) ++{ ++ ++ yaffs_Device *dev = in->myDev; ++ int oldFileSize = in->variant.fileVariant.fileSize; ++ ++ int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk; ++ ++ int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) / ++ dev->nDataBytesPerChunk; ++ int i; ++ int chunkId; ++ ++ /* Delete backwards so that we don't end up with holes if ++ * power is lost part-way through the operation. ++ */ ++ for (i = lastDel; i >= startDel; i--) { ++ /* NB this could be optimised somewhat, ++ * eg. could retrieve the tags and write them without ++ * using yaffs_DeleteChunk ++ */ ++ ++ chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); ++ if (chunkId > 0) { ++ if (chunkId < ++ (dev->internalStartBlock * dev->nChunksPerBlock) ++ || chunkId >= ++ ((dev->internalEndBlock + ++ 1) * dev->nChunksPerBlock)) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Found daft chunkId %d for %d" TENDSTR), ++ chunkId, i)); ++ } else { ++ in->nDataChunks--; ++ yaffs_DeleteChunk(dev, chunkId, 1, __LINE__); ++ } ++ } ++ } ++ ++} ++ ++int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) ++{ ++ ++ int oldFileSize = in->variant.fileVariant.fileSize; ++ __u32 newSizeOfPartialChunk; ++ int newFullChunks; ++ ++ yaffs_Device *dev = in->myDev; ++ ++ yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); ++ ++ yaffs_FlushFilesChunkCache(in); ++ yaffs_InvalidateWholeChunkCache(in); ++ ++ yaffs_CheckGarbageCollection(dev); ++ ++ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) ++ return YAFFS_FAIL; ++ ++ if (newSize == oldFileSize) ++ return YAFFS_OK; ++ ++ if (newSize < oldFileSize) { ++ ++ yaffs_PruneResizedChunks(in, newSize); ++ ++ if (newSizeOfPartialChunk != 0) { ++ int lastChunk = 1 + newFullChunks; ++ ++ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ /* Got to read and rewrite the last chunk with its new size and zero pad */ ++ yaffs_ReadChunkDataFromObject(in, lastChunk, ++ localBuffer); ++ ++ memset(localBuffer + newSizeOfPartialChunk, 0, ++ dev->nDataBytesPerChunk - newSizeOfPartialChunk); ++ ++ yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, ++ newSizeOfPartialChunk, 1); ++ ++ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); ++ } ++ ++ in->variant.fileVariant.fileSize = newSize; ++ ++ yaffs_PruneFileStructure(dev, &in->variant.fileVariant); ++ } else { ++ /* newsSize > oldFileSize */ ++ in->variant.fileVariant.fileSize = newSize; ++ } ++ ++ ++ /* Write a new object header. ++ * show we've shrunk the file, if need be ++ * Do this only if the file is not in the deleted directories. ++ */ ++ if (in->parent && ++ in->parent->objectId != YAFFS_OBJECTID_UNLINKED && ++ in->parent->objectId != YAFFS_OBJECTID_DELETED) ++ yaffs_UpdateObjectHeader(in, NULL, 0, ++ (newSize < oldFileSize) ? 1 : 0, 0); ++ ++ return YAFFS_OK; ++} ++ ++loff_t yaffs_GetFileSize(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return obj->variant.fileVariant.fileSize; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_strlen(obj->variant.symLinkVariant.alias); ++ default: ++ return 0; ++ } ++} ++ ++ ++ ++int yaffs_FlushFile(yaffs_Object *in, int updateTime) ++{ ++ int retVal; ++ if (in->dirty) { ++ yaffs_FlushFilesChunkCache(in); ++ if (updateTime) { ++#ifdef CONFIG_YAFFS_WINCE ++ yfsd_WinFileTimeNow(in->win_mtime); ++#else ++ ++ in->yst_mtime = Y_CURRENT_TIME; ++ ++#endif ++ } ++ ++ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= ++ 0) ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ retVal = YAFFS_OK; ++ } ++ ++ return retVal; ++ ++} ++ ++static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) ++{ ++ ++ /* First off, invalidate the file's data in the cache, without flushing. */ ++ yaffs_InvalidateWholeChunkCache(in); ++ ++ if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { ++ /* Move to the unlinked directory so we have a record that it was deleted. */ ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0); ++ ++ } ++ ++ yaffs_RemoveObjectFromDirectory(in); ++ yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__); ++ in->hdrChunk = 0; ++ ++ yaffs_FreeObject(in); ++ return YAFFS_OK; ++ ++} ++ ++/* yaffs_DeleteFile deletes the whole file data ++ * and the inode associated with the file. ++ * It does not delete the links associated with the file. ++ */ ++static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) ++{ ++ ++ int retVal; ++ int immediateDeletion = 0; ++ ++#ifdef __KERNEL__ ++ if (!in->myInode) ++ immediateDeletion = 1; ++#else ++ if (in->inUse <= 0) ++ immediateDeletion = 1; ++#endif ++ ++ if (immediateDeletion) { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->deletedDir, ++ _Y("deleted"), 0, 0); ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: immediate deletion of file %d" TENDSTR), ++ in->objectId)); ++ in->deleted = 1; ++ in->myDev->nDeletedFiles++; ++ if (1 || in->myDev->isYaffs2) ++ yaffs_ResizeFile(in, 0); ++ yaffs_SoftDeleteFile(in); ++ } else { ++ retVal = ++ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, ++ _Y("unlinked"), 0, 0); ++ } ++ ++ ++ return retVal; ++} ++ ++int yaffs_DeleteFile(yaffs_Object *in) ++{ ++ int retVal = YAFFS_OK; ++ int deleted = in->deleted; ++ ++ yaffs_ResizeFile(in, 0); ++ ++ if (in->nDataChunks > 0) { ++ /* Use soft deletion if there is data in the file. ++ * That won't be the case if it has been resized to zero. ++ */ ++ if (!in->unlinked) ++ retVal = yaffs_UnlinkFileIfNeeded(in); ++ ++ if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { ++ in->deleted = 1; ++ deleted = 1; ++ in->myDev->nDeletedFiles++; ++ yaffs_SoftDeleteFile(in); ++ } ++ return deleted ? YAFFS_OK : YAFFS_FAIL; ++ } else { ++ /* The file has no data chunks so we toss it immediately */ ++ yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); ++ in->variant.fileVariant.top = NULL; ++ yaffs_DoGenericObjectDeletion(in); ++ ++ return YAFFS_OK; ++ } ++} ++ ++static int yaffs_DeleteDirectory(yaffs_Object *in) ++{ ++ /* First check that the directory is empty. */ ++ if (ylist_empty(&in->variant.directoryVariant.children)) ++ return yaffs_DoGenericObjectDeletion(in); ++ ++ return YAFFS_FAIL; ++ ++} ++ ++static int yaffs_DeleteSymLink(yaffs_Object *in) ++{ ++ YFREE(in->variant.symLinkVariant.alias); ++ ++ return yaffs_DoGenericObjectDeletion(in); ++} ++ ++static int yaffs_DeleteHardLink(yaffs_Object *in) ++{ ++ /* remove this hardlink from the list assocaited with the equivalent ++ * object ++ */ ++ ylist_del_init(&in->hardLinks); ++ return yaffs_DoGenericObjectDeletion(in); ++} ++ ++int yaffs_DeleteObject(yaffs_Object *obj) ++{ ++int retVal = -1; ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ retVal = yaffs_DeleteFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return yaffs_DeleteDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ retVal = yaffs_DeleteSymLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ retVal = yaffs_DeleteHardLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ retVal = yaffs_DoGenericObjectDeletion(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ retVal = 0; ++ break; /* should not happen. */ ++ } ++ ++ return retVal; ++} ++ ++static int yaffs_UnlinkWorker(yaffs_Object *obj) ++{ ++ ++ int immediateDeletion = 0; ++ ++#ifdef __KERNEL__ ++ if (!obj->myInode) ++ immediateDeletion = 1; ++#else ++ if (obj->inUse <= 0) ++ immediateDeletion = 1; ++#endif ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ return yaffs_DeleteHardLink(obj); ++ } else if (!ylist_empty(&obj->hardLinks)) { ++ /* Curve ball: We're unlinking an object that has a hardlink. ++ * ++ * This problem arises because we are not strictly following ++ * The Linux link/inode model. ++ * ++ * We can't really delete the object. ++ * Instead, we do the following: ++ * - Select a hardlink. ++ * - Unhook it from the hard links ++ * - Unhook it from its parent directory (so that the rename can work) ++ * - Rename the object to the hardlink's name. ++ * - Delete the hardlink ++ */ ++ ++ yaffs_Object *hl; ++ int retVal; ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); ++ ++ ylist_del_init(&hl->hardLinks); ++ ylist_del_init(&hl->siblings); ++ ++ yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); ++ ++ retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); ++ ++ if (retVal == YAFFS_OK) ++ retVal = yaffs_DoGenericObjectDeletion(hl); ++ ++ return retVal; ++ ++ } else if (immediateDeletion) { ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return yaffs_DeleteFile(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return yaffs_DeleteDirectory(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return yaffs_DeleteSymLink(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ return yaffs_DoGenericObjectDeletion(obj); ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ default: ++ return YAFFS_FAIL; ++ } ++ } else ++ return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir, ++ _Y("unlinked"), 0, 0); ++} ++ ++ ++static int yaffs_UnlinkObject(yaffs_Object *obj) ++{ ++ ++ if (obj && obj->unlinkAllowed) ++ return yaffs_UnlinkWorker(obj); ++ ++ return YAFFS_FAIL; ++ ++} ++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) ++{ ++ yaffs_Object *obj; ++ ++ obj = yaffs_FindObjectByName(dir, name); ++ return yaffs_UnlinkObject(obj); ++} ++ ++/*----------------------- Initialisation Scanning ---------------------- */ ++ ++static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, ++ int backwardScanning) ++{ ++ yaffs_Object *obj; ++ ++ if (!backwardScanning) { ++ /* Handle YAFFS1 forward scanning case ++ * For YAFFS1 we always do the deletion ++ */ ++ ++ } else { ++ /* Handle YAFFS2 case (backward scanning) ++ * If the shadowed object exists then ignore. ++ */ ++ if (yaffs_FindObjectByNumber(dev, objId)) ++ return; ++ } ++ ++ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. ++ * We put it in unlinked dir to be cleaned up after the scanning ++ */ ++ obj = ++ yaffs_FindOrCreateObjectByNumber(dev, objId, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!obj) ++ return; ++ yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); ++ obj->variant.fileVariant.shrinkSize = 0; ++ obj->valid = 1; /* So that we don't read any other info for this file */ ++ ++} ++ ++typedef struct { ++ int seq; ++ int block; ++} yaffs_BlockIndex; ++ ++ ++static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) ++{ ++ yaffs_Object *hl; ++ yaffs_Object *in; ++ ++ while (hardList) { ++ hl = hardList; ++ hardList = (yaffs_Object *) (hardList->hardLinks.next); ++ ++ in = yaffs_FindObjectByNumber(dev, ++ hl->variant.hardLinkVariant. ++ equivalentObjectId); ++ ++ if (in) { ++ /* Add the hardlink pointers */ ++ hl->variant.hardLinkVariant.equivalentObject = in; ++ ylist_add(&hl->hardLinks, &in->hardLinks); ++ } else { ++ /* Todo Need to report/handle this better. ++ * Got a problem... hardlink to a non-existant object ++ */ ++ hl->variant.hardLinkVariant.equivalentObject = NULL; ++ YINIT_LIST_HEAD(&hl->hardLinks); ++ ++ } ++ } ++} ++ ++ ++ ++ ++ ++static int ybicmp(const void *a, const void *b) ++{ ++ register int aseq = ((yaffs_BlockIndex *)a)->seq; ++ register int bseq = ((yaffs_BlockIndex *)b)->seq; ++ register int ablock = ((yaffs_BlockIndex *)a)->block; ++ register int bblock = ((yaffs_BlockIndex *)b)->block; ++ if (aseq == bseq) ++ return ablock - bblock; ++ else ++ return aseq - bseq; ++} ++ ++ ++struct yaffs_ShadowFixerStruct { ++ int objectId; ++ int shadowedId; ++ struct yaffs_ShadowFixerStruct *next; ++}; ++ ++ ++static void yaffs_StripDeletedObjects(yaffs_Device *dev) ++{ ++ /* ++ * Sort out state of unlinked and deleted objects after scanning. ++ */ ++ struct ylist_head *i; ++ struct ylist_head *n; ++ yaffs_Object *l; ++ ++ /* Soft delete all the unlinked files */ ++ ylist_for_each_safe(i, n, ++ &dev->unlinkedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DeleteObject(l); ++ } ++ } ++ ++ ylist_for_each_safe(i, n, ++ &dev->deletedDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ yaffs_DeleteObject(l); ++ } ++ } ++ ++} ++ ++static int yaffs_Scan(yaffs_Device *dev) ++{ ++ yaffs_ExtendedTags tags; ++ int blk; ++ int blockIterator; ++ int startIterator; ++ int endIterator; ++ int result; ++ ++ int chunk; ++ int c; ++ int deleted; ++ yaffs_BlockState state; ++ yaffs_Object *hardList = NULL; ++ yaffs_BlockInfo *bi; ++ __u32 sequenceNumber; ++ yaffs_ObjectHeader *oh; ++ yaffs_Object *in; ++ yaffs_Object *parent; ++ ++ int alloc_failed = 0; ++ ++ struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; ++ ++ ++ __u8 *chunkData; ++ ++ ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), ++ dev->internalStartBlock, dev->internalEndBlock)); ++ ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ /* Scan all the blocks to determine their state */ ++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { ++ bi = yaffs_GetBlockInfo(dev, blk); ++ yaffs_ClearChunkBits(dev, blk); ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ ++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); ++ ++ bi->blockState = state; ++ bi->sequenceNumber = sequenceNumber; ++ ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, ++ state, sequenceNumber)); ++ ++ if (state == YAFFS_BLOCK_STATE_DEAD) { ++ T(YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("block %d is bad" TENDSTR), blk)); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block empty " TENDSTR))); ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } ++ } ++ ++ startIterator = dev->internalStartBlock; ++ endIterator = dev->internalEndBlock; ++ ++ /* For each block.... */ ++ for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; ++ blockIterator++) { ++ ++ YYIELD(); ++ ++ YYIELD(); ++ ++ blk = blockIterator; ++ ++ bi = yaffs_GetBlockInfo(dev, blk); ++ state = bi->blockState; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning....*/ ++ for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && ++ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { ++ /* Read the tags and decide what to do */ ++ chunk = blk * dev->nChunksPerBlock + c; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, ++ &tags); ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { ++ /* YAFFS1 only... ++ * A deleted chunk ++ */ ++ deleted++; ++ dev->nFreeChunks++; ++ /*T((" %d %d deleted\n",blk,c)); */ ++ } else if (!tags.chunkUsed) { ++ /* An unassigned chunk in the block ++ * This means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (c == 0) { ++ /* We're looking at the first chunk in the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ } else { ++ /* this is the block being allocated from */ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ (" Allocating from %d %d" TENDSTR), ++ blk, c)); ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->allocationBlock = blk; ++ dev->allocationPage = c; ++ dev->allocationBlockFinder = blk; ++ /* Set it to here to encourage the allocator to go forth from here. */ ++ ++ } ++ ++ dev->nFreeChunks += (dev->nChunksPerBlock - c); ++ } else if (tags.chunkId > 0) { ++ /* chunkId > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ YAFFS_OBJECT_TYPE_FILE); ++ /* PutChunkIntoFile checks for a clash (two data chunks with ++ * the same chunkId). ++ */ ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in) { ++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) ++ alloc_failed = 1; ++ } ++ ++ endpos = ++ (tags.chunkId - 1) * dev->nDataBytesPerChunk + ++ tags.byteCount; ++ if (in && ++ in->variantType == YAFFS_OBJECT_TYPE_FILE ++ && in->variant.fileVariant.scannedFileSize < ++ endpos) { ++ in->variant.fileVariant. ++ scannedFileSize = endpos; ++ if (!dev->useHeaderFileSize) { ++ in->variant.fileVariant. ++ fileSize = ++ in->variant.fileVariant. ++ scannedFileSize; ++ } ++ ++ } ++ /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ ++ } else { ++ /* chunkId == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make the object ++ */ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, ++ chunkData, ++ NULL); ++ ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ in = yaffs_FindObjectByNumber(dev, ++ tags.objectId); ++ if (in && in->variantType != oh->type) { ++ /* This should not happen, but somehow ++ * Wev'e ended up with an objectId that has been reused but not yet ++ * deleted, and worse still it has changed type. Delete the old object. ++ */ ++ ++ yaffs_DeleteObject(in); ++ ++ in = 0; ++ } ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ oh->type); ++ ++ if (!in) ++ alloc_failed = 1; ++ ++ if (in && oh->shadowsObject > 0) { ++ ++ struct yaffs_ShadowFixerStruct *fixer; ++ fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct)); ++ if (fixer) { ++ fixer->next = shadowFixerList; ++ shadowFixerList = fixer; ++ fixer->objectId = tags.objectId; ++ fixer->shadowedId = oh->shadowsObject; ++ } ++ ++ } ++ ++ if (in && in->valid) { ++ /* We have already filled this one. We have a duplicate and need to resolve it. */ ++ ++ unsigned existingSerial = in->serial; ++ unsigned newSerial = tags.serialNumber; ++ ++ if (((existingSerial + 1) & 3) == newSerial) { ++ /* Use new one - destroy the exisiting one */ ++ yaffs_DeleteChunk(dev, ++ in->hdrChunk, ++ 1, __LINE__); ++ in->valid = 0; ++ } else { ++ /* Use existing - destroy this one. */ ++ yaffs_DeleteChunk(dev, chunk, 1, ++ __LINE__); ++ } ++ } ++ ++ if (in && !in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle with directory structure */ ++ in->valid = 1; ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; ++ ++ } else if (in && !in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ in->hdrChunk = chunk; ++ in->serial = tags.serialNumber; ++ ++ yaffs_SetObjectName(in, oh->name); ++ in->dirty = 0; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, oh->parentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ if (!parent) ++ alloc_failed = 1; ++ if (parent && parent->variantType == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (!parent || parent->variantType != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * We're trying to use a non-directory as a directory ++ */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ TENDSTR))); ++ parent = dev->lostNFoundDir; ++ } ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ if (0 && (parent == dev->deletedDir || ++ parent == dev->unlinkedDir)) { ++ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ ++ dev->nDeletedFiles++; ++ } ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent object is scanned ++ * we put them all in a list. ++ * After scanning is complete, we should have all the objects, so we run through this ++ * list and fix up all the chains. ++ */ ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ if (dev->useHeaderFileSize) ++ ++ in->variant.fileVariant. ++ fileSize = ++ oh->fileSize; ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ in->variant.hardLinkVariant. ++ equivalentObjectId = ++ oh->equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) ++ hardList; ++ hardList = in; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; ++ break; ++ } ++ ++/* ++ if (parent == dev->deletedDir) { ++ yaffs_DestroyObject(in); ++ bi->hasShrinkHeader = 1; ++ } ++*/ ++ } ++ } ++ } ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ /* If we got this far while scanning, then the block is fully allocated.*/ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ bi->blockState = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_BlockBecameDirty(dev, blk); ++ } ++ ++ } ++ ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ /* Fix up any shadowed objects */ ++ { ++ struct yaffs_ShadowFixerStruct *fixer; ++ yaffs_Object *obj; ++ ++ while (shadowFixerList) { ++ fixer = shadowFixerList; ++ shadowFixerList = fixer->next; ++ /* Complete the rename transaction by deleting the shadowed object ++ * then setting the object header to unshadowed. ++ */ ++ obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId); ++ if (obj) ++ yaffs_DeleteObject(obj); ++ ++ obj = yaffs_FindObjectByNumber(dev, fixer->objectId); ++ ++ if (obj) ++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); ++ ++ YFREE(fixer); ++ } ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); ++ ++ ++ return YAFFS_OK; ++} ++ ++static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) ++{ ++ __u8 *chunkData; ++ yaffs_ObjectHeader *oh; ++ yaffs_Device *dev; ++ yaffs_ExtendedTags tags; ++ int result; ++ int alloc_failed = 0; ++ ++ if (!in) ++ return; ++ ++ dev = in->myDev; ++ ++#if 0 ++ T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR), ++ in->objectId, ++ in->lazyLoaded ? "not yet" : "already")); ++#endif ++ ++ if (in->lazyLoaded && in->hdrChunk > 0) { ++ in->lazyLoaded = 0; ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags); ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++ ++#endif ++ yaffs_SetObjectName(in, oh->name); ++ ++ if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; /* Not returned to caller */ ++ } ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ } ++} ++ ++static int yaffs_ScanBackwards(yaffs_Device *dev) ++{ ++ yaffs_ExtendedTags tags; ++ int blk; ++ int blockIterator; ++ int startIterator; ++ int endIterator; ++ int nBlocksToScan = 0; ++ ++ int chunk; ++ int result; ++ int c; ++ int deleted; ++ yaffs_BlockState state; ++ yaffs_Object *hardList = NULL; ++ yaffs_BlockInfo *bi; ++ __u32 sequenceNumber; ++ yaffs_ObjectHeader *oh; ++ yaffs_Object *in; ++ yaffs_Object *parent; ++ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; ++ int itsUnlinked; ++ __u8 *chunkData; ++ ++ int fileSize; ++ int isShrink; ++ int foundChunksInBlock; ++ int equivalentObjectId; ++ int alloc_failed = 0; ++ ++ ++ yaffs_BlockIndex *blockIndex = NULL; ++ int altBlockIndex = 0; ++ ++ if (!dev->isYaffs2) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." ++ TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); ++ ++ ++ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; ++ ++ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); ++ ++ if (!blockIndex) { ++ blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); ++ altBlockIndex = 1; ++ } ++ ++ if (!blockIndex) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ dev->blocksInCheckpoint = 0; ++ ++ chunkData = yaffs_GetTempBuffer(dev, __LINE__); ++ ++ /* Scan all the blocks to determine their state */ ++ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { ++ bi = yaffs_GetBlockInfo(dev, blk); ++ yaffs_ClearChunkBits(dev, blk); ++ bi->pagesInUse = 0; ++ bi->softDeletions = 0; ++ ++ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); ++ ++ bi->blockState = state; ++ bi->sequenceNumber = sequenceNumber; ++ ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) ++ bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; ++ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) ++ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; ++ ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, ++ state, sequenceNumber)); ++ ++ ++ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { ++ dev->blocksInCheckpoint++; ++ ++ } else if (state == YAFFS_BLOCK_STATE_DEAD) { ++ T(YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("block %d is bad" TENDSTR), blk)); ++ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("Block empty " TENDSTR))); ++ dev->nErasedBlocks++; ++ dev->nFreeChunks += dev->nChunksPerBlock; ++ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ ++ /* Determine the highest sequence number */ ++ if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && ++ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { ++ ++ blockIndex[nBlocksToScan].seq = sequenceNumber; ++ blockIndex[nBlocksToScan].block = blk; ++ ++ nBlocksToScan++; ++ ++ if (sequenceNumber >= dev->sequenceNumber) ++ dev->sequenceNumber = sequenceNumber; ++ } else { ++ /* TODO: Nasty sequence number! */ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ ("Block scanning block %d has bad sequence number %d" ++ TENDSTR), blk, sequenceNumber)); ++ ++ } ++ } ++ } ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); ++ ++ ++ ++ YYIELD(); ++ ++ /* Sort the blocks */ ++#ifndef CONFIG_YAFFS_USE_OWN_SORT ++ { ++ /* Use qsort now. */ ++ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); ++ } ++#else ++ { ++ /* Dungy old bubble sort... */ ++ ++ yaffs_BlockIndex temp; ++ int i; ++ int j; ++ ++ for (i = 0; i < nBlocksToScan; i++) ++ for (j = i + 1; j < nBlocksToScan; j++) ++ if (blockIndex[i].seq > blockIndex[j].seq) { ++ temp = blockIndex[j]; ++ blockIndex[j] = blockIndex[i]; ++ blockIndex[i] = temp; ++ } ++ } ++#endif ++ ++ YYIELD(); ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); ++ ++ /* Now scan the blocks looking at the data. */ ++ startIterator = 0; ++ endIterator = nBlocksToScan - 1; ++ T(YAFFS_TRACE_SCAN_DEBUG, ++ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); ++ ++ /* For each block.... backwards */ ++ for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; ++ blockIterator--) { ++ /* Cooperative multitasking! This loop can run for so ++ long that watchdog timers expire. */ ++ YYIELD(); ++ ++ /* get the block to scan in the correct order */ ++ blk = blockIndex[blockIterator].block; ++ ++ bi = yaffs_GetBlockInfo(dev, blk); ++ ++ ++ state = bi->blockState; ++ ++ deleted = 0; ++ ++ /* For each chunk in each block that needs scanning.... */ ++ foundChunksInBlock = 0; ++ for (c = dev->nChunksPerBlock - 1; ++ !alloc_failed && c >= 0 && ++ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { ++ /* Scan backwards... ++ * Read the tags and decide what to do ++ */ ++ ++ chunk = blk * dev->nChunksPerBlock + c; ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, ++ &tags); ++ ++ /* Let's have a good look at this chunk... */ ++ ++ if (!tags.chunkUsed) { ++ /* An unassigned chunk in the block. ++ * If there are used chunks after this one, then ++ * it is a chunk that was skipped due to failing the erased ++ * check. Just skip it so that it can be deleted. ++ * But, more typically, We get here when this is an unallocated ++ * chunk and his means that either the block is empty or ++ * this is the one being allocated from ++ */ ++ ++ if (foundChunksInBlock) { ++ /* This is a chunk that was skipped due to failing the erased check */ ++ } else if (c == 0) { ++ /* We're looking at the first chunk in the block so the block is unused */ ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ dev->nErasedBlocks++; ++ } else { ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || ++ state == YAFFS_BLOCK_STATE_ALLOCATING) { ++ if (dev->sequenceNumber == bi->sequenceNumber) { ++ /* this is the block being allocated from */ ++ ++ T(YAFFS_TRACE_SCAN, ++ (TSTR ++ (" Allocating from %d %d" ++ TENDSTR), blk, c)); ++ ++ state = YAFFS_BLOCK_STATE_ALLOCATING; ++ dev->allocationBlock = blk; ++ dev->allocationPage = c; ++ dev->allocationBlockFinder = blk; ++ } else { ++ /* This is a partially written block that is not ++ * the current allocation block. This block must have ++ * had a write failure, so set up for retirement. ++ */ ++ ++ /* bi->needsRetiring = 1; ??? TODO */ ++ bi->gcPrioritise = 1; ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Partially written block %d detected" TENDSTR), ++ blk)); ++ } ++ } ++ } ++ ++ dev->nFreeChunks++; ++ ++ } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) { ++ T(YAFFS_TRACE_SCAN, ++ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), ++ blk, c)); ++ ++ dev->nFreeChunks++; ++ ++ } else if (tags.chunkId > 0) { ++ /* chunkId > 0 so it is a data chunk... */ ++ unsigned int endpos; ++ __u32 chunkBase = ++ (tags.chunkId - 1) * dev->nDataBytesPerChunk; ++ ++ foundChunksInBlock = 1; ++ ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ in = yaffs_FindOrCreateObjectByNumber(dev, ++ tags. ++ objectId, ++ YAFFS_OBJECT_TYPE_FILE); ++ if (!in) { ++ /* Out of memory */ ++ alloc_failed = 1; ++ } ++ ++ if (in && ++ in->variantType == YAFFS_OBJECT_TYPE_FILE ++ && chunkBase < ++ in->variant.fileVariant.shrinkSize) { ++ /* This has not been invalidated by a resize */ ++ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, ++ chunk, -1)) { ++ alloc_failed = 1; ++ } ++ ++ /* File size is calculated by looking at the data chunks if we have not ++ * seen an object header yet. Stop this practice once we find an object header. ++ */ ++ endpos = ++ (tags.chunkId - ++ 1) * dev->nDataBytesPerChunk + ++ tags.byteCount; ++ ++ if (!in->valid && /* have not got an object header yet */ ++ in->variant.fileVariant. ++ scannedFileSize < endpos) { ++ in->variant.fileVariant. ++ scannedFileSize = endpos; ++ in->variant.fileVariant. ++ fileSize = ++ in->variant.fileVariant. ++ scannedFileSize; ++ } ++ ++ } else if (in) { ++ /* This chunk has been invalidated by a resize, so delete */ ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ ++ } ++ } else { ++ /* chunkId == 0, so it is an ObjectHeader. ++ * Thus, we read in the object header and make the object ++ */ ++ foundChunksInBlock = 1; ++ ++ yaffs_SetChunkBit(dev, blk, c); ++ bi->pagesInUse++; ++ ++ oh = NULL; ++ in = NULL; ++ ++ if (tags.extraHeaderInfoAvailable) { ++ in = yaffs_FindOrCreateObjectByNumber ++ (dev, tags.objectId, ++ tags.extraObjectType); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ if (!in || ++#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD ++ !in->valid || ++#endif ++ tags.extraShadows || ++ (!in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) { ++ ++ /* If we don't have valid info then we need to read the chunk ++ * TODO In future we can probably defer reading the chunk and ++ * living with invalid data until needed. ++ */ ++ ++ result = yaffs_ReadChunkWithTagsFromNAND(dev, ++ chunk, ++ chunkData, ++ NULL); ++ ++ oh = (yaffs_ObjectHeader *) chunkData; ++ ++ if (dev->inbandTags) { ++ /* Fix up the header if they got corrupted by inband tags */ ++ oh->shadowsObject = oh->inbandShadowsObject; ++ oh->isShrink = oh->inbandIsShrink; ++ } ++ ++ if (!in) { ++ in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); ++ if (!in) ++ alloc_failed = 1; ++ } ++ ++ } ++ ++ if (!in) { ++ /* TODO Hoosterman we have a problem! */ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" ++ TENDSTR), tags.objectId, chunk)); ++ continue; ++ } ++ ++ if (in->valid) { ++ /* We have already filled this one. ++ * We have a duplicate that will be discarded, but ++ * we first have to suck out resize info if it is a file. ++ */ ++ ++ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && ++ ((oh && ++ oh->type == YAFFS_OBJECT_TYPE_FILE) || ++ (tags.extraHeaderInfoAvailable && ++ tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) { ++ __u32 thisSize = ++ (oh) ? oh->fileSize : tags. ++ extraFileLength; ++ __u32 parentObjectId = ++ (oh) ? oh-> ++ parentObjectId : tags. ++ extraParentObjectId; ++ ++ ++ isShrink = ++ (oh) ? oh->isShrink : tags. ++ extraIsShrinkHeader; ++ ++ /* If it is deleted (unlinked at start also means deleted) ++ * we treat the file size as being zeroed at this point. ++ */ ++ if (parentObjectId == ++ YAFFS_OBJECTID_DELETED ++ || parentObjectId == ++ YAFFS_OBJECTID_UNLINKED) { ++ thisSize = 0; ++ isShrink = 1; ++ } ++ ++ if (isShrink && ++ in->variant.fileVariant. ++ shrinkSize > thisSize) { ++ in->variant.fileVariant. ++ shrinkSize = ++ thisSize; ++ } ++ ++ if (isShrink) ++ bi->hasShrinkHeader = 1; ++ ++ } ++ /* Use existing - destroy this one. */ ++ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); ++ ++ } ++ ++ if (!in->valid && in->variantType != ++ (oh ? oh->type : tags.extraObjectType)) ++ T(YAFFS_TRACE_ERROR, ( ++ TSTR("yaffs tragedy: Bad object type, " ++ TCONT("%d != %d, for object %d at chunk ") ++ TCONT("%d during scan") ++ TENDSTR), oh ? ++ oh->type : tags.extraObjectType, ++ in->variantType, tags.objectId, ++ chunk)); ++ ++ if (!in->valid && ++ (tags.objectId == YAFFS_OBJECTID_ROOT || ++ tags.objectId == ++ YAFFS_OBJECTID_LOSTNFOUND)) { ++ /* We only load some info, don't fiddle with directory structure */ ++ in->valid = 1; ++ ++ if (oh) { ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++ ++#endif ++ } else { ++ in->variantType = tags.extraObjectType; ++ in->lazyLoaded = 1; ++ } ++ ++ in->hdrChunk = chunk; ++ ++ } else if (!in->valid) { ++ /* we need to load this info */ ++ ++ in->valid = 1; ++ in->hdrChunk = chunk; ++ ++ if (oh) { ++ in->variantType = oh->type; ++ ++ in->yst_mode = oh->yst_mode; ++#ifdef CONFIG_YAFFS_WINCE ++ in->win_atime[0] = oh->win_atime[0]; ++ in->win_ctime[0] = oh->win_ctime[0]; ++ in->win_mtime[0] = oh->win_mtime[0]; ++ in->win_atime[1] = oh->win_atime[1]; ++ in->win_ctime[1] = oh->win_ctime[1]; ++ in->win_mtime[1] = oh->win_mtime[1]; ++#else ++ in->yst_uid = oh->yst_uid; ++ in->yst_gid = oh->yst_gid; ++ in->yst_atime = oh->yst_atime; ++ in->yst_mtime = oh->yst_mtime; ++ in->yst_ctime = oh->yst_ctime; ++ in->yst_rdev = oh->yst_rdev; ++#endif ++ ++ if (oh->shadowsObject > 0) ++ yaffs_HandleShadowedObject(dev, ++ oh-> ++ shadowsObject, ++ 1); ++ ++ ++ yaffs_SetObjectName(in, oh->name); ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, oh->parentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ ++ fileSize = oh->fileSize; ++ isShrink = oh->isShrink; ++ equivalentObjectId = oh->equivalentObjectId; ++ ++ } else { ++ in->variantType = tags.extraObjectType; ++ parent = ++ yaffs_FindOrCreateObjectByNumber ++ (dev, tags.extraParentObjectId, ++ YAFFS_OBJECT_TYPE_DIRECTORY); ++ fileSize = tags.extraFileLength; ++ isShrink = tags.extraIsShrinkHeader; ++ equivalentObjectId = tags.extraEquivalentObjectId; ++ in->lazyLoaded = 1; ++ ++ } ++ in->dirty = 0; ++ ++ if (!parent) ++ alloc_failed = 1; ++ ++ /* directory stuff... ++ * hook up to parent ++ */ ++ ++ if (parent && parent->variantType == ++ YAFFS_OBJECT_TYPE_UNKNOWN) { ++ /* Set up as a directory */ ++ parent->variantType = ++ YAFFS_OBJECT_TYPE_DIRECTORY; ++ YINIT_LIST_HEAD(&parent->variant. ++ directoryVariant. ++ children); ++ } else if (!parent || parent->variantType != ++ YAFFS_OBJECT_TYPE_DIRECTORY) { ++ /* Hoosterman, another problem.... ++ * We're trying to use a non-directory as a directory ++ */ ++ ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." ++ TENDSTR))); ++ parent = dev->lostNFoundDir; ++ } ++ ++ yaffs_AddObjectToDirectory(parent, in); ++ ++ itsUnlinked = (parent == dev->deletedDir) || ++ (parent == dev->unlinkedDir); ++ ++ if (isShrink) { ++ /* Mark the block as having a shrinkHeader */ ++ bi->hasShrinkHeader = 1; ++ } ++ ++ /* Note re hardlinks. ++ * Since we might scan a hardlink before its equivalent object is scanned ++ * we put them all in a list. ++ * After scanning is complete, we should have all the objects, so we run ++ * through this list and fix up all the chains. ++ */ ++ ++ switch (in->variantType) { ++ case YAFFS_OBJECT_TYPE_UNKNOWN: ++ /* Todo got a problem */ ++ break; ++ case YAFFS_OBJECT_TYPE_FILE: ++ ++ if (in->variant.fileVariant. ++ scannedFileSize < fileSize) { ++ /* This covers the case where the file size is greater ++ * than where the data is ++ * This will happen if the file is resized to be larger ++ * than its current data extents. ++ */ ++ in->variant.fileVariant.fileSize = fileSize; ++ in->variant.fileVariant.scannedFileSize = ++ in->variant.fileVariant.fileSize; ++ } ++ ++ if (isShrink && ++ in->variant.fileVariant.shrinkSize > fileSize) { ++ in->variant.fileVariant.shrinkSize = fileSize; ++ } ++ ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ if (!itsUnlinked) { ++ in->variant.hardLinkVariant.equivalentObjectId = ++ equivalentObjectId; ++ in->hardLinks.next = ++ (struct ylist_head *) hardList; ++ hardList = in; ++ } ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ /* Do nothing */ ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ if (oh) { ++ in->variant.symLinkVariant.alias = ++ yaffs_CloneString(oh->alias); ++ if (!in->variant.symLinkVariant.alias) ++ alloc_failed = 1; ++ } ++ break; ++ } ++ ++ } ++ ++ } ++ ++ } /* End of scanning for each chunk */ ++ ++ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { ++ /* If we got this far while scanning, then the block is fully allocated. */ ++ state = YAFFS_BLOCK_STATE_FULL; ++ } ++ ++ bi->blockState = state; ++ ++ /* Now let's see if it was dirty */ ++ if (bi->pagesInUse == 0 && ++ !bi->hasShrinkHeader && ++ bi->blockState == YAFFS_BLOCK_STATE_FULL) { ++ yaffs_BlockBecameDirty(dev, blk); ++ } ++ ++ } ++ ++ if (altBlockIndex) ++ YFREE_ALT(blockIndex); ++ else ++ YFREE(blockIndex); ++ ++ /* Ok, we've done all the scanning. ++ * Fix up the hard link chains. ++ * We should now have scanned all the objects, now it's time to add these ++ * hardlinks. ++ */ ++ yaffs_HardlinkFixup(dev, hardList); ++ ++ ++ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); ++ ++ if (alloc_failed) ++ return YAFFS_FAIL; ++ ++ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); ++ ++ return YAFFS_OK; ++} ++ ++/*------------------------------ Directory Functions ----------------------------- */ ++ ++static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) ++{ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ int count = 0; ++ ++ if (!obj) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); ++ YBUG(); ++ return; ++ } ++ ++ if (yaffs_SkipVerification(obj->myDev)) ++ return; ++ ++ if (!obj->parent) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); ++ YBUG(); ++ return; ++ } ++ ++ if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ yaffs_VerifyObject(listObj); ++ if (obj == listObj) ++ count++; ++ } ++ } ++ ++ if (count != 1) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); ++ YBUG(); ++ } ++} ++ ++static void yaffs_VerifyDirectory(yaffs_Object *directory) ++{ ++ struct ylist_head *lh; ++ yaffs_Object *listObj; ++ ++ if (!directory) { ++ YBUG(); ++ return; ++ } ++ ++ if (yaffs_SkipFullVerification(directory->myDev)) ++ return; ++ ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType)); ++ YBUG(); ++ } ++ ++ /* Iterate through the objects in each hash entry */ ++ ++ ylist_for_each(lh, &directory->variant.directoryVariant.children) { ++ if (lh) { ++ listObj = ylist_entry(lh, yaffs_Object, siblings); ++ if (listObj->parent != directory) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); ++ YBUG(); ++ } ++ yaffs_VerifyObjectInDirectory(listObj); ++ } ++ } ++} ++ ++ ++static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) ++{ ++ yaffs_Device *dev = obj->myDev; ++ yaffs_Object *parent; ++ ++ yaffs_VerifyObjectInDirectory(obj); ++ parent = obj->parent; ++ ++ yaffs_VerifyDirectory(parent); ++ ++ if (dev && dev->removeObjectCallback) ++ dev->removeObjectCallback(obj); ++ ++ ++ ylist_del_init(&obj->siblings); ++ obj->parent = NULL; ++ ++ yaffs_VerifyDirectory(parent); ++} ++ ++ ++static void yaffs_AddObjectToDirectory(yaffs_Object *directory, ++ yaffs_Object *obj) ++{ ++ if (!directory) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: Trying to add an object to a null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return; ++ } ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: Trying to add an object to a non-directory" ++ TENDSTR))); ++ YBUG(); ++ } ++ ++ if (obj->siblings.prev == NULL) { ++ /* Not initialised */ ++ YBUG(); ++ } ++ ++ ++ yaffs_VerifyDirectory(directory); ++ ++ yaffs_RemoveObjectFromDirectory(obj); ++ ++ ++ /* Now add it */ ++ ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); ++ obj->parent = directory; ++ ++ if (directory == obj->myDev->unlinkedDir ++ || directory == obj->myDev->deletedDir) { ++ obj->unlinked = 1; ++ obj->myDev->nUnlinkedFiles++; ++ obj->renameAllowed = 0; ++ } ++ ++ yaffs_VerifyDirectory(directory); ++ yaffs_VerifyObjectInDirectory(obj); ++} ++ ++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory, ++ const YCHAR *name) ++{ ++ int sum; ++ ++ struct ylist_head *i; ++ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ yaffs_Object *l; ++ ++ if (!name) ++ return NULL; ++ ++ if (!directory) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return NULL; ++ } ++ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); ++ YBUG(); ++ } ++ ++ sum = yaffs_CalcNameSum(name); ++ ++ ylist_for_each(i, &directory->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ ++ if (l->parent != directory) ++ YBUG(); ++ ++ yaffs_CheckObjectDetailsLoaded(l); ++ ++ /* Special case for lost-n-found */ ++ if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { ++ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) ++ return l; ++ } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) { ++ /* LostnFound chunk called Objxxx ++ * Do a real check ++ */ ++ yaffs_GetObjectName(l, buffer, ++ YAFFS_MAX_NAME_LENGTH); ++ if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0) ++ return l; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++#if 0 ++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, ++ int (*fn) (yaffs_Object *)) ++{ ++ struct ylist_head *i; ++ yaffs_Object *l; ++ ++ if (!theDir) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: null pointer directory" ++ TENDSTR))); ++ YBUG(); ++ return YAFFS_FAIL; ++ } ++ if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); ++ YBUG(); ++ return YAFFS_FAIL; ++ } ++ ++ ylist_for_each(i, &theDir->variant.directoryVariant.children) { ++ if (i) { ++ l = ylist_entry(i, yaffs_Object, siblings); ++ if (l && !fn(l)) ++ return YAFFS_FAIL; ++ } ++ } ++ ++ return YAFFS_OK; ++ ++} ++#endif ++ ++/* GetEquivalentObject dereferences any hard links to get to the ++ * actual object. ++ */ ++ ++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) ++{ ++ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { ++ /* We want the object id of the equivalent object, not this one */ ++ obj = obj->variant.hardLinkVariant.equivalentObject; ++ yaffs_CheckObjectDetailsLoaded(obj); ++ } ++ return obj; ++} ++ ++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) ++{ ++ memset(name, 0, buffSize * sizeof(YCHAR)); ++ ++ yaffs_CheckObjectDetailsLoaded(obj); ++ ++ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { ++ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); ++ } else if (obj->hdrChunk <= 0) { ++ YCHAR locName[20]; ++ YCHAR numString[20]; ++ YCHAR *x = &numString[19]; ++ unsigned v = obj->objectId; ++ numString[19] = 0; ++ while (v > 0) { ++ x--; ++ *x = '0' + (v % 10); ++ v /= 10; ++ } ++ /* make up a name */ ++ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); ++ yaffs_strcat(locName, x); ++ yaffs_strncpy(name, locName, buffSize - 1); ++ ++ } ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ else if (obj->shortName[0]) ++ yaffs_strcpy(name, obj->shortName); ++#endif ++ else { ++ int result; ++ __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); ++ ++ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer; ++ ++ memset(buffer, 0, obj->myDev->nDataBytesPerChunk); ++ ++ if (obj->hdrChunk > 0) { ++ result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, ++ obj->hdrChunk, buffer, ++ NULL); ++ } ++ yaffs_strncpy(name, oh->name, buffSize - 1); ++ ++ yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); ++ } ++ ++ return yaffs_strlen(name); ++} ++ ++int yaffs_GetObjectFileLength(yaffs_Object *obj) ++{ ++ /* Dereference any hard linking */ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) ++ return obj->variant.fileVariant.fileSize; ++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_strlen(obj->variant.symLinkVariant.alias); ++ else { ++ /* Only a directory should drop through to here */ ++ return obj->myDev->nDataBytesPerChunk; ++ } ++} ++ ++int yaffs_GetObjectLinkCount(yaffs_Object *obj) ++{ ++ int count = 0; ++ struct ylist_head *i; ++ ++ if (!obj->unlinked) ++ count++; /* the object itself */ ++ ++ ylist_for_each(i, &obj->hardLinks) ++ count++; /* add the hard links; */ ++ ++ return count; ++} ++ ++int yaffs_GetObjectInode(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ return obj->objectId; ++} ++ ++unsigned yaffs_GetObjectType(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ ++ switch (obj->variantType) { ++ case YAFFS_OBJECT_TYPE_FILE: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_DIRECTORY: ++ return DT_DIR; ++ break; ++ case YAFFS_OBJECT_TYPE_SYMLINK: ++ return DT_LNK; ++ break; ++ case YAFFS_OBJECT_TYPE_HARDLINK: ++ return DT_REG; ++ break; ++ case YAFFS_OBJECT_TYPE_SPECIAL: ++ if (S_ISFIFO(obj->yst_mode)) ++ return DT_FIFO; ++ if (S_ISCHR(obj->yst_mode)) ++ return DT_CHR; ++ if (S_ISBLK(obj->yst_mode)) ++ return DT_BLK; ++ if (S_ISSOCK(obj->yst_mode)) ++ return DT_SOCK; ++ default: ++ return DT_REG; ++ break; ++ } ++} ++ ++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj) ++{ ++ obj = yaffs_GetEquivalentObject(obj); ++ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) ++ return yaffs_CloneString(obj->variant.symLinkVariant.alias); ++ else ++ return yaffs_CloneString(_Y("")); ++} ++ ++#ifndef CONFIG_YAFFS_WINCE ++ ++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) ++{ ++ unsigned int valid = attr->ia_valid; ++ ++ if (valid & ATTR_MODE) ++ obj->yst_mode = attr->ia_mode; ++ if (valid & ATTR_UID) ++ obj->yst_uid = attr->ia_uid; ++ if (valid & ATTR_GID) ++ obj->yst_gid = attr->ia_gid; ++ ++ if (valid & ATTR_ATIME) ++ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); ++ if (valid & ATTR_CTIME) ++ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); ++ if (valid & ATTR_MTIME) ++ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); ++ ++ if (valid & ATTR_SIZE) ++ yaffs_ResizeFile(obj, attr->ia_size); ++ ++ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); ++ ++ return YAFFS_OK; ++ ++} ++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) ++{ ++ unsigned int valid = 0; ++ ++ attr->ia_mode = obj->yst_mode; ++ valid |= ATTR_MODE; ++ attr->ia_uid = obj->yst_uid; ++ valid |= ATTR_UID; ++ attr->ia_gid = obj->yst_gid; ++ valid |= ATTR_GID; ++ ++ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; ++ valid |= ATTR_ATIME; ++ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; ++ valid |= ATTR_CTIME; ++ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; ++ valid |= ATTR_MTIME; ++ ++ attr->ia_size = yaffs_GetFileSize(obj); ++ valid |= ATTR_SIZE; ++ ++ attr->ia_valid = valid; ++ ++ return YAFFS_OK; ++} ++ ++#endif ++ ++#if 0 ++int yaffs_DumpObject(yaffs_Object *obj) ++{ ++ YCHAR name[257]; ++ ++ yaffs_GetObjectName(obj, name, 256); ++ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" ++ " chunk %d type %d size %d\n" ++ TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, ++ obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk, ++ yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); ++ ++ return YAFFS_OK; ++} ++#endif ++ ++/*---------------------------- Initialisation code -------------------------------------- */ ++ ++static int yaffs_CheckDevFunctions(const yaffs_Device *dev) ++{ ++ ++ /* Common functions, gotta have */ ++ if (!dev->eraseBlockInNAND || !dev->initialiseNAND) ++ return 0; ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ ++ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ ++ if (dev->writeChunkWithTagsToNAND && ++ dev->readChunkWithTagsFromNAND && ++ !dev->writeChunkToNAND && ++ !dev->readChunkFromNAND && ++ dev->markNANDBlockBad && dev->queryNANDBlock) ++ return 1; ++#endif ++ ++ /* Can use the "spare" style interface for yaffs1 */ ++ if (!dev->isYaffs2 && ++ !dev->writeChunkWithTagsToNAND && ++ !dev->readChunkWithTagsFromNAND && ++ dev->writeChunkToNAND && ++ dev->readChunkFromNAND && ++ !dev->markNANDBlockBad && !dev->queryNANDBlock) ++ return 1; ++ ++ return 0; /* bad */ ++} ++ ++ ++static int yaffs_CreateInitialDirectories(yaffs_Device *dev) ++{ ++ /* Initialise the unlinked, deleted, root and lost and found directories */ ++ ++ dev->lostNFoundDir = dev->rootDir = NULL; ++ dev->unlinkedDir = dev->deletedDir = NULL; ++ ++ dev->unlinkedDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); ++ ++ dev->deletedDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); ++ ++ dev->rootDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT, ++ YAFFS_ROOT_MODE | S_IFDIR); ++ dev->lostNFoundDir = ++ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, ++ YAFFS_LOSTNFOUND_MODE | S_IFDIR); ++ ++ if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) { ++ yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); ++ return YAFFS_OK; ++ } ++ ++ return YAFFS_FAIL; ++} ++ ++int yaffs_GutsInitialise(yaffs_Device *dev) ++{ ++ int init_failed = 0; ++ unsigned x; ++ int bits; ++ ++ T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR))); ++ ++ /* Check stuff that must be set */ ++ ++ if (!dev) { ++ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ dev->internalStartBlock = dev->startBlock; ++ dev->internalEndBlock = dev->endBlock; ++ dev->blockOffset = 0; ++ dev->chunkOffset = 0; ++ dev->nFreeChunks = 0; ++ ++ dev->gcBlock = -1; ++ ++ if (dev->startBlock == 0) { ++ dev->internalStartBlock = dev->startBlock + 1; ++ dev->internalEndBlock = dev->endBlock + 1; ++ dev->blockOffset = 1; ++ dev->chunkOffset = dev->nChunksPerBlock; ++ } ++ ++ /* Check geometry parameters. */ ++ ++ if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || ++ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || ++ (dev->inbandTags && !dev->isYaffs2) || ++ dev->nChunksPerBlock < 2 || ++ dev->nReservedBlocks < 2 || ++ dev->internalStartBlock <= 0 || ++ dev->internalEndBlock <= 0 || ++ dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d " ++ TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); ++ return YAFFS_FAIL; ++ } ++ ++ if (yaffs_InitialiseNAND(dev) != YAFFS_OK) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Sort out space for inband tags, if required */ ++ if (dev->inbandTags) ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); ++ else ++ dev->nDataBytesPerChunk = dev->totalBytesPerChunk; ++ ++ /* Got the right mix of functions? */ ++ if (!yaffs_CheckDevFunctions(dev)) { ++ /* Function missing */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR ++ ("yaffs: device function(s) missing or wrong\n" TENDSTR))); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* This is really a compilation check. */ ++ if (!yaffs_CheckStructures()) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs_CheckStructures failed\n" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ if (dev->isMounted) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: device already mounted\n" TENDSTR))); ++ return YAFFS_FAIL; ++ } ++ ++ /* Finished with most checks. One or two more checks happen later on too. */ ++ ++ dev->isMounted = 1; ++ ++ /* OK now calculate a few things for the device */ ++ ++ /* ++ * Calculate all the chunk size manipulation numbers: ++ */ ++ x = dev->nDataBytesPerChunk; ++ /* We always use dev->chunkShift and dev->chunkDiv */ ++ dev->chunkShift = Shifts(x); ++ x >>= dev->chunkShift; ++ dev->chunkDiv = x; ++ /* We only use chunk mask if chunkDiv is 1 */ ++ dev->chunkMask = (1<chunkShift) - 1; ++ ++ /* ++ * Calculate chunkGroupBits. ++ * We need to find the next power of 2 > than internalEndBlock ++ */ ++ ++ x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); ++ ++ bits = ShiftsGE(x); ++ ++ /* Set up tnode width if wide tnodes are enabled. */ ++ if (!dev->wideTnodesDisabled) { ++ /* bits must be even so that we end up with 32-bit words */ ++ if (bits & 1) ++ bits++; ++ if (bits < 16) ++ dev->tnodeWidth = 16; ++ else ++ dev->tnodeWidth = bits; ++ } else ++ dev->tnodeWidth = 16; ++ ++ dev->tnodeMask = (1<tnodeWidth)-1; ++ ++ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), ++ * so if the bitwidth of the ++ * chunk range we're using is greater than 16 we need ++ * to figure out chunk shift and chunkGroupSize ++ */ ++ ++ if (bits <= dev->tnodeWidth) ++ dev->chunkGroupBits = 0; ++ else ++ dev->chunkGroupBits = bits - dev->tnodeWidth; ++ ++ ++ dev->chunkGroupSize = 1 << dev->chunkGroupBits; ++ ++ if (dev->nChunksPerBlock < dev->chunkGroupSize) { ++ /* We have a problem because the soft delete won't work if ++ * the chunk group size > chunks per block. ++ * This can be remedied by using larger "virtual blocks". ++ */ ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: chunk group too large\n" TENDSTR))); ++ ++ return YAFFS_FAIL; ++ } ++ ++ /* OK, we've finished verifying the device, lets continue with initialisation */ ++ ++ /* More device initialisation */ ++ dev->garbageCollections = 0; ++ dev->passiveGarbageCollections = 0; ++ dev->currentDirtyChecker = 0; ++ dev->bufferedBlock = -1; ++ dev->doingBufferedBlockRewrite = 0; ++ dev->nDeletedFiles = 0; ++ dev->nBackgroundDeletions = 0; ++ dev->nUnlinkedFiles = 0; ++ dev->eccFixed = 0; ++ dev->eccUnfixed = 0; ++ dev->tagsEccFixed = 0; ++ dev->tagsEccUnfixed = 0; ++ dev->nErasureFailures = 0; ++ dev->nErasedBlocks = 0; ++ dev->isDoingGC = 0; ++ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ ++ ++ /* Initialise temporary buffers and caches. */ ++ if (!yaffs_InitialiseTempBuffers(dev)) ++ init_failed = 1; ++ ++ dev->srCache = NULL; ++ dev->gcCleanupList = NULL; ++ ++ ++ if (!init_failed && ++ dev->nShortOpCaches > 0) { ++ int i; ++ void *buf; ++ int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); ++ ++ if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) ++ dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; ++ ++ dev->srCache = YMALLOC(srCacheBytes); ++ ++ buf = (__u8 *) dev->srCache; ++ ++ if (dev->srCache) ++ memset(dev->srCache, 0, srCacheBytes); ++ ++ for (i = 0; i < dev->nShortOpCaches && buf; i++) { ++ dev->srCache[i].object = NULL; ++ dev->srCache[i].lastUse = 0; ++ dev->srCache[i].dirty = 0; ++ dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); ++ } ++ if (!buf) ++ init_failed = 1; ++ ++ dev->srLastUse = 0; ++ } ++ ++ dev->cacheHits = 0; ++ ++ if (!init_failed) { ++ dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); ++ if (!dev->gcCleanupList) ++ init_failed = 1; ++ } ++ ++ if (dev->isYaffs2) ++ dev->useHeaderFileSize = 1; ++ ++ if (!init_failed && !yaffs_InitialiseBlocks(dev)) ++ init_failed = 1; ++ ++ yaffs_InitialiseTnodes(dev); ++ yaffs_InitialiseObjects(dev); ++ ++ if (!init_failed && !yaffs_CreateInitialDirectories(dev)) ++ init_failed = 1; ++ ++ ++ if (!init_failed) { ++ /* Now scan the flash. */ ++ if (dev->isYaffs2) { ++ if (yaffs_CheckpointRestore(dev)) { ++ yaffs_CheckObjectDetailsLoaded(dev->rootDir); ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("yaffs: restored from checkpoint" TENDSTR))); ++ } else { ++ ++ /* Clean up the mess caused by an aborted checkpoint load ++ * and scan backwards. ++ */ ++ yaffs_DeinitialiseBlocks(dev); ++ yaffs_DeinitialiseTnodes(dev); ++ yaffs_DeinitialiseObjects(dev); ++ ++ ++ dev->nErasedBlocks = 0; ++ dev->nFreeChunks = 0; ++ dev->allocationBlock = -1; ++ dev->allocationPage = -1; ++ dev->nDeletedFiles = 0; ++ dev->nUnlinkedFiles = 0; ++ dev->nBackgroundDeletions = 0; ++ dev->oldestDirtySequence = 0; ++ ++ if (!init_failed && !yaffs_InitialiseBlocks(dev)) ++ init_failed = 1; ++ ++ yaffs_InitialiseTnodes(dev); ++ yaffs_InitialiseObjects(dev); ++ ++ if (!init_failed && !yaffs_CreateInitialDirectories(dev)) ++ init_failed = 1; ++ ++ if (!init_failed && !yaffs_ScanBackwards(dev)) ++ init_failed = 1; ++ } ++ } else if (!yaffs_Scan(dev)) ++ init_failed = 1; ++ ++ yaffs_StripDeletedObjects(dev); ++ } ++ ++ if (init_failed) { ++ /* Clean up the mess */ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); ++ ++ yaffs_Deinitialise(dev); ++ return YAFFS_FAIL; ++ } ++ ++ /* Zero out stats */ ++ dev->nPageReads = 0; ++ dev->nPageWrites = 0; ++ dev->nBlockErasures = 0; ++ dev->nGCCopies = 0; ++ dev->nRetriedWrites = 0; ++ ++ dev->nRetiredBlocks = 0; ++ ++ yaffs_VerifyFreeChunks(dev); ++ yaffs_VerifyBlocks(dev); ++ ++ ++ T(YAFFS_TRACE_TRACING, ++ (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); ++ return YAFFS_OK; ++ ++} ++ ++void yaffs_Deinitialise(yaffs_Device *dev) ++{ ++ if (dev->isMounted) { ++ int i; ++ ++ yaffs_DeinitialiseBlocks(dev); ++ yaffs_DeinitialiseTnodes(dev); ++ yaffs_DeinitialiseObjects(dev); ++ if (dev->nShortOpCaches > 0 && ++ dev->srCache) { ++ ++ for (i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].data) ++ YFREE(dev->srCache[i].data); ++ dev->srCache[i].data = NULL; ++ } ++ ++ YFREE(dev->srCache); ++ dev->srCache = NULL; ++ } ++ ++ YFREE(dev->gcCleanupList); ++ ++ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) ++ YFREE(dev->tempBuffer[i].buffer); ++ ++ dev->isMounted = 0; ++ ++ if (dev->deinitialiseNAND) ++ dev->deinitialiseNAND(dev); ++ } ++} ++ ++static int yaffs_CountFreeChunks(yaffs_Device *dev) ++{ ++ int nFree; ++ int b; ++ ++ yaffs_BlockInfo *blk; ++ ++ for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; ++ b++) { ++ blk = yaffs_GetBlockInfo(dev, b); ++ ++ switch (blk->blockState) { ++ case YAFFS_BLOCK_STATE_EMPTY: ++ case YAFFS_BLOCK_STATE_ALLOCATING: ++ case YAFFS_BLOCK_STATE_COLLECTING: ++ case YAFFS_BLOCK_STATE_FULL: ++ nFree += ++ (dev->nChunksPerBlock - blk->pagesInUse + ++ blk->softDeletions); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return nFree; ++} ++ ++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) ++{ ++ /* This is what we report to the outside world */ ++ ++ int nFree; ++ int nDirtyCacheChunks; ++ int blocksForCheckpoint; ++ int i; ++ ++#if 1 ++ nFree = dev->nFreeChunks; ++#else ++ nFree = yaffs_CountFreeChunks(dev); ++#endif ++ ++ nFree += dev->nDeletedFiles; ++ ++ /* Now count the number of dirty chunks in the cache and subtract those */ ++ ++ for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { ++ if (dev->srCache[i].dirty) ++ nDirtyCacheChunks++; ++ } ++ ++ nFree -= nDirtyCacheChunks; ++ ++ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); ++ ++ /* Now we figure out how much to reserve for the checkpoint and report that... */ ++ blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; ++ if (blocksForCheckpoint < 0) ++ blocksForCheckpoint = 0; ++ ++ nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); ++ ++ if (nFree < 0) ++ nFree = 0; ++ ++ return nFree; ++ ++} ++ ++static int yaffs_freeVerificationFailures; ++ ++static void yaffs_VerifyFreeChunks(yaffs_Device *dev) ++{ ++ int counted; ++ int difference; ++ ++ if (yaffs_SkipVerification(dev)) ++ return; ++ ++ counted = yaffs_CountFreeChunks(dev); ++ ++ difference = dev->nFreeChunks - counted; ++ ++ if (difference) { ++ T(YAFFS_TRACE_ALWAYS, ++ (TSTR("Freechunks verification failure %d %d %d" TENDSTR), ++ dev->nFreeChunks, counted, difference)); ++ yaffs_freeVerificationFailures++; ++ } ++} ++ ++/*---------------------------------------- YAFFS test code ----------------------*/ ++ ++#define yaffs_CheckStruct(structure, syze, name) \ ++ do { \ ++ if (sizeof(structure) != syze) { \ ++ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ ++ name, syze, sizeof(structure))); \ ++ return YAFFS_FAIL; \ ++ } \ ++ } while (0) ++ ++static int yaffs_CheckStructures(void) ++{ ++/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ ++/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ ++/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ ++#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); ++#endif ++#ifndef CONFIG_YAFFS_WINCE ++ yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); ++#endif ++ return YAFFS_OK; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h linux-2.6.30/fs/yaffs2/yaffs_guts.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_guts.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,904 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_GUTS_H__ ++#define __YAFFS_GUTS_H__ ++ ++#include "devextras.h" ++#include "yportenv.h" ++ ++#define YAFFS_OK 1 ++#define YAFFS_FAIL 0 ++ ++/* Give us a Y=0x59, ++ * Give us an A=0x41, ++ * Give us an FF=0xFF ++ * Give us an S=0x53 ++ * And what have we got... ++ */ ++#define YAFFS_MAGIC 0x5941FF53 ++ ++#define YAFFS_NTNODES_LEVEL0 16 ++#define YAFFS_TNODES_LEVEL0_BITS 4 ++#define YAFFS_TNODES_LEVEL0_MASK 0xf ++ ++#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) ++#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) ++#define YAFFS_TNODES_INTERNAL_MASK 0x7 ++#define YAFFS_TNODES_MAX_LEVEL 6 ++ ++#ifndef CONFIG_YAFFS_NO_YAFFS1 ++#define YAFFS_BYTES_PER_SPARE 16 ++#define YAFFS_BYTES_PER_CHUNK 512 ++#define YAFFS_CHUNK_SIZE_SHIFT 9 ++#define YAFFS_CHUNKS_PER_BLOCK 32 ++#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) ++#endif ++ ++#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 ++#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 ++ ++#define YAFFS_MAX_CHUNK_ID 0x000FFFFF ++ ++#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF ++ ++#define YAFFS_ALLOCATION_NOBJECTS 100 ++#define YAFFS_ALLOCATION_NTNODES 100 ++#define YAFFS_ALLOCATION_NLINKS 100 ++ ++#define YAFFS_NOBJECT_BUCKETS 256 ++ ++ ++#define YAFFS_OBJECT_SPACE 0x40000 ++ ++#define YAFFS_CHECKPOINT_VERSION 3 ++ ++#ifdef CONFIG_YAFFS_UNICODE ++#define YAFFS_MAX_NAME_LENGTH 127 ++#define YAFFS_MAX_ALIAS_LENGTH 79 ++#else ++#define YAFFS_MAX_NAME_LENGTH 255 ++#define YAFFS_MAX_ALIAS_LENGTH 159 ++#endif ++ ++#define YAFFS_SHORT_NAME_LENGTH 15 ++ ++/* Some special object ids for pseudo objects */ ++#define YAFFS_OBJECTID_ROOT 1 ++#define YAFFS_OBJECTID_LOSTNFOUND 2 ++#define YAFFS_OBJECTID_UNLINKED 3 ++#define YAFFS_OBJECTID_DELETED 4 ++ ++/* Sseudo object ids for checkpointing */ ++#define YAFFS_OBJECTID_SB_HEADER 0x10 ++#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 ++#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 ++ ++/* */ ++ ++#define YAFFS_MAX_SHORT_OP_CACHES 20 ++ ++#define YAFFS_N_TEMP_BUFFERS 6 ++ ++/* We limit the number attempts at sucessfully saving a chunk of data. ++ * Small-page devices have 32 pages per block; large-page devices have 64. ++ * Default to something in the order of 5 to 10 blocks worth of chunks. ++ */ ++#define YAFFS_WR_ATTEMPTS (5*64) ++ ++/* Sequence numbers are used in YAFFS2 to determine block allocation order. ++ * The range is limited slightly to help distinguish bad numbers from good. ++ * This also allows us to perhaps in the future use special numbers for ++ * special purposes. ++ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, ++ * and is a larger number than the lifetime of a 2GB device. ++ */ ++#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 ++#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 ++ ++/* Special sequence number for bad block that failed to be marked bad */ ++#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000 ++ ++/* ChunkCache is used for short read/write operations.*/ ++typedef struct { ++ struct yaffs_ObjectStruct *object; ++ int chunkId; ++ int lastUse; ++ int dirty; ++ int nBytes; /* Only valid if the cache is dirty */ ++ int locked; /* Can't push out or flush while locked. */ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ __u8 *data; ++#else ++ __u8 data[YAFFS_BYTES_PER_CHUNK]; ++#endif ++} yaffs_ChunkCache; ++ ++ ++ ++/* Tags structures in RAM ++ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise ++ * the structure size will get blown out. ++ */ ++ ++#ifndef CONFIG_YAFFS_NO_YAFFS1 ++typedef struct { ++ unsigned chunkId:20; ++ unsigned serialNumber:2; ++ unsigned byteCountLSB:10; ++ unsigned objectId:18; ++ unsigned ecc:12; ++ unsigned byteCountMSB:2; ++} yaffs_Tags; ++ ++typedef union { ++ yaffs_Tags asTags; ++ __u8 asBytes[8]; ++} yaffs_TagsUnion; ++ ++#endif ++ ++/* Stuff used for extended tags in YAFFS2 */ ++ ++typedef enum { ++ YAFFS_ECC_RESULT_UNKNOWN, ++ YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_ECC_RESULT_FIXED, ++ YAFFS_ECC_RESULT_UNFIXED ++} yaffs_ECCResult; ++ ++typedef enum { ++ YAFFS_OBJECT_TYPE_UNKNOWN, ++ YAFFS_OBJECT_TYPE_FILE, ++ YAFFS_OBJECT_TYPE_SYMLINK, ++ YAFFS_OBJECT_TYPE_DIRECTORY, ++ YAFFS_OBJECT_TYPE_HARDLINK, ++ YAFFS_OBJECT_TYPE_SPECIAL ++} yaffs_ObjectType; ++ ++#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL ++ ++typedef struct { ++ ++ unsigned validMarker0; ++ unsigned chunkUsed; /* Status of the chunk: used or unused */ ++ unsigned objectId; /* If 0 then this is not part of an object (unused) */ ++ unsigned chunkId; /* If 0 then this is a header, else a data chunk */ ++ unsigned byteCount; /* Only valid for data chunks */ ++ ++ /* The following stuff only has meaning when we read */ ++ yaffs_ECCResult eccResult; ++ unsigned blockBad; ++ ++ /* YAFFS 1 stuff */ ++ unsigned chunkDeleted; /* The chunk is marked deleted */ ++ unsigned serialNumber; /* Yaffs1 2-bit serial number */ ++ ++ /* YAFFS2 stuff */ ++ unsigned sequenceNumber; /* The sequence number of this block */ ++ ++ /* Extra info if this is an object header (YAFFS2 only) */ ++ ++ unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */ ++ unsigned extraParentObjectId; /* The parent object */ ++ unsigned extraIsShrinkHeader; /* Is it a shrink header? */ ++ unsigned extraShadows; /* Does this shadow another object? */ ++ ++ yaffs_ObjectType extraObjectType; /* What object type? */ ++ ++ unsigned extraFileLength; /* Length if it is a file */ ++ unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */ ++ ++ unsigned validMarker1; ++ ++} yaffs_ExtendedTags; ++ ++/* Spare structure for YAFFS1 */ ++typedef struct { ++ __u8 tagByte0; ++ __u8 tagByte1; ++ __u8 tagByte2; ++ __u8 tagByte3; ++ __u8 pageStatus; /* set to 0 to delete the chunk */ ++ __u8 blockStatus; ++ __u8 tagByte4; ++ __u8 tagByte5; ++ __u8 ecc1[3]; ++ __u8 tagByte6; ++ __u8 tagByte7; ++ __u8 ecc2[3]; ++} yaffs_Spare; ++ ++/*Special structure for passing through to mtd */ ++struct yaffs_NANDSpare { ++ yaffs_Spare spare; ++ int eccres1; ++ int eccres2; ++}; ++ ++/* Block data in RAM */ ++ ++typedef enum { ++ YAFFS_BLOCK_STATE_UNKNOWN = 0, ++ ++ YAFFS_BLOCK_STATE_SCANNING, ++ YAFFS_BLOCK_STATE_NEEDS_SCANNING, ++ /* The block might have something on it (ie it is allocating or full, perhaps empty) ++ * but it needs to be scanned to determine its true state. ++ * This state is only valid during yaffs_Scan. ++ * NB We tolerate empty because the pre-scanner might be incapable of deciding ++ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number ++ */ ++ ++ YAFFS_BLOCK_STATE_EMPTY, ++ /* This block is empty */ ++ ++ YAFFS_BLOCK_STATE_ALLOCATING, ++ /* This block is partially allocated. ++ * At least one page holds valid data. ++ * This is the one currently being used for page ++ * allocation. Should never be more than one of these ++ */ ++ ++ YAFFS_BLOCK_STATE_FULL, ++ /* All the pages in this block have been allocated. ++ */ ++ ++ YAFFS_BLOCK_STATE_DIRTY, ++ /* All pages have been allocated and deleted. ++ * Erase me, reuse me. ++ */ ++ ++ YAFFS_BLOCK_STATE_CHECKPOINT, ++ /* This block is assigned to holding checkpoint data. ++ */ ++ ++ YAFFS_BLOCK_STATE_COLLECTING, ++ /* This block is being garbage collected */ ++ ++ YAFFS_BLOCK_STATE_DEAD ++ /* This block has failed and is not in use */ ++} yaffs_BlockState; ++ ++#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) ++ ++ ++typedef struct { ++ ++ int softDeletions:10; /* number of soft deleted pages */ ++ int pagesInUse:10; /* number of pages in use */ ++ unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ ++ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ ++ /* and retire the block. */ ++ __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */ ++ __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block. ++ It should be prioritised for GC */ ++ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */ ++ __u32 sequenceNumber; /* block sequence number for yaffs2 */ ++#endif ++ ++} yaffs_BlockInfo; ++ ++/* -------------------------- Object structure -------------------------------*/ ++/* This is the object structure as stored on NAND */ ++ ++typedef struct { ++ yaffs_ObjectType type; ++ ++ /* Apply to everything */ ++ int parentObjectId; ++ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ ++ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; ++ ++ /* The following apply to directories, files, symlinks - not hard links */ ++ __u32 yst_mode; /* protection */ ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 notForWinCE[5]; ++#else ++ __u32 yst_uid; ++ __u32 yst_gid; ++ __u32 yst_atime; ++ __u32 yst_mtime; ++ __u32 yst_ctime; ++#endif ++ ++ /* File size applies to files only */ ++ int fileSize; ++ ++ /* Equivalent object id applies to hard links only. */ ++ int equivalentObjectId; ++ ++ /* Alias is for symlinks only. */ ++ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; ++ ++ __u32 yst_rdev; /* device stuff for block and char devices (major/min) */ ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 win_ctime[2]; ++ __u32 win_atime[2]; ++ __u32 win_mtime[2]; ++#else ++ __u32 roomToGrow[6]; ++ ++#endif ++ __u32 inbandShadowsObject; ++ __u32 inbandIsShrink; ++ ++ __u32 reservedSpace[2]; ++ int shadowsObject; /* This object header shadows the specified object if > 0 */ ++ ++ /* isShrink applies to object headers written when we shrink the file (ie resize) */ ++ __u32 isShrink; ++ ++} yaffs_ObjectHeader; ++ ++/*--------------------------- Tnode -------------------------- */ ++ ++union yaffs_Tnode_union { ++#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG ++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; ++#else ++ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; ++#endif ++/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ ++ ++}; ++ ++typedef union yaffs_Tnode_union yaffs_Tnode; ++ ++struct yaffs_TnodeList_struct { ++ struct yaffs_TnodeList_struct *next; ++ yaffs_Tnode *tnodes; ++}; ++ ++typedef struct yaffs_TnodeList_struct yaffs_TnodeList; ++ ++/*------------------------ Object -----------------------------*/ ++/* An object can be one of: ++ * - a directory (no data, has children links ++ * - a regular file (data.... not prunes :->). ++ * - a symlink [symbolic link] (the alias). ++ * - a hard link ++ */ ++ ++typedef struct { ++ __u32 fileSize; ++ __u32 scannedFileSize; ++ __u32 shrinkSize; ++ int topLevel; ++ yaffs_Tnode *top; ++} yaffs_FileStructure; ++ ++typedef struct { ++ struct ylist_head children; /* list of child links */ ++} yaffs_DirectoryStructure; ++ ++typedef struct { ++ YCHAR *alias; ++} yaffs_SymLinkStructure; ++ ++typedef struct { ++ struct yaffs_ObjectStruct *equivalentObject; ++ __u32 equivalentObjectId; ++} yaffs_HardLinkStructure; ++ ++typedef union { ++ yaffs_FileStructure fileVariant; ++ yaffs_DirectoryStructure directoryVariant; ++ yaffs_SymLinkStructure symLinkVariant; ++ yaffs_HardLinkStructure hardLinkVariant; ++} yaffs_ObjectVariant; ++ ++struct yaffs_ObjectStruct { ++ __u8 deleted:1; /* This should only apply to unlinked files. */ ++ __u8 softDeleted:1; /* it has also been soft deleted */ ++ __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/ ++ __u8 fake:1; /* A fake object has no presence on NAND. */ ++ __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ ++ __u8 unlinkAllowed:1; ++ __u8 dirty:1; /* the object needs to be written to flash */ ++ __u8 valid:1; /* When the file system is being loaded up, this ++ * object might be created before the data ++ * is available (ie. file data records appear before the header). ++ */ ++ __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */ ++ ++ __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is ++ * still in the inode cache. Free of object is defered. ++ * until the inode is released. ++ */ ++ __u8 beingCreated:1; /* This object is still being created so skip some checks. */ ++ ++ __u8 serial; /* serial number of chunk in NAND. Cached here */ ++ __u16 sum; /* sum of the name to speed searching */ ++ ++ struct yaffs_DeviceStruct *myDev; /* The device I'm on */ ++ ++ struct ylist_head hashLink; /* list of objects in this hash bucket */ ++ ++ struct ylist_head hardLinks; /* all the equivalent hard linked objects */ ++ ++ /* directory structure stuff */ ++ /* also used for linking up the free list */ ++ struct yaffs_ObjectStruct *parent; ++ struct ylist_head siblings; ++ ++ /* Where's my object header in NAND? */ ++ int hdrChunk; ++ ++ int nDataChunks; /* Number of data chunks attached to the file. */ ++ ++ __u32 objectId; /* the object id value */ ++ ++ __u32 yst_mode; ++ ++#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM ++ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; ++#endif ++ ++#ifndef __KERNEL__ ++ __u32 inUse; ++#endif ++ ++#ifdef CONFIG_YAFFS_WINCE ++ __u32 win_ctime[2]; ++ __u32 win_mtime[2]; ++ __u32 win_atime[2]; ++#else ++ __u32 yst_uid; ++ __u32 yst_gid; ++ __u32 yst_atime; ++ __u32 yst_mtime; ++ __u32 yst_ctime; ++#endif ++ ++ __u32 yst_rdev; ++ ++#ifdef __KERNEL__ ++ struct inode *myInode; ++ ++#endif ++ ++ yaffs_ObjectType variantType; ++ ++ yaffs_ObjectVariant variant; ++ ++}; ++ ++typedef struct yaffs_ObjectStruct yaffs_Object; ++ ++struct yaffs_ObjectList_struct { ++ yaffs_Object *objects; ++ struct yaffs_ObjectList_struct *next; ++}; ++ ++typedef struct yaffs_ObjectList_struct yaffs_ObjectList; ++ ++typedef struct { ++ struct ylist_head list; ++ int count; ++} yaffs_ObjectBucket; ++ ++ ++/* yaffs_CheckpointObject holds the definition of an object as dumped ++ * by checkpointing. ++ */ ++ ++typedef struct { ++ int structType; ++ __u32 objectId; ++ __u32 parentId; ++ int hdrChunk; ++ yaffs_ObjectType variantType:3; ++ __u8 deleted:1; ++ __u8 softDeleted:1; ++ __u8 unlinked:1; ++ __u8 fake:1; ++ __u8 renameAllowed:1; ++ __u8 unlinkAllowed:1; ++ __u8 serial; ++ ++ int nDataChunks; ++ __u32 fileSizeOrEquivalentObjectId; ++} yaffs_CheckpointObject; ++ ++/*--------------------- Temporary buffers ---------------- ++ * ++ * These are chunk-sized working buffers. Each device has a few ++ */ ++ ++typedef struct { ++ __u8 *buffer; ++ int line; /* track from whence this buffer was allocated */ ++ int maxLine; ++} yaffs_TempBuffer; ++ ++/*----------------- Device ---------------------------------*/ ++ ++struct yaffs_DeviceStruct { ++ struct ylist_head devList; ++ const char *name; ++ ++ /* Entry parameters set up way early. Yaffs sets up the rest.*/ ++ int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ ++ int nChunksPerBlock; /* does not need to be a power of 2 */ ++ int spareBytesPerChunk; /* spare area size */ ++ int startBlock; /* Start block we're allowed to use */ ++ int endBlock; /* End block we're allowed to use */ ++ int nReservedBlocks; /* We want this tuneable so that we can reduce */ ++ /* reserved blocks on NOR and RAM. */ ++ ++ ++ /* Stuff used by the shared space checkpointing mechanism */ ++ /* If this value is zero, then this mechanism is disabled */ ++ ++/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */ ++ ++ ++ int nShortOpCaches; /* If <= 0, then short op caching is disabled, else ++ * the number of short op caches (don't use too many) ++ */ ++ ++ int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ ++ ++ int useNANDECC; /* Flag to decide whether or not to use NANDECC */ ++ ++ void *genericDevice; /* Pointer to device context ++ * On an mtd this holds the mtd pointer. ++ */ ++ void *superBlock; ++ ++ /* NAND access functions (Must be set before calling YAFFS)*/ ++ ++ int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_Spare *spare); ++ int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare); ++ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++ int (*initialiseNAND) (struct yaffs_DeviceStruct *dev); ++ int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev); ++ ++#ifdef CONFIG_YAFFS_YAFFS2 ++ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++ int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_ExtendedTags *tags); ++ int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo); ++ int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++#endif ++ ++ int isYaffs2; ++ ++ /* The removeObjectCallback function must be supplied by OS flavours that ++ * need it. The Linux kernel does not use this, but yaffs direct does use ++ * it to implement the faster readdir ++ */ ++ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); ++ ++ /* Callback to mark the superblock dirsty */ ++ void (*markSuperBlockDirty)(void *superblock); ++ ++ int wideTnodesDisabled; /* Set to disable wide tnodes */ ++ ++ YCHAR *pathDividers; /* String of legal path dividers */ ++ ++ ++ /* End of stuff that must be set before initialisation. */ ++ ++ /* Checkpoint control. Can be set before or after initialisation */ ++ __u8 skipCheckpointRead; ++ __u8 skipCheckpointWrite; ++ ++ /* Runtime parameters. Set up by YAFFS. */ ++ ++ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ ++ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ ++ ++ /* Stuff to support wide tnodes */ ++ __u32 tnodeWidth; ++ __u32 tnodeMask; ++ ++ /* Stuff for figuring out file offset to chunk conversions */ ++ __u32 chunkShift; /* Shift value */ ++ __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */ ++ __u32 chunkMask; /* Mask to use for power-of-2 case */ ++ ++ /* Stuff to handle inband tags */ ++ int inbandTags; ++ __u32 totalBytesPerChunk; ++ ++#ifdef __KERNEL__ ++ ++ struct semaphore sem; /* Semaphore for waiting on erasure.*/ ++ struct semaphore grossLock; /* Gross locking semaphore */ ++ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer ++ * at compile time so we have to allocate it. ++ */ ++ void (*putSuperFunc) (struct super_block *sb); ++#endif ++ ++ int isMounted; ++ ++ int isCheckpointed; ++ ++ ++ /* Stuff to support block offsetting to support start block zero */ ++ int internalStartBlock; ++ int internalEndBlock; ++ int blockOffset; ++ int chunkOffset; ++ ++ ++ /* Runtime checkpointing stuff */ ++ int checkpointPageSequence; /* running sequence number of checkpoint pages */ ++ int checkpointByteCount; ++ int checkpointByteOffset; ++ __u8 *checkpointBuffer; ++ int checkpointOpenForWrite; ++ int blocksInCheckpoint; ++ int checkpointCurrentChunk; ++ int checkpointCurrentBlock; ++ int checkpointNextBlock; ++ int *checkpointBlockList; ++ int checkpointMaxBlocks; ++ __u32 checkpointSum; ++ __u32 checkpointXor; ++ ++ int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */ ++ ++ /* Block Info */ ++ yaffs_BlockInfo *blockInfo; ++ __u8 *chunkBits; /* bitmap of chunks in use */ ++ unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ ++ unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ ++ int chunkBitmapStride; /* Number of bytes of chunkBits per block. ++ * Must be consistent with nChunksPerBlock. ++ */ ++ ++ int nErasedBlocks; ++ int allocationBlock; /* Current block being allocated off */ ++ __u32 allocationPage; ++ int allocationBlockFinder; /* Used to search for next allocation block */ ++ ++ /* Runtime state */ ++ int nTnodesCreated; ++ yaffs_Tnode *freeTnodes; ++ int nFreeTnodes; ++ yaffs_TnodeList *allocatedTnodeList; ++ ++ int isDoingGC; ++ int gcBlock; ++ int gcChunk; ++ ++ int nObjectsCreated; ++ yaffs_Object *freeObjects; ++ int nFreeObjects; ++ ++ int nHardLinks; ++ ++ yaffs_ObjectList *allocatedObjectList; ++ ++ yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; ++ ++ int nFreeChunks; ++ ++ int currentDirtyChecker; /* Used to find current dirtiest block */ ++ ++ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ ++ int nonAggressiveSkip; /* GC state/mode */ ++ ++ /* Statistcs */ ++ int nPageWrites; ++ int nPageReads; ++ int nBlockErasures; ++ int nErasureFailures; ++ int nGCCopies; ++ int garbageCollections; ++ int passiveGarbageCollections; ++ int nRetriedWrites; ++ int nRetiredBlocks; ++ int eccFixed; ++ int eccUnfixed; ++ int tagsEccFixed; ++ int tagsEccUnfixed; ++ int nDeletions; ++ int nUnmarkedDeletions; ++ ++ int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ ++ ++ /* Special directories */ ++ yaffs_Object *rootDir; ++ yaffs_Object *lostNFoundDir; ++ ++ /* Buffer areas for storing data to recover from write failures TODO ++ * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; ++ * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; ++ */ ++ ++ int bufferedBlock; /* Which block is buffered here? */ ++ int doingBufferedBlockRewrite; ++ ++ yaffs_ChunkCache *srCache; ++ int srLastUse; ++ ++ int cacheHits; ++ ++ /* Stuff for background deletion and unlinked files.*/ ++ yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ ++ yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ ++ yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/ ++ int nDeletedFiles; /* Count of files awaiting deletion;*/ ++ int nUnlinkedFiles; /* Count of unlinked files. */ ++ int nBackgroundDeletions; /* Count of background deletions. */ ++ ++ ++ /* Temporary buffer management */ ++ yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; ++ int maxTemp; ++ int tempInUse; ++ int unmanagedTempAllocations; ++ int unmanagedTempDeallocations; ++ ++ /* yaffs2 runtime stuff */ ++ unsigned sequenceNumber; /* Sequence number of currently allocating block */ ++ unsigned oldestDirtySequence; ++ ++}; ++ ++typedef struct yaffs_DeviceStruct yaffs_Device; ++ ++/* The static layout of block usage etc is stored in the super block header */ ++typedef struct { ++ int StructType; ++ int version; ++ int checkpointStartBlock; ++ int checkpointEndBlock; ++ int startBlock; ++ int endBlock; ++ int rfu[100]; ++} yaffs_SuperBlockHeader; ++ ++/* The CheckpointDevice structure holds the device information that changes at runtime and ++ * must be preserved over unmount/mount cycles. ++ */ ++typedef struct { ++ int structType; ++ int nErasedBlocks; ++ int allocationBlock; /* Current block being allocated off */ ++ __u32 allocationPage; ++ int nFreeChunks; ++ ++ int nDeletedFiles; /* Count of files awaiting deletion;*/ ++ int nUnlinkedFiles; /* Count of unlinked files. */ ++ int nBackgroundDeletions; /* Count of background deletions. */ ++ ++ /* yaffs2 runtime stuff */ ++ unsigned sequenceNumber; /* Sequence number of currently allocating block */ ++ unsigned oldestDirtySequence; ++ ++} yaffs_CheckpointDevice; ++ ++ ++typedef struct { ++ int structType; ++ __u32 magic; ++ __u32 version; ++ __u32 head; ++} yaffs_CheckpointValidity; ++ ++ ++/*----------------------- YAFFS Functions -----------------------*/ ++ ++int yaffs_GutsInitialise(yaffs_Device *dev); ++void yaffs_Deinitialise(yaffs_Device *dev); ++ ++int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev); ++ ++int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, ++ yaffs_Object *newDir, const YCHAR *newName); ++ ++int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name); ++int yaffs_DeleteObject(yaffs_Object *obj); ++ ++int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize); ++int yaffs_GetObjectFileLength(yaffs_Object *obj); ++int yaffs_GetObjectInode(yaffs_Object *obj); ++unsigned yaffs_GetObjectType(yaffs_Object *obj); ++int yaffs_GetObjectLinkCount(yaffs_Object *obj); ++ ++int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr); ++int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr); ++ ++/* File operations */ ++int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset, ++ int nBytes); ++int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset, ++ int nBytes, int writeThrough); ++int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize); ++ ++yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid); ++int yaffs_FlushFile(yaffs_Object *obj, int updateTime); ++ ++/* Flushing and checkpointing */ ++void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); ++ ++int yaffs_CheckpointSave(yaffs_Device *dev); ++int yaffs_CheckpointRestore(yaffs_Device *dev); ++ ++/* Directory operations */ ++yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid); ++yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name); ++int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, ++ int (*fn) (yaffs_Object *)); ++ ++yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number); ++ ++/* Link operations */ ++yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, ++ yaffs_Object *equivalentObject); ++ ++yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj); ++ ++/* Symlink operations */ ++yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, ++ const YCHAR *alias); ++YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); ++ ++/* Special inodes (fifos, sockets and devices) */ ++yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, ++ __u32 mode, __u32 uid, __u32 gid, __u32 rdev); ++ ++/* Special directories */ ++yaffs_Object *yaffs_Root(yaffs_Device *dev); ++yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); ++ ++#ifdef CONFIG_YAFFS_WINCE ++/* CONFIG_YAFFS_WINCE special stuff */ ++void yfsd_WinFileTimeNow(__u32 target[2]); ++#endif ++ ++#ifdef __KERNEL__ ++ ++void yaffs_HandleDeferedFree(yaffs_Object *obj); ++#endif ++ ++/* Debug dump */ ++int yaffs_DumpObject(yaffs_Object *obj); ++ ++void yaffs_GutsTest(yaffs_Device *dev); ++ ++/* A few useful functions */ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); ++void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn); ++int yaffs_CheckFF(__u8 *buffer, int nBytes); ++void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); ++ ++__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo); ++void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h linux-2.6.30/fs/yaffs2/yaffsinterface.h +--- linux-2.6.30.orig/fs/yaffs2/yaffsinterface.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffsinterface.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFSINTERFACE_H__ ++#define __YAFFSINTERFACE_H__ ++ ++int yaffs_Initialise(unsigned nBlocks); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,365 @@ ++/* ++ * YAFFS: Yet another FFS. A NAND-flash specific file system. ++ * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. ++ * ++ * Copyright (C) 2002 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * This module provides the interface between yaffs_nand.c and the ++ * MTD API. This version is used when the MTD interface supports the ++ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, ++ * and we have small-page NAND device. ++ * ++ * These functions are invoked via function pointers in yaffs_nand.c. ++ * This replaces functionality provided by functions in yaffs_mtdif.c ++ * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are ++ * called in yaffs_mtdif.c when the function pointers are NULL. ++ * We assume the MTD layer is performing ECC (useNANDECC is true). ++ */ ++ ++#include "yportenv.h" ++#include "yaffs_guts.h" ++#include "yaffs_packedtags1.h" ++#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */ ++ ++#include "linux/kernel.h" ++#include "linux/version.h" ++#include "linux/types.h" ++#include "linux/mtd/mtd.h" ++ ++/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ ++const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $"; ++ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++# define YTAG1_SIZE 8 ++#else ++# define YTAG1_SIZE 9 ++#endif ++ ++#if 0 ++/* Use the following nand_ecclayout with MTD when using ++ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. ++ * If you have existing Yaffs images and the byte order differs from this, ++ * adjust 'oobfree' to match your existing Yaffs data. ++ * ++ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the ++ * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to ++ * the 9th byte. ++ * ++ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 ++ * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P ++ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus ++ * byte and B is the small-page bad-block indicator byte. ++ */ ++static struct nand_ecclayout nand_oob_16 = { ++ .eccbytes = 6, ++ .eccpos = { 8, 9, 10, 13, 14, 15 }, ++ .oobavail = 9, ++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } ++}; ++#endif ++ ++/* Write a chunk (page) of data to NAND. ++ * ++ * Caller always provides ExtendedTags data which are converted to a more ++ * compact (packed) form for storage in NAND. A mini-ECC runs over the ++ * contents of the tags meta-data; used to valid the tags when read. ++ * ++ * - Pack ExtendedTags to PackedTags1 form ++ * - Compute mini-ECC for PackedTags1 ++ * - Write data and packed tags to NAND. ++ * ++ * Note: Due to the use of the PackedTags1 meta-data which does not include ++ * a full sequence number (as found in the larger PackedTags2 form) it is ++ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as ++ * discarded and dirty. This is not ideal: newer NAND parts are supposed ++ * to be written just once. When Yaffs performs this operation, this ++ * function is called with a NULL data pointer -- calling MTD write_oob ++ * without data is valid usage (2.6.17). ++ * ++ * Any underlying MTD error results in YAFFS_FAIL. ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkBytes = dev->nDataBytesPerChunk; ++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; ++ struct mtd_oob_ops ops; ++ yaffs_PackedTags1 pt1; ++ int retval; ++ ++ /* we assume that PackedTags1 and yaffs_Tags are compatible */ ++ compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); ++ compile_time_assertion(sizeof(yaffs_Tags) == 8); ++ ++ dev->nPageWrites++; ++ ++ yaffs_PackTags1(&pt1, etags); ++ yaffs_CalcTagsECC((yaffs_Tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * etags, one with chunkDeleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++ if (etags->chunkDeleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++#else ++ ((__u8 *)&pt1)[8] = 0xff; ++ if (etags->chunkDeleted) { ++ memset(&pt1, 0xff, 8); ++ /* zero pageStatus byte to indicate deleted */ ++ ((__u8 *)&pt1)[8] = 0; ++ } ++#endif ++ ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OOB_AUTO; ++ ops.len = (data) ? chunkBytes : 0; ++ ops.ooblen = YTAG1_SIZE; ++ ops.datbuf = (__u8 *)data; ++ ops.oobbuf = (__u8 *)&pt1; ++ ++ retval = mtd->write_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "write_oob failed, chunk %d, mtd error %d\n", ++ chunkInNAND, retval); ++ } ++ return retval ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++/* Return with empty ExtendedTags but add eccResult. ++ */ ++static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) ++{ ++ if (etags) { ++ memset(etags, 0, sizeof(*etags)); ++ etags->eccResult = eccResult; ++ } ++ return retval; ++} ++ ++/* Read a chunk (page) from NAND. ++ * ++ * Caller expects ExtendedTags data to be usable even on error; that is, ++ * all members except eccResult and blockBad are zeroed. ++ * ++ * - Check ECC results for data (if applicable) ++ * - Check for blank/erased block (return empty ExtendedTags if blank) ++ * - Check the PackedTags1 mini-ECC (correct if necessary/possible) ++ * - Convert PackedTags1 to ExtendedTags ++ * - Update eccResult and blockBad members to refect state. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkBytes = dev->nDataBytesPerChunk; ++ loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; ++ int eccres = YAFFS_ECC_RESULT_NO_ERROR; ++ struct mtd_oob_ops ops; ++ yaffs_PackedTags1 pt1; ++ int retval; ++ int deleted; ++ ++ dev->nPageReads++; ++ ++ memset(&ops, 0, sizeof(ops)); ++ ops.mode = MTD_OOB_AUTO; ++ ops.len = (data) ? chunkBytes : 0; ++ ops.ooblen = YTAG1_SIZE; ++ ops.datbuf = data; ++ ops.oobbuf = (__u8 *)&pt1; ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) ++ /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; ++ * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. ++ */ ++ ops.len = (ops.datbuf) ? ops.len : ops.ooblen; ++#endif ++ /* Read page and oob using MTD. ++ * Check status and determine ECC result. ++ */ ++ retval = mtd->read_oob(mtd, addr, &ops); ++ if (retval) { ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "read_oob failed, chunk %d, mtd error %d\n", ++ chunkInNAND, retval); ++ } ++ ++ switch (retval) { ++ case 0: ++ /* no error */ ++ break; ++ ++ case -EUCLEAN: ++ /* MTD's ECC fixed the data */ ++ eccres = YAFFS_ECC_RESULT_FIXED; ++ dev->eccFixed++; ++ break; ++ ++ case -EBADMSG: ++ /* MTD's ECC could not fix the data */ ++ dev->eccUnfixed++; ++ /* fall into... */ ++ default: ++ rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ etags->blockBad = (mtd->block_isbad)(mtd, addr); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. ++ */ ++ if (yaffs_CheckFF((__u8 *)&pt1, 8)) { ++ /* when blank, upper layers want eccResult to be <= NO_ERROR */ ++ return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); ++ } ++ ++#ifndef CONFIG_YAFFS_9BYTE_TAGS ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++#else ++ deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); ++#endif ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. ++ */ ++ retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->tagsEccFixed++; ++ if (eccres == YAFFS_ECC_RESULT_NO_ERROR) ++ eccres = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->tagsEccUnfixed++; ++ return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] ++ */ ++ pt1.shouldBeFF = 0xFFFFFFFF; ++ yaffs_UnpackTags1(etags, &pt1); ++ etags->eccResult = eccres; ++ ++ /* Set deleted state */ ++ etags->chunkDeleted = deleted; ++ return YAFFS_OK; ++} ++ ++/* Mark a block bad. ++ * ++ * This is a persistant state. ++ * Use of this function should be rare. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); ++ ++ retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); ++ return (retval) ? YAFFS_FAIL : YAFFS_OK; ++} ++ ++/* Check any MTD prerequists. ++ * ++ * Returns YAFFS_OK or YAFFS_FAIL. ++ */ ++static int nandmtd1_TestPrerequists(struct mtd_info *mtd) ++{ ++ /* 2.6.18 has mtd->ecclayout->oobavail */ ++ /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ ++ int oobavail = mtd->ecclayout->oobavail; ++ ++ if (oobavail < YTAG1_SIZE) { ++ yaffs_trace(YAFFS_TRACE_ERROR, ++ "mtd device has only %d bytes for tags, need %d\n", ++ oobavail, YTAG1_SIZE); ++ return YAFFS_FAIL; ++ } ++ return YAFFS_OK; ++} ++ ++/* Query for the current state of a specific block. ++ * ++ * Examine the tags of the first chunk of the block and return the state: ++ * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad ++ * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use ++ * - YAFFS_BLOCK_STATE_EMPTY, the block is clean ++ * ++ * Always returns YAFFS_OK. ++ */ ++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *pState, __u32 *pSequenceNumber) ++{ ++ struct mtd_info *mtd = dev->genericDevice; ++ int chunkNo = blockNo * dev->nChunksPerBlock; ++ loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; ++ yaffs_ExtendedTags etags; ++ int state = YAFFS_BLOCK_STATE_DEAD; ++ int seqnum = 0; ++ int retval; ++ ++ /* We don't yet have a good place to test for MTD config prerequists. ++ * Do it here as we are called during the initial scan. ++ */ ++ if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) ++ return YAFFS_FAIL; ++ ++ retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); ++ etags.blockBad = (mtd->block_isbad)(mtd, addr); ++ if (etags.blockBad) { ++ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, ++ "block %d is marked bad\n", blockNo); ++ state = YAFFS_BLOCK_STATE_DEAD; ++ } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { ++ /* bad tags, need to look more closely */ ++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ } else if (etags.chunkUsed) { ++ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ seqnum = etags.sequenceNumber; ++ } else { ++ state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ *pState = state; ++ *pSequenceNumber = seqnum; ++ ++ /* query always succeeds */ ++ return YAFFS_OK; ++} ++ ++#endif /*MTD_VERSION*/ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif1.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF1_H__ ++#define __YAFFS_MTDIF1_H__ ++ ++int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_ExtendedTags *tags); ++ ++int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags); ++ ++int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++ ++int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,246 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++/* mtd interface for YAFFS2 */ ++ ++const char *yaffs_mtdif2_c_version = ++ "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++ ++#include "yaffs_mtdif2.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++ ++#include "yaffs_packedtags2.h" ++ ++/* NB For use with inband tags.... ++ * We assume that the data buffer is of size totalBytersPerChunk so that we can also ++ * use it to load the tags. ++ */ ++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#else ++ size_t dummy; ++#endif ++ int retval = 0; ++ ++ loff_t addr; ++ ++ yaffs_PackedTags2 pt; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" ++ TENDSTR), chunkInNAND, data, tags)); ++ ++ ++ addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; ++ ++ /* For yaffs2 writing there must be both data and tags. ++ * If we're using inband tags, then the tags are stuffed into ++ * the end of the data buffer. ++ */ ++ if (!data || !tags) ++ BUG(); ++ else if (dev->inbandTags) { ++ yaffs_PackedTags2TagsPart *pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); ++ yaffs_PackTags2TagsPart(pt2tp, tags); ++ } else ++ yaffs_PackTags2(&pt, tags); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt); ++ ops.len = dev->totalBytesPerChunk; ++ ops.ooboffs = 0; ++ ops.datbuf = (__u8 *)data; ++ ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; ++ retval = mtd->write_oob(mtd, addr, &ops); ++ ++#else ++ if (!dev->inbandTags) { ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, (__u8 *) &pt, NULL); ++ } else { ++ retval = ++ mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, ++ data); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ int localData = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; ++ ++ yaffs_PackedTags2 pt; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" ++ TENDSTR), chunkInNAND, data, tags)); ++ ++ if (dev->inbandTags) { ++ ++ if (!data) { ++ localData = 1; ++ data = yaffs_GetTempBuffer(dev, __LINE__); ++ } ++ ++ ++ } ++ ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) ++ if (dev->inbandTags || (data && !tags)) ++ retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, ++ &dummy, data); ++ else if (tags) { ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = sizeof(pt); ++ ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt); ++ ops.ooboffs = 0; ++ ops.datbuf = data; ++ ops.oobbuf = dev->spareBuffer; ++ retval = mtd->read_oob(mtd, addr, &ops); ++ } ++#else ++ if (!dev->inbandTags && data && tags) { ++ ++ retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, dev->spareBuffer, ++ NULL); ++ } else { ++ if (data) ++ retval = ++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (!dev->inbandTags && tags) ++ retval = ++ mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, ++ dev->spareBuffer); ++ } ++#endif ++ ++ ++ if (dev->inbandTags) { ++ if (tags) { ++ yaffs_PackedTags2TagsPart *pt2tp; ++ pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; ++ yaffs_UnpackTags2TagsPart(tags, pt2tp); ++ } ++ } else { ++ if (tags) { ++ memcpy(&pt, dev->spareBuffer, sizeof(pt)); ++ yaffs_UnpackTags2(tags, &pt); ++ } ++ } ++ ++ if (localData) ++ yaffs_ReleaseTempBuffer(dev, data, __LINE__); ++ ++ if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) ++ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ int retval; ++ T(YAFFS_TRACE_MTD, ++ (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); ++ ++ retval = ++ mtd->block_markbad(mtd, ++ blockNo * dev->nChunksPerBlock * ++ dev->totalBytesPerChunk); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++ ++} ++ ++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ int retval; ++ ++ T(YAFFS_TRACE_MTD, ++ (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); ++ retval = ++ mtd->block_isbad(mtd, ++ blockNo * dev->nChunksPerBlock * ++ dev->totalBytesPerChunk); ++ ++ if (retval) { ++ T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); ++ ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ *sequenceNumber = 0; ++ } else { ++ yaffs_ExtendedTags t; ++ nandmtd2_ReadChunkWithTagsFromNAND(dev, ++ blockNo * ++ dev->nChunksPerBlock, NULL, ++ &t); ++ ++ if (t.chunkUsed) { ++ *sequenceNumber = t.sequenceNumber; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ } else { ++ *sequenceNumber = 0; ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ } ++ T(YAFFS_TRACE_MTD, ++ (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber, ++ *state)); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif2.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF2_H__ ++#define __YAFFS_MTDIF2_H__ ++ ++#include "yaffs_guts.h" ++int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *data, yaffs_ExtendedTags *tags); ++int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.30/fs/yaffs2/yaffs_mtdif.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,241 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_mtdif_c_version = ++ "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $"; ++ ++#include "yportenv.h" ++ ++ ++#include "yaffs_mtdif.h" ++ ++#include "linux/mtd/mtd.h" ++#include "linux/types.h" ++#include "linux/time.h" ++#include "linux/mtd/nand.h" ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) ++static struct nand_oobinfo yaffs_oobinfo = { ++ .useecc = 1, ++ .eccbytes = 6, ++ .eccpos = {8, 9, 10, 13, 14, 15} ++}; ++ ++static struct nand_oobinfo yaffs_noeccinfo = { ++ .useecc = 0, ++}; ++#endif ++ ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) ++{ ++ oob[0] = spare->tagByte0; ++ oob[1] = spare->tagByte1; ++ oob[2] = spare->tagByte2; ++ oob[3] = spare->tagByte3; ++ oob[4] = spare->tagByte4; ++ oob[5] = spare->tagByte5 & 0x3f; ++ oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; ++ oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; ++ oob[6] = spare->tagByte6; ++ oob[7] = spare->tagByte7; ++} ++ ++static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) ++{ ++ struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; ++ spare->tagByte0 = oob[0]; ++ spare->tagByte1 = oob[1]; ++ spare->tagByte2 = oob[2]; ++ spare->tagByte3 = oob[3]; ++ spare->tagByte4 = oob[4]; ++ spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; ++ spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; ++ spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; ++ spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; ++ spare->tagByte6 = oob[6]; ++ spare->tagByte7 = oob[7]; ++ spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; ++ ++ nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ ++} ++#endif ++ ++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_Spare *spare) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ __u8 spareAsBytes[8]; /* OOB */ ++ ++ if (data && !spare) ++ retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data); ++ else if (spare) { ++ if (dev->useNANDECC) { ++ translate_spare2oob(spare, spareAsBytes); ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = 8; /* temp hack */ ++ } else { ++ ops.mode = MTD_OOB_RAW; ++ ops.ooblen = YAFFS_BYTES_PER_SPARE; ++ } ++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; ++ ops.datbuf = (u8 *)data; ++ ops.ooboffs = 0; ++ ops.oobbuf = spareAsBytes; ++ retval = mtd->write_oob(mtd, addr, &ops); ++ } ++#else ++ __u8 *spareAsBytes = (__u8 *) spare; ++ ++ if (data && spare) { ++ if (dev->useNANDECC) ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_oobinfo); ++ else ++ retval = ++ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_noeccinfo); ++ } else { ++ if (data) ++ retval = ++ mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (spare) ++ retval = ++ mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, ++ &dummy, spareAsBytes); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ struct mtd_oob_ops ops; ++#endif ++ size_t dummy; ++ int retval = 0; ++ ++ loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; ++#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) ++ __u8 spareAsBytes[8]; /* OOB */ ++ ++ if (data && !spare) ++ retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data); ++ else if (spare) { ++ if (dev->useNANDECC) { ++ ops.mode = MTD_OOB_AUTO; ++ ops.ooblen = 8; /* temp hack */ ++ } else { ++ ops.mode = MTD_OOB_RAW; ++ ops.ooblen = YAFFS_BYTES_PER_SPARE; ++ } ++ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; ++ ops.datbuf = data; ++ ops.ooboffs = 0; ++ ops.oobbuf = spareAsBytes; ++ retval = mtd->read_oob(mtd, addr, &ops); ++ if (dev->useNANDECC) ++ translate_oob2spare(spare, spareAsBytes); ++ } ++#else ++ __u8 *spareAsBytes = (__u8 *) spare; ++ ++ if (data && spare) { ++ if (dev->useNANDECC) { ++ /* Careful, this call adds 2 ints */ ++ /* to the end of the spare data. Calling function */ ++ /* should allocate enough memory for spare, */ ++ /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ ++ retval = ++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_oobinfo); ++ } else { ++ retval = ++ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, ++ &dummy, data, spareAsBytes, ++ &yaffs_noeccinfo); ++ } ++ } else { ++ if (data) ++ retval = ++ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, ++ data); ++ if (spare) ++ retval = ++ mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, ++ &dummy, spareAsBytes); ++ } ++#endif ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) ++{ ++ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); ++ __u32 addr = ++ ((loff_t) blockNumber) * dev->nDataBytesPerChunk ++ * dev->nChunksPerBlock; ++ struct erase_info ei; ++ int retval = 0; ++ ++ ei.mtd = mtd; ++ ei.addr = addr; ++ ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; ++ ei.time = 1000; ++ ei.retries = 2; ++ ei.callback = NULL; ++ ei.priv = (u_long) dev; ++ ++ /* Todo finish off the ei if required */ ++ ++ sema_init(&dev->sem, 0); ++ ++ retval = mtd->erase(mtd, &ei); ++ ++ if (retval == 0) ++ return YAFFS_OK; ++ else ++ return YAFFS_FAIL; ++} ++ ++int nandmtd_InitialiseNAND(yaffs_Device *dev) ++{ ++ return YAFFS_OK; ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.30/fs/yaffs2/yaffs_mtdif.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_mtdif.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_MTDIF_H__ ++#define __YAFFS_MTDIF_H__ ++ ++#include "yaffs_guts.h" ++ ++#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) ++extern struct nand_oobinfo yaffs_oobinfo; ++extern struct nand_oobinfo yaffs_noeccinfo; ++#endif ++ ++int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, const yaffs_Spare *spare); ++int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, ++ yaffs_Spare *spare); ++int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); ++int nandmtd_InitialiseNAND(yaffs_Device *dev); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c linux-2.6.30/fs/yaffs2/yaffs_nand.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nand.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,135 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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. ++ */ ++ ++const char *yaffs_nand_c_version = ++ "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $"; ++ ++#include "yaffs_nand.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_tagsvalidity.h" ++ ++#include "yaffs_getblockinfo.h" ++ ++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *buffer, ++ yaffs_ExtendedTags *tags) ++{ ++ int result; ++ yaffs_ExtendedTags localTags; ++ ++ int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; ++ ++ /* If there are no tags provided, use local tags to get prioritised gc working */ ++ if (!tags) ++ tags = &localTags; ++ ++ if (dev->readChunkWithTagsFromNAND) ++ result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, ++ tags); ++ else ++ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, ++ realignedChunkInNAND, ++ buffer, ++ tags); ++ if (tags && ++ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { ++ ++ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); ++ yaffs_HandleChunkError(dev, bi); ++ } ++ ++ return result; ++} ++ ++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags) ++{ ++ chunkInNAND -= dev->chunkOffset; ++ ++ ++ if (tags) { ++ tags->sequenceNumber = dev->sequenceNumber; ++ tags->chunkUsed = 1; ++ if (!yaffs_ValidateTags(tags)) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("Writing uninitialised tags" TENDSTR))); ++ YBUG(); ++ } ++ T(YAFFS_TRACE_WRITE, ++ (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND, ++ tags->objectId, tags->chunkId)); ++ } else { ++ T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR))); ++ YBUG(); ++ } ++ ++ if (dev->writeChunkWithTagsToNAND) ++ return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, ++ tags); ++ else ++ return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, ++ chunkInNAND, ++ buffer, ++ tags); ++} ++ ++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) ++{ ++ blockNo -= dev->blockOffset; ++ ++; ++ if (dev->markNANDBlockBad) ++ return dev->markNANDBlockBad(dev, blockNo); ++ else ++ return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); ++} ++ ++int yaffs_QueryInitialBlockState(yaffs_Device *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber) ++{ ++ blockNo -= dev->blockOffset; ++ ++ if (dev->queryNANDBlock) ++ return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); ++ else ++ return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, ++ state, ++ sequenceNumber); ++} ++ ++ ++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND) ++{ ++ int result; ++ ++ blockInNAND -= dev->blockOffset; ++ ++ ++ dev->nBlockErasures++; ++ result = dev->eraseBlockInNAND(dev, blockInNAND); ++ ++ return result; ++} ++ ++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) ++{ ++ return dev->initialiseNAND(dev); ++} ++ ++ ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nandemul2k.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nandemul2k.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* Interface to emulated NAND functions (2k page size) */ ++ ++#ifndef __YAFFS_NANDEMUL2K_H__ ++#define __YAFFS_NANDEMUL2K_H__ ++ ++#include "yaffs_guts.h" ++ ++int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, __u8 *data, ++ yaffs_ExtendedTags *tags); ++int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); ++int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, ++ yaffs_BlockState *state, __u32 *sequenceNumber); ++int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); ++int nandemul2k_GetBytesPerChunk(void); ++int nandemul2k_GetChunksPerBlock(void); ++int nandemul2k_GetNumberOfBlocks(void); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h linux-2.6.30/fs/yaffs2/yaffs_nand.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_nand.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,44 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_NAND_H__ ++#define __YAFFS_NAND_H__ ++#include "yaffs_guts.h" ++ ++ ++ ++int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, ++ __u8 *buffer, ++ yaffs_ExtendedTags *tags); ++ ++int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *buffer, ++ yaffs_ExtendedTags *tags); ++ ++int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo); ++ ++int yaffs_QueryInitialBlockState(yaffs_Device *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ unsigned *sequenceNumber); ++ ++int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, ++ int blockInNAND); ++ ++int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev); ++ ++#endif ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags1.h" ++#include "yportenv.h" ++ ++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t) ++{ ++ pt->chunkId = t->chunkId; ++ pt->serialNumber = t->serialNumber; ++ pt->byteCount = t->byteCount; ++ pt->objectId = t->objectId; ++ pt->ecc = 0; ++ pt->deleted = (t->chunkDeleted) ? 0 : 1; ++ pt->unusedStuff = 0; ++ pt->shouldBeFF = 0xFFFFFFFF; ++ ++} ++ ++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt) ++{ ++ static const __u8 allFF[] = ++ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff }; ++ ++ if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) { ++ t->blockBad = 0; ++ if (pt->shouldBeFF != 0xFFFFFFFF) ++ t->blockBad = 1; ++ t->chunkUsed = 1; ++ t->objectId = pt->objectId; ++ t->chunkId = pt->chunkId; ++ t->byteCount = pt->byteCount; ++ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ t->chunkDeleted = (pt->deleted) ? 0 : 1; ++ t->serialNumber = pt->serialNumber; ++ } else { ++ memset(t, 0, sizeof(yaffs_ExtendedTags)); ++ } ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags1.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS1_H__ ++#define __YAFFS_PACKEDTAGS1_H__ ++ ++#include "yaffs_guts.h" ++ ++typedef struct { ++ unsigned chunkId:20; ++ unsigned serialNumber:2; ++ unsigned byteCount:10; ++ unsigned objectId:18; ++ unsigned ecc:12; ++ unsigned deleted:1; ++ unsigned unusedStuff:1; ++ unsigned shouldBeFF; ++ ++} yaffs_PackedTags1; ++ ++void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,206 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_packedtags2.h" ++#include "yportenv.h" ++#include "yaffs_tagsvalidity.h" ++ ++/* This code packs a set of extended tags into a binary structure for ++ * NAND storage ++ */ ++ ++/* Some of the information is "extra" struff which can be packed in to ++ * speed scanning ++ * This is defined by having the EXTRA_HEADER_INFO_FLAG set. ++ */ ++ ++/* Extra flags applied to chunkId */ ++ ++#define EXTRA_HEADER_INFO_FLAG 0x80000000 ++#define EXTRA_SHRINK_FLAG 0x40000000 ++#define EXTRA_SHADOWS_FLAG 0x20000000 ++#define EXTRA_SPARE_FLAGS 0x10000000 ++ ++#define ALL_EXTRA_FLAGS 0xF0000000 ++ ++/* Also, the top 4 bits of the object Id are set to the object type. */ ++#define EXTRA_OBJECT_TYPE_SHIFT (28) ++#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) ++ ++ ++static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) ++{ ++ T(YAFFS_TRACE_MTD, ++ (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), ++ ptt->objectId, ptt->chunkId, ptt->byteCount, ++ ptt->sequenceNumber)); ++} ++static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt) ++{ ++ yaffs_DumpPackedTags2TagsPart(&pt->t); ++} ++ ++static void yaffs_DumpTags2(const yaffs_ExtendedTags *t) ++{ ++ T(YAFFS_TRACE_MTD, ++ (TSTR ++ ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" ++ TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, ++ t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, ++ t->sequenceNumber)); ++ ++} ++ ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, ++ const yaffs_ExtendedTags *t) ++{ ++ ptt->chunkId = t->chunkId; ++ ptt->sequenceNumber = t->sequenceNumber; ++ ptt->byteCount = t->byteCount; ++ ptt->objectId = t->objectId; ++ ++ if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { ++ /* Store the extra header info instead */ ++ /* We save the parent object in the chunkId */ ++ ptt->chunkId = EXTRA_HEADER_INFO_FLAG ++ | t->extraParentObjectId; ++ if (t->extraIsShrinkHeader) ++ ptt->chunkId |= EXTRA_SHRINK_FLAG; ++ if (t->extraShadows) ++ ptt->chunkId |= EXTRA_SHADOWS_FLAG; ++ ++ ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ptt->objectId |= ++ (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); ++ ++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) ++ ptt->byteCount = t->extraEquivalentObjectId; ++ else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) ++ ptt->byteCount = t->extraFileLength; ++ else ++ ptt->byteCount = 0; ++ } ++ ++ yaffs_DumpPackedTags2TagsPart(ptt); ++ yaffs_DumpTags2(t); ++} ++ ++ ++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) ++{ ++ yaffs_PackTags2TagsPart(&pt->t, t); ++ ++#ifndef YAFFS_IGNORE_TAGS_ECC ++ { ++ yaffs_ECCCalculateOther((unsigned char *)&pt->t, ++ sizeof(yaffs_PackedTags2TagsPart), ++ &pt->ecc); ++ } ++#endif ++} ++ ++ ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, ++ yaffs_PackedTags2TagsPart *ptt) ++{ ++ ++ memset(t, 0, sizeof(yaffs_ExtendedTags)); ++ ++ yaffs_InitialiseTags(t); ++ ++ if (ptt->sequenceNumber != 0xFFFFFFFF) { ++ t->blockBad = 0; ++ t->chunkUsed = 1; ++ t->objectId = ptt->objectId; ++ t->chunkId = ptt->chunkId; ++ t->byteCount = ptt->byteCount; ++ t->chunkDeleted = 0; ++ t->serialNumber = 0; ++ t->sequenceNumber = ptt->sequenceNumber; ++ ++ /* Do extra header info stuff */ ++ ++ if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) { ++ t->chunkId = 0; ++ t->byteCount = 0; ++ ++ t->extraHeaderInfoAvailable = 1; ++ t->extraParentObjectId = ++ ptt->chunkId & (~(ALL_EXTRA_FLAGS)); ++ t->extraIsShrinkHeader = ++ (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; ++ t->extraShadows = ++ (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; ++ t->extraObjectType = ++ ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT; ++ t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; ++ ++ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) ++ t->extraEquivalentObjectId = ptt->byteCount; ++ else ++ t->extraFileLength = ptt->byteCount; ++ } ++ } ++ ++ yaffs_DumpPackedTags2TagsPart(ptt); ++ yaffs_DumpTags2(t); ++ ++} ++ ++ ++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) ++{ ++ ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ if (pt->t.sequenceNumber != 0xFFFFFFFF) { ++ /* Page is in use */ ++#ifndef YAFFS_IGNORE_TAGS_ECC ++ { ++ yaffs_ECCOther ecc; ++ int result; ++ yaffs_ECCCalculateOther((unsigned char *)&pt->t, ++ sizeof ++ (yaffs_PackedTags2TagsPart), ++ &ecc); ++ result = ++ yaffs_ECCCorrectOther((unsigned char *)&pt->t, ++ sizeof ++ (yaffs_PackedTags2TagsPart), ++ &pt->ecc, &ecc); ++ switch (result) { ++ case 0: ++ eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ break; ++ case 1: ++ eccResult = YAFFS_ECC_RESULT_FIXED; ++ break; ++ case -1: ++ eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ break; ++ default: ++ eccResult = YAFFS_ECC_RESULT_UNKNOWN; ++ } ++ } ++#endif ++ } ++ ++ yaffs_UnpackTags2TagsPart(t, &pt->t); ++ ++ t->eccResult = eccResult; ++ ++ yaffs_DumpPackedTags2(pt); ++ yaffs_DumpTags2(t); ++ ++} ++ +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_packedtags2.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,43 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ ++ ++#ifndef __YAFFS_PACKEDTAGS2_H__ ++#define __YAFFS_PACKEDTAGS2_H__ ++ ++#include "yaffs_guts.h" ++#include "yaffs_ecc.h" ++ ++typedef struct { ++ unsigned sequenceNumber; ++ unsigned objectId; ++ unsigned chunkId; ++ unsigned byteCount; ++} yaffs_PackedTags2TagsPart; ++ ++typedef struct { ++ yaffs_PackedTags2TagsPart t; ++ yaffs_ECCOther ecc; ++} yaffs_PackedTags2; ++ ++/* Full packed tags with ECC, used for oob tags */ ++void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt); ++ ++/* Only the tags part (no ECC for use with inband tags */ ++void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t); ++void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c linux-2.6.30/fs/yaffs2/yaffs_qsort.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_qsort.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (c) 1992, 1993 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#include "yportenv.h" ++/* #include */ ++ ++/* ++ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". ++ */ ++#define swapcode(TYPE, parmi, parmj, n) do { \ ++ long i = (n) / sizeof (TYPE); \ ++ register TYPE *pi = (TYPE *) (parmi); \ ++ register TYPE *pj = (TYPE *) (parmj); \ ++ do { \ ++ register TYPE t = *pi; \ ++ *pi++ = *pj; \ ++ *pj++ = t; \ ++ } while (--i > 0); \ ++} while (0) ++ ++#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ ++ es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1; ++ ++static __inline void ++swapfunc(char *a, char *b, int n, int swaptype) ++{ ++ if (swaptype <= 1) ++ swapcode(long, a, b, n); ++ else ++ swapcode(char, a, b, n); ++} ++ ++#define yswap(a, b) do { \ ++ if (swaptype == 0) { \ ++ long t = *(long *)(a); \ ++ *(long *)(a) = *(long *)(b); \ ++ *(long *)(b) = t; \ ++ } else \ ++ swapfunc(a, b, es, swaptype); \ ++} while (0) ++ ++#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) ++ ++static __inline char * ++med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) ++{ ++ return cmp(a, b) < 0 ? ++ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) ++ : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c)); ++} ++ ++#ifndef min ++#define min(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++ ++void ++yaffs_qsort(void *aa, size_t n, size_t es, ++ int (*cmp)(const void *, const void *)) ++{ ++ char *pa, *pb, *pc, *pd, *pl, *pm, *pn; ++ int d, r, swaptype, swap_cnt; ++ register char *a = aa; ++ ++loop: SWAPINIT(a, es); ++ swap_cnt = 0; ++ if (n < 7) { ++ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) ++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; ++ pl -= es) ++ yswap(pl, pl - es); ++ return; ++ } ++ pm = (char *)a + (n / 2) * es; ++ if (n > 7) { ++ pl = (char *)a; ++ pn = (char *)a + (n - 1) * es; ++ if (n > 40) { ++ d = (n / 8) * es; ++ pl = med3(pl, pl + d, pl + 2 * d, cmp); ++ pm = med3(pm - d, pm, pm + d, cmp); ++ pn = med3(pn - 2 * d, pn - d, pn, cmp); ++ } ++ pm = med3(pl, pm, pn, cmp); ++ } ++ yswap(a, pm); ++ pa = pb = (char *)a + es; ++ ++ pc = pd = (char *)a + (n - 1) * es; ++ for (;;) { ++ while (pb <= pc && (r = cmp(pb, a)) <= 0) { ++ if (r == 0) { ++ swap_cnt = 1; ++ yswap(pa, pb); ++ pa += es; ++ } ++ pb += es; ++ } ++ while (pb <= pc && (r = cmp(pc, a)) >= 0) { ++ if (r == 0) { ++ swap_cnt = 1; ++ yswap(pc, pd); ++ pd -= es; ++ } ++ pc -= es; ++ } ++ if (pb > pc) ++ break; ++ yswap(pb, pc); ++ swap_cnt = 1; ++ pb += es; ++ pc -= es; ++ } ++ if (swap_cnt == 0) { /* Switch to insertion sort */ ++ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) ++ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; ++ pl -= es) ++ yswap(pl, pl - es); ++ return; ++ } ++ ++ pn = (char *)a + n * es; ++ r = min(pa - (char *)a, pb - pa); ++ vecswap(a, pb - r, r); ++ r = min((long)(pd - pc), (long)(pn - pd - es)); ++ vecswap(pb, pn - r, r); ++ r = pb - pa; ++ if (r > es) ++ yaffs_qsort(a, r / es, es, cmp); ++ r = pd - pc; ++ if (r > es) { ++ /* Iterate rather than recurse to save stack space */ ++ a = pn - r; ++ n = r / es; ++ goto loop; ++ } ++/* yaffs_qsort(pn - r, r / es, es, cmp);*/ ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h linux-2.6.30/fs/yaffs2/yaffs_qsort.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_qsort.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_qsort.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YAFFS_QSORT_H__ ++#define __YAFFS_QSORT_H__ ++ ++extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, ++ int (*cmp)(const void *, const void *)); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,541 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_guts.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_ecc.h" ++#include "yaffs_getblockinfo.h" ++ ++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); ++#ifdef NOTYET ++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND); ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_Spare *spare); ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_Spare *spare); ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND); ++#endif ++ ++static const char yaffs_countBitsTable[256] = { ++ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, ++ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 ++}; ++ ++int yaffs_CountBits(__u8 x) ++{ ++ int retVal; ++ retVal = yaffs_countBitsTable[x]; ++ return retVal; ++} ++ ++/********** Tags ECC calculations *********/ ++ ++void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) ++{ ++ yaffs_ECCCalculate(data, spare->ecc1); ++ yaffs_ECCCalculate(&data[256], spare->ecc2); ++} ++ ++void yaffs_CalcTagsECC(yaffs_Tags *tags) ++{ ++ /* Calculate an ecc */ ++ ++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; ++ unsigned i, j; ++ unsigned ecc = 0; ++ unsigned bit = 0; ++ ++ tags->ecc = 0; ++ ++ for (i = 0; i < 8; i++) { ++ for (j = 1; j & 0xff; j <<= 1) { ++ bit++; ++ if (b[i] & j) ++ ecc ^= bit; ++ } ++ } ++ ++ tags->ecc = ecc; ++ ++} ++ ++int yaffs_CheckECCOnTags(yaffs_Tags *tags) ++{ ++ unsigned ecc = tags->ecc; ++ ++ yaffs_CalcTagsECC(tags); ++ ++ ecc ^= tags->ecc; ++ ++ if (ecc && ecc <= 64) { ++ /* TODO: Handle the failure better. Retire? */ ++ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; ++ ++ ecc--; ++ ++ b[ecc / 8] ^= (1 << (ecc & 7)); ++ ++ /* Now recvalc the ecc */ ++ yaffs_CalcTagsECC(tags); ++ ++ return 1; /* recovered error */ ++ } else if (ecc) { ++ /* Wierd ecc failure value */ ++ /* TODO Need to do somethiong here */ ++ return -1; /* unrecovered error */ ++ } ++ ++ return 0; ++} ++ ++/********** Tags **********/ ++ ++static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, ++ yaffs_Tags *tagsPtr) ++{ ++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; ++ ++ yaffs_CalcTagsECC(tagsPtr); ++ ++ sparePtr->tagByte0 = tu->asBytes[0]; ++ sparePtr->tagByte1 = tu->asBytes[1]; ++ sparePtr->tagByte2 = tu->asBytes[2]; ++ sparePtr->tagByte3 = tu->asBytes[3]; ++ sparePtr->tagByte4 = tu->asBytes[4]; ++ sparePtr->tagByte5 = tu->asBytes[5]; ++ sparePtr->tagByte6 = tu->asBytes[6]; ++ sparePtr->tagByte7 = tu->asBytes[7]; ++} ++ ++static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr, ++ yaffs_Tags *tagsPtr) ++{ ++ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; ++ int result; ++ ++ tu->asBytes[0] = sparePtr->tagByte0; ++ tu->asBytes[1] = sparePtr->tagByte1; ++ tu->asBytes[2] = sparePtr->tagByte2; ++ tu->asBytes[3] = sparePtr->tagByte3; ++ tu->asBytes[4] = sparePtr->tagByte4; ++ tu->asBytes[5] = sparePtr->tagByte5; ++ tu->asBytes[6] = sparePtr->tagByte6; ++ tu->asBytes[7] = sparePtr->tagByte7; ++ ++ result = yaffs_CheckECCOnTags(tagsPtr); ++ if (result > 0) ++ dev->tagsEccFixed++; ++ else if (result < 0) ++ dev->tagsEccUnfixed++; ++} ++ ++static void yaffs_SpareInitialise(yaffs_Spare *spare) ++{ ++ memset(spare, 0xFF, sizeof(yaffs_Spare)); ++} ++ ++static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, const __u8 *data, ++ yaffs_Spare *spare) ++{ ++ if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), ++ chunkInNAND)); ++ return YAFFS_FAIL; ++ } ++ ++ dev->nPageWrites++; ++ return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); ++} ++ ++static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_Spare *spare, ++ yaffs_ECCResult *eccResult, ++ int doErrorCorrection) ++{ ++ int retVal; ++ yaffs_Spare localSpare; ++ ++ dev->nPageReads++; ++ ++ if (!spare && data) { ++ /* If we don't have a real spare, then we use a local one. */ ++ /* Need this for the calculation of the ecc */ ++ spare = &localSpare; ++ } ++ ++ if (!dev->useNANDECC) { ++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); ++ if (data && doErrorCorrection) { ++ /* Do ECC correction */ ++ /* Todo handle any errors */ ++ int eccResult1, eccResult2; ++ __u8 calcEcc[3]; ++ ++ yaffs_ECCCalculate(data, calcEcc); ++ eccResult1 = ++ yaffs_ECCCorrect(data, spare->ecc1, calcEcc); ++ yaffs_ECCCalculate(&data[256], calcEcc); ++ eccResult2 = ++ yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc); ++ ++ if (eccResult1 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error fix performed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ dev->eccFixed++; ++ } else if (eccResult1 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error unfixed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ dev->eccUnfixed++; ++ } ++ ++ if (eccResult2 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error fix performed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ dev->eccFixed++; ++ } else if (eccResult2 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>yaffs ecc error unfixed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ dev->eccUnfixed++; ++ } ++ ++ if (eccResult1 || eccResult2) { ++ /* We had a data problem on this page */ ++ yaffs_HandleReadDataError(dev, chunkInNAND); ++ } ++ ++ if (eccResult1 < 0 || eccResult2 < 0) ++ *eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ else if (eccResult1 > 0 || eccResult2 > 0) ++ *eccResult = YAFFS_ECC_RESULT_FIXED; ++ else ++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ } ++ } else { ++ /* Must allocate enough memory for spare+2*sizeof(int) */ ++ /* for ecc results from device. */ ++ struct yaffs_NANDSpare nspare; ++ ++ memset(&nspare, 0, sizeof(nspare)); ++ ++ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, ++ (yaffs_Spare *) &nspare); ++ memcpy(spare, &nspare, sizeof(yaffs_Spare)); ++ if (data && doErrorCorrection) { ++ if (nspare.eccres1 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error fix performed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ } else if (nspare.eccres1 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error unfixed on chunk %d:0" ++ TENDSTR), chunkInNAND)); ++ } ++ ++ if (nspare.eccres2 > 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error fix performed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ } else if (nspare.eccres2 < 0) { ++ T(YAFFS_TRACE_ERROR, ++ (TSTR ++ ("**>>mtd ecc error unfixed on chunk %d:1" ++ TENDSTR), chunkInNAND)); ++ } ++ ++ if (nspare.eccres1 || nspare.eccres2) { ++ /* We had a data problem on this page */ ++ yaffs_HandleReadDataError(dev, chunkInNAND); ++ } ++ ++ if (nspare.eccres1 < 0 || nspare.eccres2 < 0) ++ *eccResult = YAFFS_ECC_RESULT_UNFIXED; ++ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) ++ *eccResult = YAFFS_ECC_RESULT_FIXED; ++ else ++ *eccResult = YAFFS_ECC_RESULT_NO_ERROR; ++ ++ } ++ } ++ return retVal; ++} ++ ++#ifdef NOTYET ++static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, ++ int chunkInNAND) ++{ ++ static int init; ++ static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; ++ static __u8 data[YAFFS_BYTES_PER_CHUNK]; ++ /* Might as well always allocate the larger size for */ ++ /* dev->useNANDECC == true; */ ++ static __u8 spare[sizeof(struct yaffs_NANDSpare)]; ++ ++ dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); ++ ++ if (!init) { ++ memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); ++ init = 1; ++ } ++ ++ if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK)) ++ return YAFFS_FAIL; ++ if (memcmp(cmpbuf, spare, 16)) ++ return YAFFS_FAIL; ++ ++ return YAFFS_OK; ++ ++} ++#endif ++ ++/* ++ * Functions for robustisizing ++ */ ++ ++static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ ++ /* Mark the block for retirement */ ++ yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; ++ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, ++ (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); ++ ++ /* TODO: ++ * Just do a garbage collection on the affected block ++ * then retire the block ++ * NB recursion ++ */ ++} ++ ++#ifdef NOTYET ++static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND) ++{ ++} ++ ++static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, ++ const __u8 *data, ++ const yaffs_Spare *spare) ++{ ++} ++ ++static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, ++ const yaffs_Spare *spare) ++{ ++} ++ ++static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) ++{ ++ int blockInNAND = chunkInNAND / dev->nChunksPerBlock; ++ ++ /* Mark the block for retirement */ ++ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; ++ /* Delete the chunk */ ++ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); ++} ++ ++static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1, ++ const yaffs_Spare *s0, const yaffs_Spare *s1) ++{ ++ ++ if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 || ++ s0->tagByte0 != s1->tagByte0 || ++ s0->tagByte1 != s1->tagByte1 || ++ s0->tagByte2 != s1->tagByte2 || ++ s0->tagByte3 != s1->tagByte3 || ++ s0->tagByte4 != s1->tagByte4 || ++ s0->tagByte5 != s1->tagByte5 || ++ s0->tagByte6 != s1->tagByte6 || ++ s0->tagByte7 != s1->tagByte7 || ++ s0->ecc1[0] != s1->ecc1[0] || ++ s0->ecc1[1] != s1->ecc1[1] || ++ s0->ecc1[2] != s1->ecc1[2] || ++ s0->ecc2[0] != s1->ecc2[0] || ++ s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) { ++ return 0; ++ } ++ ++ return 1; ++} ++#endif /* NOTYET */ ++ ++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *eTags) ++{ ++ yaffs_Spare spare; ++ yaffs_Tags tags; ++ ++ yaffs_SpareInitialise(&spare); ++ ++ if (eTags->chunkDeleted) ++ spare.pageStatus = 0; ++ else { ++ tags.objectId = eTags->objectId; ++ tags.chunkId = eTags->chunkId; ++ ++ tags.byteCountLSB = eTags->byteCount & 0x3ff; ++ ++ if (dev->nDataBytesPerChunk >= 1024) ++ tags.byteCountMSB = (eTags->byteCount >> 10) & 3; ++ else ++ tags.byteCountMSB = 3; ++ ++ ++ tags.serialNumber = eTags->serialNumber; ++ ++ if (!dev->useNANDECC && data) ++ yaffs_CalcECC(data, &spare); ++ ++ yaffs_LoadTagsIntoSpare(&spare, &tags); ++ ++ } ++ ++ return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare); ++} ++ ++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_ExtendedTags *eTags) ++{ ++ ++ yaffs_Spare spare; ++ yaffs_Tags tags; ++ yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN; ++ ++ static yaffs_Spare spareFF; ++ static int init; ++ ++ if (!init) { ++ memset(&spareFF, 0xFF, sizeof(spareFF)); ++ init = 1; ++ } ++ ++ if (yaffs_ReadChunkFromNAND ++ (dev, chunkInNAND, data, &spare, &eccResult, 1)) { ++ /* eTags may be NULL */ ++ if (eTags) { ++ ++ int deleted = ++ (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; ++ ++ eTags->chunkDeleted = deleted; ++ eTags->eccResult = eccResult; ++ eTags->blockBad = 0; /* We're reading it */ ++ /* therefore it is not a bad block */ ++ eTags->chunkUsed = ++ (memcmp(&spareFF, &spare, sizeof(spareFF)) != ++ 0) ? 1 : 0; ++ ++ if (eTags->chunkUsed) { ++ yaffs_GetTagsFromSpare(dev, &spare, &tags); ++ ++ eTags->objectId = tags.objectId; ++ eTags->chunkId = tags.chunkId; ++ eTags->byteCount = tags.byteCountLSB; ++ ++ if (dev->nDataBytesPerChunk >= 1024) ++ eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10); ++ ++ eTags->serialNumber = tags.serialNumber; ++ } ++ } ++ ++ return YAFFS_OK; ++ } else { ++ return YAFFS_FAIL; ++ } ++} ++ ++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, ++ int blockInNAND) ++{ ++ ++ yaffs_Spare spare; ++ ++ memset(&spare, 0xff, sizeof(yaffs_Spare)); ++ ++ spare.blockStatus = 'Y'; ++ ++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, ++ &spare); ++ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, ++ NULL, &spare); ++ ++ return YAFFS_OK; ++ ++} ++ ++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber) ++{ ++ ++ yaffs_Spare spare0, spare1; ++ static yaffs_Spare spareFF; ++ static int init; ++ yaffs_ECCResult dummy; ++ ++ if (!init) { ++ memset(&spareFF, 0xFF, sizeof(spareFF)); ++ init = 1; ++ } ++ ++ *sequenceNumber = 0; ++ ++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, ++ &spare0, &dummy, 1); ++ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, ++ &spare1, &dummy, 1); ++ ++ if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ else ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; ++ ++ return YAFFS_OK; ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagscompat.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++#ifndef __YAFFS_TAGSCOMPAT_H__ ++#define __YAFFS_TAGSCOMPAT_H__ ++ ++#include "yaffs_guts.h" ++int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ const __u8 *data, ++ const yaffs_ExtendedTags *tags); ++int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, ++ int chunkInNAND, ++ __u8 *data, ++ yaffs_ExtendedTags *tags); ++int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, ++ int blockNo); ++int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, ++ int blockNo, ++ yaffs_BlockState *state, ++ __u32 *sequenceNumber); ++ ++void yaffs_CalcTagsECC(yaffs_Tags *tags); ++int yaffs_CheckECCOnTags(yaffs_Tags *tags); ++int yaffs_CountBits(__u8 byte); ++ ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.c 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * 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 "yaffs_tagsvalidity.h" ++ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags) ++{ ++ memset(tags, 0, sizeof(yaffs_ExtendedTags)); ++ tags->validMarker0 = 0xAAAAAAAA; ++ tags->validMarker1 = 0x55555555; ++} ++ ++int yaffs_ValidateTags(yaffs_ExtendedTags *tags) ++{ ++ return (tags->validMarker0 == 0xAAAAAAAA && ++ tags->validMarker1 == 0x55555555); ++ ++} +diff -Nur linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h +--- linux-2.6.30.orig/fs/yaffs2/yaffs_tagsvalidity.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yaffs_tagsvalidity.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,24 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YAFFS_TAGS_VALIDITY_H__ ++#define __YAFFS_TAGS_VALIDITY_H__ ++ ++#include "yaffs_guts.h" ++ ++void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); ++int yaffs_ValidateTags(yaffs_ExtendedTags *tags); ++#endif +diff -Nur linux-2.6.30.orig/fs/yaffs2/yportenv.h linux-2.6.30/fs/yaffs2/yportenv.h +--- linux-2.6.30.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.30/fs/yaffs2/yportenv.h 2009-06-11 09:21:04.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. ++ * ++ * Copyright (C) 2002-2007 Aleph One Ltd. ++ * for Toby Churchill Ltd and Brightstar Engineering ++ * ++ * Created by Charles Manning ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License version 2.1 as ++ * published by the Free Software Foundation. ++ * ++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. ++ */ ++ ++ ++#ifndef __YPORTENV_H__ ++#define __YPORTENV_H__ ++ ++/* ++ * Define the MTD version in terms of Linux Kernel versions ++ * This allows yaffs to be used independantly of the kernel ++ * as well as with it. ++ */ ++ ++#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) ++ ++#if defined CONFIG_YAFFS_WINCE ++ ++#include "ywinceenv.h" ++ ++#elif defined __KERNEL__ ++ ++#include "moduleconfig.h" ++ ++/* Linux kernel */ ++ ++#include ++#define MTD_VERSION_CODE LINUX_VERSION_CODE ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++#define yaffs_strcat(a, b) strcat(a, b) ++#define yaffs_strcpy(a, b) strcpy(a, b) ++#define yaffs_strncpy(a, b, c) strncpy(a, b, c) ++#define yaffs_strncmp(a, b, c) strncmp(a, b, c) ++#define yaffs_strlen(s) strlen(s) ++#define yaffs_sprintf sprintf ++#define yaffs_toupper(a) toupper(a) ++ ++#define Y_INLINE inline ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++ ++/* #define YPRINTF(x) printk x */ ++#define YMALLOC(x) kmalloc(x, GFP_NOFS) ++#define YFREE(x) kfree(x) ++#define YMALLOC_ALT(x) vmalloc(x) ++#define YFREE_ALT(x) vfree(x) ++#define YMALLOC_DMA(x) YMALLOC(x) ++ ++/* KR - added for use in scan so processes aren't blocked indefinitely. */ ++#define YYIELD() schedule() ++ ++#define YAFFS_ROOT_MODE 0666 ++#define YAFFS_LOSTNFOUND_MODE 0666 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) ++#define Y_CURRENT_TIME CURRENT_TIME.tv_sec ++#define Y_TIME_CONVERT(x) (x).tv_sec ++#else ++#define Y_CURRENT_TIME CURRENT_TIME ++#define Y_TIME_CONVERT(x) (x) ++#endif ++ ++#define yaffs_SumCompare(x, y) ((x) == (y)) ++#define yaffs_strcmp(a, b) strcmp(a, b) ++ ++#define TENDSTR "\n" ++#define TSTR(x) KERN_WARNING x ++#define TCONT(x) x ++#define TOUT(p) printk p ++ ++#define yaffs_trace(mask, fmt, args...) \ ++ do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ ++ printk(KERN_WARNING "yaffs: " fmt, ## args); \ ++ } while (0) ++ ++#define compile_time_assertion(assertion) \ ++ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) ++ ++#elif defined CONFIG_YAFFS_DIRECT ++ ++#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22) ++ ++/* Direct interface */ ++#include "ydirectenv.h" ++ ++#elif defined CONFIG_YAFFS_UTIL ++ ++/* Stuff for YAFFS utilities */ ++ ++#include "stdlib.h" ++#include "stdio.h" ++#include "string.h" ++ ++#include "devextras.h" ++ ++#define YMALLOC(x) malloc(x) ++#define YFREE(x) free(x) ++#define YMALLOC_ALT(x) malloc(x) ++#define YFREE_ALT(x) free(x) ++ ++#define YCHAR char ++#define YUCHAR unsigned char ++#define _Y(x) x ++#define yaffs_strcat(a, b) strcat(a, b) ++#define yaffs_strcpy(a, b) strcpy(a, b) ++#define yaffs_strncpy(a, b, c) strncpy(a, b, c) ++#define yaffs_strlen(s) strlen(s) ++#define yaffs_sprintf sprintf ++#define yaffs_toupper(a) toupper(a) ++ ++#define Y_INLINE inline ++ ++/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */ ++/* #define YALERT(s) YINFO(s) */ ++ ++#define TENDSTR "\n" ++#define TSTR(x) x ++#define TOUT(p) printf p ++ ++#define YAFFS_LOSTNFOUND_NAME "lost+found" ++#define YAFFS_LOSTNFOUND_PREFIX "obj" ++/* #define YPRINTF(x) printf x */ ++ ++#define YAFFS_ROOT_MODE 0666 ++#define YAFFS_LOSTNFOUND_MODE 0666 ++ ++#define yaffs_SumCompare(x, y) ((x) == (y)) ++#define yaffs_strcmp(a, b) strcmp(a, b) ++ ++#else ++/* Should have specified a configuration type */ ++#error Unknown configuration ++ ++#endif ++ ++/* see yaffs_fs.c */ ++extern unsigned int yaffs_traceMask; ++extern unsigned int yaffs_wr_attempts; ++ ++/* ++ * Tracing flags. ++ * The flags masked in YAFFS_TRACE_ALWAYS are always traced. ++ */ ++ ++#define YAFFS_TRACE_OS 0x00000002 ++#define YAFFS_TRACE_ALLOCATE 0x00000004 ++#define YAFFS_TRACE_SCAN 0x00000008 ++#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 ++#define YAFFS_TRACE_ERASE 0x00000020 ++#define YAFFS_TRACE_GC 0x00000040 ++#define YAFFS_TRACE_WRITE 0x00000080 ++#define YAFFS_TRACE_TRACING 0x00000100 ++#define YAFFS_TRACE_DELETION 0x00000200 ++#define YAFFS_TRACE_BUFFERS 0x00000400 ++#define YAFFS_TRACE_NANDACCESS 0x00000800 ++#define YAFFS_TRACE_GC_DETAIL 0x00001000 ++#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 ++#define YAFFS_TRACE_MTD 0x00004000 ++#define YAFFS_TRACE_CHECKPOINT 0x00008000 ++ ++#define YAFFS_TRACE_VERIFY 0x00010000 ++#define YAFFS_TRACE_VERIFY_NAND 0x00020000 ++#define YAFFS_TRACE_VERIFY_FULL 0x00040000 ++#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 ++ ++ ++#define YAFFS_TRACE_ERROR 0x40000000 ++#define YAFFS_TRACE_BUG 0x80000000 ++#define YAFFS_TRACE_ALWAYS 0xF0000000 ++ ++ ++#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) ++ ++#ifndef YBUG ++#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) ++#endif ++ ++#endif diff --git a/target/rb532/device.mk b/target/rb532/device.mk index 6f5553ffa..4561640ee 100644 --- a/target/rb532/device.mk +++ b/target/rb532/device.mk @@ -1,7 +1,7 @@ ARCH:= mips CPU_ARCH:= mipsel -KERNEL_VERSION:= 2.6.30.1 +KERNEL_VERSION:= 2.6.30.4 KERNEL_RELEASE:= 1 -KERNEL_MD5SUM:= 7da2e2e31f1c00f2673d2dc50de76b33 -TARGET_OPTIMIZATION:= -O2 -pipe +KERNEL_MD5SUM:= ac05e32764368af7eff79c5e3df65efb +TARGET_OPTIMIZATION:= -Os -pipe TARGET_CFLAGS_ARCH:= -march=mips32 diff --git a/toolchain/gcc/Makefile.inc b/toolchain/gcc/Makefile.inc index 9b771706f..3fa197be8 100644 --- a/toolchain/gcc/Makefile.inc +++ b/toolchain/gcc/Makefile.inc @@ -2,7 +2,7 @@ # material, please see the LICENCE file in the top-level directory. PKG_NAME:= gcc -PKG_VERSION:= 4.4.0 +PKG_VERSION:= 4.4.1 PKG_RELEASE:= 1 PKG_MD5SUM:= cf5d787bee57f38168b74d65a7c0e6fd PKG_SITES:= ${MASTER_SITE_GNU:=gcc/gcc-${PKG_VERSION}/} diff --git a/toolchain/uClibc/Makefile b/toolchain/uClibc/Makefile index e393eba5b..69b5d343a 100644 --- a/toolchain/uClibc/Makefile +++ b/toolchain/uClibc/Makefile @@ -8,6 +8,11 @@ include ../rules.mk include Makefile.inc include ${TOPDIR}/mk/buildhlp.mk +#workaround for mips and gcc 4.4, where -Os does not inline code in ld.so +ifeq ($(ARCH),mips) +TARGET_CFLAGS:=$(subst Os,O2,$(TARGET_CFLAGS)) +endif + $(WRKBUILD)/.headers: $(SED) 's,^CROSS=.*,CROSS=$(TARGET_CROSS),g' $(WRKBUILD)/Rules.mak sed -e 's^KERNEL_HEADERS.*$$KERNEL_HEADERS=\"${TOOLCHAIN_SYSROOT}/usr/include\"' \ -- cgit v1.2.3 From a206070dd67744e3be5c54c80ed9dc00f55c28cb Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 12 Aug 2009 23:19:38 +0200 Subject: fix openswan - avoid busybox IP when openswan is selected - fix crypto dependencies for esp --- mk/build.mk | 4 ++-- package/busybox/config/networking/Config.in | 2 ++ package/busybox/patches/003-ip-config.patch | 18 ++++++++++++++++++ target/linux/config/Config.in.crypto | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 package/busybox/patches/003-ip-config.patch diff --git a/mk/build.mk b/mk/build.mk index 399d57216..b9e6b5d56 100644 --- a/mk/build.mk +++ b/mk/build.mk @@ -33,8 +33,8 @@ POSTCONFIG= -@\ done; \ fi; \ if [ "$$(grep ^BUSYBOX .config|md5sum)" != "$$(grep ^BUSYBOX .config.old|md5sum)" ];then \ - if [ -f build_$(CPU_ARCH)/w-busybox*/busybox*/.configure_done ];then \ - rm build_$(CPU_ARCH)/w-busybox*/busybox*/.configure_done; \ + if [ -f build_*/w-busybox*/busybox*/.configure_done ];then \ + rm build_*/w-busybox*/busybox*/.configure_done; \ fi; \ fi; \ fi diff --git a/package/busybox/config/networking/Config.in b/package/busybox/config/networking/Config.in index 3bd3e1e8f..ca92ac7f9 100644 --- a/package/busybox/config/networking/Config.in +++ b/package/busybox/config/networking/Config.in @@ -338,6 +338,7 @@ config BUSYBOX_FEATURE_IFUPDOWN_IP_BUILTIN bool "Use busybox ip applet" default y depends on BUSYBOX_FEATURE_IFUPDOWN_IP + depends on !ADK_PACKAGE_IP select BUSYBOX_IP select BUSYBOX_FEATURE_IP_ADDRESS select BUSYBOX_FEATURE_IP_LINK @@ -456,6 +457,7 @@ config BUSYBOX_FEATURE_INETD_RPC config BUSYBOX_IP bool "ip" default y + depends on !ADK_PACKAGE_IP help The "ip" applet is a TCP/IP interface configuration and routing utility. You generally don't need "ip" to use busybox with diff --git a/package/busybox/patches/003-ip-config.patch b/package/busybox/patches/003-ip-config.patch new file mode 100644 index 000000000..8c32dafe6 --- /dev/null +++ b/package/busybox/patches/003-ip-config.patch @@ -0,0 +1,18 @@ +diff -Nur busybox-1.13.4.orig/networking/Config.in busybox-1.13.4/networking/Config.in +--- busybox-1.13.4.orig/networking/Config.in 2008-11-09 18:27:59.000000000 +0100 ++++ busybox-1.13.4/networking/Config.in 2009-08-12 23:12:27.132893048 +0200 +@@ -338,10 +338,10 @@ + bool "Use busybox ip applet" + default y + depends on FEATURE_IFUPDOWN_IP +- select IP +- select FEATURE_IP_ADDRESS +- select FEATURE_IP_LINK +- select FEATURE_IP_ROUTE ++ #select IP ++ #select FEATURE_IP_ADDRESS ++ #select FEATURE_IP_LINK ++ #select FEATURE_IP_ROUTE + help + Use the busybox iproute "ip" applet to implement "ifupdown". + diff --git a/target/linux/config/Config.in.crypto b/target/linux/config/Config.in.crypto index 42e723db9..8a7b534ca 100644 --- a/target/linux/config/Config.in.crypto +++ b/target/linux/config/Config.in.crypto @@ -106,6 +106,7 @@ config ADK_KPACKAGE_KMOD_CRYPTO_AEAD tristate default n select ADK_KERNEL_CRYPTO + select ADK_KPACKAGE_KMOD_CRYPTO_ALGAPI help config ADK_KPACKAGE_KMOD_CRYPTO_MANAGER -- cgit v1.2.3 From 7a265338683b6e8100d34eda6e04b113ceba0e7f Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 13 Aug 2009 00:07:42 +0200 Subject: enable cfgfs for rb532 - choose backend at runtime - do not hardcode partition device anymore --- package/cfgfs/Config.in | 3 ++- package/cfgfs/Makefile | 11 +---------- package/cfgfs/src/fwcf.sh | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/package/cfgfs/Config.in b/package/cfgfs/Config.in index 78051901b..e3412a458 100644 --- a/package/cfgfs/Config.in +++ b/package/cfgfs/Config.in @@ -4,7 +4,8 @@ config ADK_PACKAGE_CFGFS select BUSYBOX_COMM select BUSYBOX_MD5SUM select BUSYBOX_FEATURE_SORT_BIG - depends on ADK_LINUX_X86_ALIX1C || ADK_LINUX_CRIS_FOXBOARD + depends on ADK_LINUX_X86_ALIX1C || ADK_LINUX_CRIS_FOXBOARD || \ + ADK_LINUX_MIPS_RB532 default y help Adopted from FreeWRT fwcf diff --git a/package/cfgfs/Makefile b/package/cfgfs/Makefile index 1485cb9d9..790f536fc 100644 --- a/package/cfgfs/Makefile +++ b/package/cfgfs/Makefile @@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk PKG_NAME:= cfgfs PKG_VERSION:= 1.0.6 -PKG_RELEASE:= 2 +PKG_RELEASE:= 3 PKG_DESCR:= compressed config filesystem PKG_SECTION:= base @@ -27,14 +27,5 @@ do-install: ${INSTALL_DIR} ${IDIR_CFGFS}/sbin ${INSTALL_BIN} ${WRKBUILD}/fwcf.sh ${IDIR_CFGFS}/sbin/cfgfs ${INSTALL_BIN} ${WRKBUILD}/fwcf.helper.out ${IDIR_CFGFS}/sbin/cfgfs.helper -ifeq ($(ARCH),cris) - ${INSTALL_BIN} ${WRKBUILD}/mtd ${IDIR_CFGFS}/sbin/mtd - echo '#!/bin/sh' > ${IDIR_CFGFS}/sbin/cfgfs.write - echo 'mtd -F write - cfgfs' >> ${IDIR_CFGFS}/sbin/cfgfs.write -else - echo '#!/bin/sh' > ${IDIR_CFGFS}/sbin/cfgfs.write - echo 'cat > /dev/sda2' >> ${IDIR_CFGFS}/sbin/cfgfs.write -endif - chmod 755 ${IDIR_CFGFS}/sbin/cfgfs.write include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/cfgfs/src/fwcf.sh b/package/cfgfs/src/fwcf.sh index fcaaf80a0..84eef3780 100644 --- a/package/cfgfs/src/fwcf.sh +++ b/package/cfgfs/src/fwcf.sh @@ -114,10 +114,12 @@ EOF esac # find backend device, first try to find partition with ID 88 +mtd=0 part=$(fdisk -l|awk '$5 == 88 { print $1 }') if [ -z $part ]; then # otherwise search for MTD device with name cfgfs part=/dev/mtd$(fgrep '"cfgfs"' /proc/mtd 2>/dev/null | sed 's/^mtd\([^:]*\):.*$/\1/')ro + mtd=1 fi if [[ ! -e $part ]]; then @@ -127,7 +129,11 @@ fi if test $1 = erase; then dd if="$part" 2>&1 | md5sum 2>&1 >/dev/urandom - cfgfs.helper -Me | cfgfs.write + if [ $mtd -eq 1 ]; then + cfgfs.helper -Me | mtd -F write - cfgfs + else + cfgfs.helper -Me | cat > $part + fi exit $? fi @@ -153,7 +159,12 @@ if test $1 = setup; then unclean=2 else x=$(dd if="$part" bs=4 count=1 2>/dev/null) - [[ "$x" = "FWCF" ]] || cfgfs.helper -Me | cfgfs.write + [[ "$x" = "FWCF" ]] || \ + if [ $mtd -eq 1 ]; then + cfgfs.helper -Me | mtd -F write - cfgfs + else + cfgfs.helper -Me | cat > $part + fi if ! cfgfs.helper -U /tmp/.cfgfs/temp <"$part"; then unclean=1 echo 'cfgfs: error: cannot extract' @@ -246,9 +257,16 @@ if test $1 = commit; then [[ "$x" = "$y" ]] && rm "../temp/$f" done rv=0 - if ! ( cfgfs.helper -M /tmp/.cfgfs/temp | cfgfs.write ); then - echo 'cfgfs: error: cannot write to $part!' - rv=6 + if [ $mtd -eq 1 ]; then + if ! ( cfgfs.helper -M /tmp/.cfgfs/temp | mtd -F write - cfgfs ); then + echo 'cfgfs: error: cannot write to $part!' + rv=6 + fi + else + if ! ( cfgfs.helper -M /tmp/.cfgfs/temp | cat > $part ); then + echo 'cfgfs: error: cannot write to $part!' + rv=6 + fi fi umount /tmp/.cfgfs/temp exit $rv @@ -368,9 +386,16 @@ if test $1 = restore; then rm -rf /tmp/.cfgfs.restore exit 12 fi - if ! ( cfgfs.helper -MD dump | cfgfs.write ); then - echo 'cfgfs: error: cannot write to $part!' - exit 6 + if [ $mtd -eq 1 ]; then + if ! ( cfgfs.helper -MD dump | mtd -F write - cfgfs ); then + echo 'cfgfs: error: cannot write to $part!' + exit 6 + fi + else + if ! ( cfgfs.helper -MD dump | cat > $part ); then + echo 'cfgfs: error: cannot write to $part!' + exit 6 + fi fi cd / rm -rf /tmp/.cfgfs.restore -- cgit v1.2.3 From 61d89dc5b0c09b1d89849eb4385835d8cbdd4cb3 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 20 Aug 2009 17:30:08 +0200 Subject: add correct kernel config (page size) --- target/lemote/Makefile | 12 ++++++++++-- target/lemote/kernel.config | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/target/lemote/Makefile b/target/lemote/Makefile index 3c473aee1..d27d3a37f 100644 --- a/target/lemote/Makefile +++ b/target/lemote/Makefile @@ -7,8 +7,11 @@ include $(TOPDIR)/mk/modules.mk include $(TOPDIR)/mk/kernel-build.mk include $(TOPDIR)/mk/image.mk +OSTRIP:=-R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id + kernel-install: - cp $(LINUX_DIR)/vmlinux $(BIN_DIR)/${DEVICE}-${ARCH}-kernel + $(KERNEL_CROSS)objcopy $(OSTRIP) -S $(LINUX_DIR)/vmlinux \ + $(BIN_DIR)/${DEVICE}-${ARCH}-kernel ifeq ($(FS),nfsroot) imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL) @@ -17,7 +20,12 @@ imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL) endif ifeq ($(FS),initramfs) imageinstall: $(BIN_DIR)/$(INITRAMFS) - cp $(LINUX_DIR)/vmlinux $(BIN_DIR)/${DEVICE}-${ARCH}-kernel @echo 'The kernel file is: ${BIN_DIR}/${DEVICE}-${ARCH}-kernel' @echo 'The initramfs image is: ${BIN_DIR}/${INITRAMFS}' endif +ifeq ($(FS),ext2) +imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL) + @echo + @echo 'The kernel file is: ${BIN_DIR}/${DEVICE}-${ARCH}-kernel' + @echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSTARBALL)," +endif diff --git a/target/lemote/kernel.config b/target/lemote/kernel.config index 61afec593..f51a5d828 100644 --- a/target/lemote/kernel.config +++ b/target/lemote/kernel.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.30 -# Sun Jun 21 18:23:45 2009 +# Fri Jul 3 19:30:18 2009 # CONFIG_MIPS=y @@ -119,9 +119,9 @@ CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y # # CONFIG_32BIT is not set CONFIG_64BIT=y -CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_4KB is not set # CONFIG_PAGE_SIZE_8KB is not set -# CONFIG_PAGE_SIZE_16KB is not set +CONFIG_PAGE_SIZE_16KB=y # CONFIG_PAGE_SIZE_32KB is not set # CONFIG_PAGE_SIZE_64KB is not set CONFIG_BOARD_SCACHE=y -- cgit v1.2.3 From 4a0a9fe7fee9d7032adc62e244a23d37013816e3 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 20 Aug 2009 20:39:56 +0200 Subject: update foxboard to latest stuff --- target/foxboard/Makefile | 2 +- target/foxboard/device.mk | 4 +- target/foxboard/patches/cris.patch | 216 +++++++++++-------------------------- toolchain/uClibc/Makefile | 4 + 4 files changed, 69 insertions(+), 157 deletions(-) diff --git a/target/foxboard/Makefile b/target/foxboard/Makefile index 5a7c98c42..a72a0b6e1 100644 --- a/target/foxboard/Makefile +++ b/target/foxboard/Makefile @@ -18,7 +18,7 @@ tools-compile: $(TOOLS_BUILD_DIR) kernel-install: tools-compile PATH='${TARGET_PATH}' \ - mkfimage $(LINUX_DIR)/arch/cris/arch-v10/boot/zImage \ + mkfimage $(LINUX_DIR)/arch/cris/boot/zImage \ $(BIN_DIR)/${DEVICE}-${ARCH}-kernel $(MAKE_TRACE) ifeq ($(FS),squashfs) diff --git a/target/foxboard/device.mk b/target/foxboard/device.mk index 0c7504fbd..e9be810b6 100644 --- a/target/foxboard/device.mk +++ b/target/foxboard/device.mk @@ -1,7 +1,7 @@ ARCH:= cris CPU_ARCH:= cris -KERNEL_VERSION:= 2.6.29.1 +KERNEL_VERSION:= 2.6.30.5 KERNEL_RELEASE:= 1 -KERNEL_MD5SUM:= 4ada43caecb08fe2af71b416b6f586d8 +KERNEL_MD5SUM:= be9c3a697a54ac099c910d068ff0dc03 TARGET_OPTIMIZATION:= -Os -pipe -fno-peephole2 TARGET_CFLAGS_ARCH:= -march=v10 diff --git a/target/foxboard/patches/cris.patch b/target/foxboard/patches/cris.patch index e0522d674..20dc5121c 100644 --- a/target/foxboard/patches/cris.patch +++ b/target/foxboard/patches/cris.patch @@ -1,6 +1,6 @@ -diff -Nur linux-2.6.29.1.orig/arch/cris/Kconfig linux-2.6.29.1/arch/cris/Kconfig ---- linux-2.6.29.1.orig/arch/cris/Kconfig 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/Kconfig 2009-05-09 01:52:49.814118199 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/Kconfig /tmp/linux-2.6.30.5/arch/cris/Kconfig +--- linux-2.6.30.5.orig/arch/cris/Kconfig 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/Kconfig 2009-08-20 18:55:37.850545072 +0200 @@ -168,6 +168,12 @@ help Size of DRAM (decimal in MB) typically 2, 8 or 16. @@ -35,9 +35,9 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/Kconfig linux-2.6.29.1/arch/cris/Kconfig source "drivers/net/Kconfig" source "drivers/i2c/Kconfig" -diff -Nur linux-2.6.29.1.orig/arch/cris/Makefile linux-2.6.29.1/arch/cris/Makefile ---- linux-2.6.29.1.orig/arch/cris/Makefile 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/Makefile 2009-05-09 01:53:12.795556299 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/Makefile /tmp/linux-2.6.30.5/arch/cris/Makefile +--- linux-2.6.30.5.orig/arch/cris/Makefile 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/Makefile 2009-08-20 18:55:37.850545072 +0200 @@ -40,12 +40,12 @@ LD = $(CROSS_COMPILE)ld -mcrislinux @@ -53,102 +53,9 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/Makefile linux-2.6.29.1/arch/cris/Makefi KBUILD_CPPFLAGS += $(inc) ifdef CONFIG_FRAME_POINTER -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/boot/Makefile linux-2.6.29.1/arch/cris/arch-v10/boot/Makefile ---- linux-2.6.29.1.orig/arch/cris/arch-v10/boot/Makefile 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/boot/Makefile 2009-05-09 01:52:50.030131736 +0200 -@@ -2,10 +2,8 @@ - # arch/cris/arch-v10/boot/Makefile - # - --OBJCOPYFLAGS = -O binary --remove-section=.bss -- - subdir- := compressed rescue --targets := Image -+targets := Image zImage - - $(obj)/Image: vmlinux FORCE - $(call if_changed,objcopy) -@@ -13,7 +11,6 @@ - - $(obj)/compressed/vmlinux: $(obj)/Image FORCE - $(Q)$(MAKE) $(build)=$(obj)/compressed $@ -- $(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin - - $(obj)/zImage: $(obj)/compressed/vmlinux - @cp $< $@ -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/boot/compressed/Makefile linux-2.6.29.1/arch/cris/arch-v10/boot/compressed/Makefile ---- linux-2.6.29.1.orig/arch/cris/arch-v10/boot/compressed/Makefile 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/boot/compressed/Makefile 2009-05-09 01:52:50.102136724 +0200 -@@ -6,7 +6,6 @@ - ccflags-y += -O2 $(LINUXINCLUDE) - ldflags-y += -T $(srctree)/$(src)/decompress.lds - OBJECTS = $(obj)/head.o $(obj)/misc.o --OBJCOPYFLAGS = -O binary --remove-section=.bss - - quiet_cmd_image = BUILD $@ - cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@ -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/boot/compressed/misc.c linux-2.6.29.1/arch/cris/arch-v10/boot/compressed/misc.c ---- linux-2.6.29.1.orig/arch/cris/arch-v10/boot/compressed/misc.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/boot/compressed/misc.c 2009-05-09 01:52:50.126138666 +0200 -@@ -5,7 +5,7 @@ - * adapted for Linux. - * - * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 -- * puts by Nick Holloway 1993, better puts by Martin Mares 1995 -+ * putstr by Nick Holloway 1993, better putstr by Martin Mares 1995 - * adaptation for Linux/CRIS Axis Communications AB, 1999 - * - */ -@@ -102,7 +102,7 @@ - static long bytes_out = 0; - static uch *output_data; - static unsigned long output_ptr = 0; --static void puts(const char *); -+static void putstr(const char *); - - /* the "heap" is put directly after the BSS ends, at end */ - -@@ -115,7 +115,7 @@ - /* decompressor info and error messages to serial console */ - - static void --puts(const char *s) -+putstr(const char *s) - { - #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL - while (*s) { -@@ -188,9 +188,9 @@ - - static void error(char *x) - { -- puts("\n\n"); -- puts(x); -- puts("\n\n -- System halted\n"); -+ putstr("\n\n"); -+ putstr(x); -+ putstr("\n\n -- System halted\n"); - - while (1); /* Halt */ - } -@@ -234,13 +234,7 @@ - - makecrc(); - -- __asm__ volatile ("move $vr,%0" : "=rm" (revision)); -- if (revision < 10) { -- puts("You need an ETRAX 100LX to run linux 2.6\n"); -- while (1); -- } -- -- puts("Uncompressing Linux...\n"); -+ putstr("Uncompressing Linux...\n"); - gunzip(); -- puts("Done. Now booting the kernel.\n"); -+ putstr("Done. Now booting the kernel.\n"); - } -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6.29.1/arch/cris/arch-v10/drivers/axisflashmap.c ---- linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/axisflashmap.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/drivers/axisflashmap.c 2009-05-09 01:52:50.210144343 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/axisflashmap.c /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/axisflashmap.c +--- linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/axisflashmap.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/axisflashmap.c 2009-08-20 18:55:49.807658902 +0200 @@ -122,19 +122,19 @@ */ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { @@ -280,9 +187,9 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2. return err; } -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.29.1/arch/cris/arch-v10/drivers/ds1302.c ---- linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/ds1302.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/drivers/ds1302.c 2009-05-09 01:52:50.538166563 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/ds1302.c /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/ds1302.c +--- linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/ds1302.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/ds1302.c 2009-08-20 18:55:49.811661367 +0200 @@ -21,6 +21,7 @@ #include #include @@ -315,9 +222,9 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.29.1 return 0; } -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.29.1/arch/cris/arch-v10/drivers/gpio.c ---- linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/gpio.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/drivers/gpio.c 2009-05-09 01:52:50.586168771 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/gpio.c /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/gpio.c +--- linux-2.6.30.5.orig/arch/cris/arch-v10/drivers/gpio.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/arch-v10/drivers/gpio.c 2009-08-20 18:55:49.811661367 +0200 @@ -21,6 +21,7 @@ #include #include @@ -351,18 +258,18 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.29.1/a /* Clear all leds */ #if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) CRIS_LED_NETWORK_SET(0); -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.29.1/arch/cris/arch-v10/lib/hw_settings.S ---- linux-2.6.29.1.orig/arch/cris/arch-v10/lib/hw_settings.S 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/lib/hw_settings.S 2009-05-09 01:52:50.690174762 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/arch-v10/lib/hw_settings.S /tmp/linux-2.6.30.5/arch/cris/arch-v10/lib/hw_settings.S +--- linux-2.6.30.5.orig/arch/cris/arch-v10/lib/hw_settings.S 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/arch-v10/lib/hw_settings.S 2009-08-20 18:55:49.811661367 +0200 @@ -60,3 +60,5 @@ .dword R_PORT_PB_SET .dword PB_SET_VALUE .dword 0 ; No more register values + .ascii "ACME_PART_MAGIC" + .dword 0xdeadc0de -diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/mm/init.c linux-2.6.29.1/arch/cris/arch-v10/mm/init.c ---- linux-2.6.29.1.orig/arch/cris/arch-v10/mm/init.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/arch/cris/arch-v10/mm/init.c 2009-05-09 01:52:50.754179285 +0200 +diff -Nur linux-2.6.30.5.orig/arch/cris/arch-v10/mm/init.c /tmp/linux-2.6.30.5/arch/cris/arch-v10/mm/init.c +--- linux-2.6.30.5.orig/arch/cris/arch-v10/mm/init.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/arch/cris/arch-v10/mm/init.c 2009-08-20 18:55:49.811661367 +0200 @@ -184,6 +184,9 @@ free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); @@ -373,10 +280,10 @@ diff -Nur linux-2.6.29.1.orig/arch/cris/arch-v10/mm/init.c linux-2.6.29.1/arch/c /* Initialize remaps of some I/O-ports. It is important that this * is called before any driver is initialized. -diff -Nur linux-2.6.29.1.orig/drivers/net/cris/eth_v10.c linux-2.6.29.1/drivers/net/cris/eth_v10.c ---- linux-2.6.29.1.orig/drivers/net/cris/eth_v10.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/drivers/net/cris/eth_v10.c 2009-05-09 01:52:50.754179285 +0200 -@@ -1705,7 +1705,7 @@ +diff -Nur linux-2.6.30.5.orig/drivers/net/cris/eth_v10.c /tmp/linux-2.6.30.5/drivers/net/cris/eth_v10.c +--- linux-2.6.30.5.orig/drivers/net/cris/eth_v10.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/drivers/net/cris/eth_v10.c 2009-08-20 18:55:49.811661367 +0200 +@@ -1711,7 +1711,7 @@ static void e100_netpoll(struct net_device* netdev) { @@ -385,26 +292,26 @@ diff -Nur linux-2.6.29.1.orig/drivers/net/cris/eth_v10.c linux-2.6.29.1/drivers/ } #endif -diff -Nur linux-2.6.29.1.orig/drivers/serial/crisv10.c linux-2.6.29.1/drivers/serial/crisv10.c ---- linux-2.6.29.1.orig/drivers/serial/crisv10.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/drivers/serial/crisv10.c 2009-05-09 01:52:50.758178956 +0200 -@@ -27,6 +27,7 @@ +diff -Nur linux-2.6.30.5.orig/drivers/serial/crisv10.c /tmp/linux-2.6.30.5/drivers/serial/crisv10.c +--- linux-2.6.30.5.orig/drivers/serial/crisv10.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/drivers/serial/crisv10.c 2009-08-20 18:58:30.409697920 +0200 +@@ -26,6 +26,7 @@ #include #include #include +#include - - #include - #include -@@ -4393,6 +4394,7 @@ - .tiocmset = rs_tiocmset + #include + #include + #include +@@ -4414,6 +4415,7 @@ + #endif }; +static struct class *rs_class; - static int __init - rs_init(void) + static int __init rs_init(void) { -@@ -4527,6 +4529,24 @@ + int i; +@@ -4547,6 +4549,24 @@ #endif #endif /* CONFIG_SVINTO_SIM */ @@ -429,28 +336,28 @@ diff -Nur linux-2.6.29.1.orig/drivers/serial/crisv10.c linux-2.6.29.1/drivers/se return 0; } -diff -Nur linux-2.6.29.1.orig/drivers/usb/Makefile linux-2.6.29.1/drivers/usb/Makefile ---- linux-2.6.29.1.orig/drivers/usb/Makefile 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/drivers/usb/Makefile 2009-05-09 01:52:50.758178956 +0200 +diff -Nur linux-2.6.30.5.orig/drivers/usb/Makefile /tmp/linux-2.6.30.5/drivers/usb/Makefile +--- linux-2.6.30.5.orig/drivers/usb/Makefile 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/drivers/usb/Makefile 2009-08-20 18:57:11.704787130 +0200 @@ -19,6 +19,7 @@ - obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/ + obj-$(CONFIG_USB_ISP1760_HCD) += host/ +obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ -diff -Nur linux-2.6.29.1.orig/drivers/usb/host/Makefile linux-2.6.29.1/drivers/usb/host/Makefile ---- linux-2.6.29.1.orig/drivers/usb/host/Makefile 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/drivers/usb/host/Makefile 2009-05-09 01:52:50.758178956 +0200 +diff -Nur linux-2.6.30.5.orig/drivers/usb/host/Makefile /tmp/linux-2.6.30.5/drivers/usb/host/Makefile +--- linux-2.6.30.5.orig/drivers/usb/host/Makefile 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/drivers/usb/host/Makefile 2009-08-20 18:55:49.819660151 +0200 @@ -29,3 +29,4 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o +obj-$(CONFIG_ETRAX_USB_HOST) += hc-crisv10.o -diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.29.1/drivers/usb/host/hc-cris-dbg.h ---- linux-2.6.29.1.orig/drivers/usb/host/hc-cris-dbg.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.29.1/drivers/usb/host/hc-cris-dbg.h 2009-05-09 01:52:50.762178907 +0200 +diff -Nur linux-2.6.30.5.orig/drivers/usb/host/hc-cris-dbg.h /tmp/linux-2.6.30.5/drivers/usb/host/hc-cris-dbg.h +--- linux-2.6.30.5.orig/drivers/usb/host/hc-cris-dbg.h 1970-01-01 01:00:00.000000000 +0100 ++++ /tmp/linux-2.6.30.5/drivers/usb/host/hc-cris-dbg.h 2009-08-20 18:55:49.839661303 +0200 @@ -0,0 +1,146 @@ + +/* macros for debug output */ @@ -598,10 +505,10 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.29.1/driv + }; \ + s; \ + }) -diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drivers/usb/host/hc-crisv10.c ---- linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.29.1/drivers/usb/host/hc-crisv10.c 2009-05-09 01:52:50.834182770 +0200 -@@ -0,0 +1,4800 @@ +diff -Nur linux-2.6.30.5.orig/drivers/usb/host/hc-crisv10.c /tmp/linux-2.6.30.5/drivers/usb/host/hc-crisv10.c +--- linux-2.6.30.5.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100 ++++ /tmp/linux-2.6.30.5/drivers/usb/host/hc-crisv10.c 2009-08-20 20:04:48.211654313 +0200 +@@ -0,0 +1,4801 @@ +/* + * + * ETRAX 100LX USB Host Controller Driver @@ -2832,6 +2739,7 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive + int epid; + char toggle; + int urb_num; ++ unsigned long flags; + + DBFENTER; + ASSERT(urb_priv != NULL); @@ -2999,7 +2907,6 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive + + /*hinko link/unlink urb -> ep */ + //spin_lock(&crisv10_hcd->lock); -+ unsigned long flags; + spin_lock_irqsave(&crisv10_hcd->lock, flags); + usb_hcd_unlink_urb_from_ep(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); @@ -5142,6 +5049,7 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive + struct usb_hcd *hcd; + struct crisv10_hcd *crisv10_hcd; + int retval; ++ int rev_maj, rev_min; + + /* Check DMA burst length */ + if(IO_EXTRACT(R_BUS_CONFIG, dma_burst, *R_BUS_CONFIG) != @@ -5151,7 +5059,7 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive + return -EPERM; + } + -+ hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev->bus_id); ++ hcd = usb_create_hcd(&crisv10_hc_driver, dev, dev_name(dev)); + if (!hcd) + return -ENOMEM; + @@ -5166,8 +5074,8 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive + ETRAX_USB_RX_IRQ, ETRAX_USB_TX_IRQ); + + /* Print out chip version read from registers */ -+ int rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major); -+ int rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor); ++ rev_maj = *R_USB_REVISION & IO_MASK(R_USB_REVISION, major); ++ rev_min = *R_USB_REVISION & IO_MASK(R_USB_REVISION, minor); + if(rev_min == 0) { + devdrv_info("Etrax 100LX USB Revision %d v1,2\n", rev_maj); + } else { @@ -5402,9 +5310,9 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.c linux-2.6.29.1/drive +/* Module hooks */ +module_init(module_hcd_init); +module_exit(module_hcd_exit); -diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.h linux-2.6.29.1/drivers/usb/host/hc-crisv10.h ---- linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.29.1/drivers/usb/host/hc-crisv10.h 2009-05-09 01:52:50.842184906 +0200 +diff -Nur linux-2.6.30.5.orig/drivers/usb/host/hc-crisv10.h /tmp/linux-2.6.30.5/drivers/usb/host/hc-crisv10.h +--- linux-2.6.30.5.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100 ++++ /tmp/linux-2.6.30.5/drivers/usb/host/hc-crisv10.h 2009-08-20 18:55:50.199684523 +0200 @@ -0,0 +1,331 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H @@ -5737,9 +5645,9 @@ diff -Nur linux-2.6.29.1.orig/drivers/usb/host/hc-crisv10.h linux-2.6.29.1/drive +#define USB_SB_command__full__yes 1 + +#endif -diff -Nur linux-2.6.29.1.orig/lib/klist.c linux-2.6.29.1/lib/klist.c ---- linux-2.6.29.1.orig/lib/klist.c 2009-04-02 22:55:27.000000000 +0200 -+++ linux-2.6.29.1/lib/klist.c 2009-05-09 01:52:50.846185695 +0200 +diff -Nur linux-2.6.30.5.orig/lib/klist.c /tmp/linux-2.6.30.5/lib/klist.c +--- linux-2.6.30.5.orig/lib/klist.c 2009-08-16 23:19:38.000000000 +0200 ++++ /tmp/linux-2.6.30.5/lib/klist.c 2009-08-20 18:55:50.199684523 +0200 @@ -60,7 +60,7 @@ { knode->n_klist = klist; diff --git a/toolchain/uClibc/Makefile b/toolchain/uClibc/Makefile index 69b5d343a..2ac996fe8 100644 --- a/toolchain/uClibc/Makefile +++ b/toolchain/uClibc/Makefile @@ -12,6 +12,10 @@ include ${TOPDIR}/mk/buildhlp.mk ifeq ($(ARCH),mips) TARGET_CFLAGS:=$(subst Os,O2,$(TARGET_CFLAGS)) endif +#workaround for cris and gcc 4.4, where -Os generates ICE +ifeq ($(ARCH),cris) +TARGET_CFLAGS:=$(subst Os,O2,$(TARGET_CFLAGS)) +endif $(WRKBUILD)/.headers: $(SED) 's,^CROSS=.*,CROSS=$(TARGET_CROSS),g' $(WRKBUILD)/Rules.mak -- cgit v1.2.3