]> code.ossystems Code Review - openembedded-core.git/commitdiff
linux-rp: upgraded from 2.6.23+git to 2.6.24-rc1
authorMarcin Juszkiewicz <hrw@openedhand.com>
Wed, 24 Oct 2007 10:51:45 +0000 (10:51 +0000)
committerMarcin Juszkiewicz <hrw@openedhand.com>
Wed, 24 Oct 2007 10:51:45 +0000 (10:51 +0000)
Updated patches:
- hx2750_base
- pxa27x_overlay
- squashfs3 (does not build anyway)

Disabled patches:
- input_power (does not like LONG() function)
- tsc2101 (breaks Kconfig - something with MACH_HX2750)
- squashfs3

Builds for c7x0 but is too big.

git-svn-id: https://svn.o-hand.com/repos/poky/trunk@2951 311d38ba-8fff-0310-9ca6-ca027cbcb966

33 files changed:
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/arm_pxa_20070923.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/arm_pxa_20070923.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/binutils-buildid-arm.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/binutils-buildid-arm.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/connectplus-remove-ide-HACK.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/connectplus-remove-ide-HACK.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-akita [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-akita with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-bootcdx86 [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-bootcdx86 with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-c7x0 [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-c7x0 with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-collie [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-collie with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-htcuniversal [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-htcuniversal with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-hx2000 [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-hx2000 with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-poodle [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-poodle with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-qemuarm [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-qemuarm with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-qemux86 [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-qemux86 with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-spitz [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-spitz with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-tosa [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-tosa with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/defconfig-zylonite [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/defconfig-zylonite with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/hostap-monitor-mode.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/hostap-monitor-mode.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/htcuni-acx.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/htcuni-acx.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/htcuni.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/htcuni.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/hx2750_base-r31.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/mmcsd_no_scr_check-r2.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/mmcsd_no_scr_check-r2.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pda-power.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pxa-serial-hack.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pxa-serial-hack.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pxa27x_overlay-r8.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pxa_fb_overlay.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pxa_fb_overlay.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/serial-add-support-for-non-standard-xtals-to-16c950-driver.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/serial-add-support-for-non-standard-xtals-to-16c950-driver.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/squashfs3.0-2.6.15.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/squashfs3.0-2.6.15.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/squashfs3.2-2.6.20-r0.patch [new file with mode: 0644]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/uvesafb-0.1-rc3-2.6.22.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/uvesafb-0.1-rc3-2.6.22.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/vt_ioctl_race.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/vt_ioctl_race.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/w100fb-unused-var.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/w100fb-unused-var.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/wm97xx-lcdnoise-r0.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/wm97xx-lcdnoise-r0.patch with 100% similarity]
meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/zylonite-boot.patch [moved from meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/zylonite-boot.patch with 100% similarity]
meta/packages/linux/linux-rp_2.6.23+2.6.24-rc1.bb [moved from meta/packages/linux/linux-rp_2.6.23+2.6.24-rc0+git.bb with 90% similarity]

diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/hx2750_base-r31.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/hx2750_base-r31.patch
new file mode 100644 (file)
index 0000000..5d58bcf
--- /dev/null
@@ -0,0 +1,1094 @@
+---
+ arch/arm/mach-pxa/Kconfig         |   10 
+ arch/arm/mach-pxa/Makefile        |    1 
+ arch/arm/mach-pxa/hx2750.c        |  450 ++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-pxa/hx2750_test.c   |  433 ++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-pxa/pm.c            |    5 
+ arch/arm/mach-pxa/pxa25x.c        |    4 
+ arch/arm/mach-pxa/pxa27x.c        |    4 
+ include/asm-arm/arch-pxa/hx2750.h |   90 +++++++
+ 8 files changed, 995 insertions(+), 2 deletions(-)
+
+--- /dev/null
++++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/hx2750.h
+@@ -0,0 +1,90 @@
++/*
++ * Hardware specific definitions for iPAQ hx2750
++ *
++ * Copyright 2005 Openedhand Ltd.
++ *
++ * Author: Richard Purdie <richard@o-hand.com>
++ *
++ * 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.
++ *
++ */
++#ifndef __ASM_ARCH_HX2750_H
++#define __ASM_ARCH_HX2750_H  1
++
++/*
++ * HX2750 (Non Standard) GPIO Definitions
++ */
++
++#define HX2750_GPIO_KEYPWR      (0)    /* Power button */
++#define HX2750_GPIO_BATTCOVER1  (9)    /* Battery Cover Switch */
++#define HX2750_GPIO_CF_IRQ      (11)   /* CF IRQ? */
++#define HX2750_GPIO_USBCONNECT  (12)   /* USB Connected? */
++#define HX2750_GPIO_CF_DETECT   (13)   /* CF Card Detect? */
++#define HX2750_GPIO_EXTPWR      (14)   /* External Power Detect */
++#define HX2750_GPIO_BATLVL      (15)   /* Battery Level Detect */
++#define HX2750_GPIO_CF_PWR      (17)   /* CF Power? */
++#define HX2750_GPIO_SR_STROBE   (18)   /* Shift Register Strobe */
++#define HX2750_GPIO_CHARGE      (22)   /* Charging Enable (active low) */
++#define HX2750_GPIO_TSC2101_SS  (24)   /* TSC2101 SS# */
++#define HX2750_GPIO_BTPWR       (27)   /* Bluetooth Power? */
++#define HX2750_GPIO_BATTCOVER2  (33)   /* Battery Cover Switch */
++#define HX2750_GPIO_SD_DETECT   (38)   /* MMC Card Detect */
++#define HX2750_GPIO_SR_CLK1     (52)   /* Shift Register Clock */
++#define HX2750_GPIO_SR_CLK2     (53)
++#define HX2750_GPIO_CF_WIFIIRQ  (54)   /* CF Wifi IRQ? */
++#define HX2750_GPIO_GPIO_DIN    (88)   /* Shift Register Data */
++#define HX2750_GPIO_KEYLEFT     (90)   /* Left button */
++#define HX2750_GPIO_KEYRIGHT    (91)   /* Right button */
++#define HX2750_GPIO_KEYCAL      (93)   /* Calander button */
++#define HX2750_GPIO_KEYTASK     (94)   /* Task button */
++#define HX2750_GPIO_KEYSIDE     (95)   /* Side button */
++#define HX2750_GPIO_KEYENTER    (96)   /* Enter Button*/
++#define HX2750_GPIO_KEYCON      (97)   /* Contacts button */
++#define HX2750_GPIO_KEYMAIL     (98)   /* Mail button */
++#define HX2750_GPIO_BIOPWR      (99)   /* BIO Reader Power? */
++#define HX2750_GPIO_KEYUP       (100)  /* Up button */
++#define HX2750_GPIO_KEYDOWN     (101)  /* Down button*/
++#define HX2750_GPIO_SD_READONLY (103)  /* MMC/SD Write Protection */
++#define HX2750_GPIO_LEDMAIL     (106)  /* Green Mail LED */
++#define HX2750_GPIO_HP_JACK     (108)  /* Head Phone Jack Present */
++#define HX2750_GPIO_PENDOWN     (117)  /* Touch Screen Pendown */
++
++
++//#define HX2750_GPIO_     () /* */
++
++/*
++ * HX2750 Interrupts
++ */
++#define HX2750_IRQ_GPIO_EXTPWR      IRQ_GPIO(HX2750_GPIO_EXTPWR)
++#define HX2750_IRQ_GPIO_SD_DETECT   IRQ_GPIO(HX2750_GPIO_SD_DETECT)
++#define HX2750_IRQ_GPIO_PENDOWN     IRQ_GPIO(HX2750_GPIO_PENDOWN)
++#define HX2750_IRQ_GPIO_CF_DETECT   IRQ_GPIO(HX2750_GPIO_CF_DETECT)
++#define HX2750_IRQ_GPIO_CF_IRQ      IRQ_GPIO(HX2750_GPIO_CF_IRQ)
++#define HX2750_IRQ_GPIO_CF_WIFIIRQ  IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ)
++
++/*
++ * HX2750 Extra GPIO Definitions
++ */
++
++#define HX2750_EGPIO_WIFI_PWR (1 << 11)  /* Wifi power */
++#define HX2750_EGPIO_LCD_PWR  (1 << 10)  /* LCD Power */
++#define HX2750_EGPIO_BL_PWR     (1 << 9)   /* Backlight LED Power */
++#define HX2750_EGPIO_8          (1 << 8)   /* */
++#define HX2750_EGPIO_7          (1 << 7)   /* */
++#define HX2750_EGPIO_SD_PWR     (1 << 6)   /* SD Power */
++#define HX2750_EGPIO_TSC_PWR    (1 << 5)   /* TS Power */
++#define HX2750_EGPIO_CF0_RESET  (1 << 4)   /* CF0 Reset */
++#define HX2750_EGPIO_CF1_RESET  (1 << 3)   /* CF1 Reset */
++#define HX2750_EGPIO_2          (1 << 2)   /* Power/Red LED Related?*/
++#define HX2750_EGPIO_1          (1 << 1)   /* Power/Red LED Related?*/
++#define HX2750_EGPIO_PWRLED     (1 << 0)   /* Power/Red LED Related?*/
++
++
++void hx2750_set_egpio(unsigned int gpio);
++void hx2750_clear_egpio(unsigned int gpio);
++
++
++#endif /* __ASM_ARCH_HX2750_H  */
++
+--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Makefile
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/Makefile
+@@ -22,6 +22,7 @@
+ obj-$(CONFIG_MACH_POODLE)     += poodle.o corgi_ssp.o
+ obj-$(CONFIG_MACH_TOSA)               += tosa.o
+ obj-$(CONFIG_MACH_EM_X270)    += em-x270.o
++obj-$(CONFIG_MACH_HX2750)     += hx2750.o hx2750_test.o
+ ifeq ($(CONFIG_MACH_ZYLONITE),y)
+   obj-y                               += zylonite.o
+--- /dev/null
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750_test.c
+@@ -0,0 +1,433 @@
++/*
++ * HP iPAQ hx2750 Test Development Code
++ *
++ * Copyright 2005 Openedhand Ltd.
++ *
++ * Author: Richard Purdie <richard@o-hand.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/mach/arch.h>
++
++#include <asm/arch/hx2750.h>
++#include <asm/arch/pxa-regs.h>
++
++
++static int prodval;
++
++/*
++ * Sysfs functions
++ */
++static ssize_t test1_show(struct device *dev, char *buf)
++{
++      unsigned long rp;
++
++      asm ("mrc       p15, 0, %0, cr1, cr0;\n" :"=r"(rp) );
++      printk("%lx\n",rp);
++
++      asm ("mrc       p15, 0, %0, cr1, cr1;\n" :"=r"(rp) );
++      printk("%lx\n",rp);
++
++      asm ("mrc       p15, 0, %0, cr2, cr0;\n" :"=r"(rp) );
++      printk("%lx\n",rp);
++
++      asm ("mrc       p15, 0, %0, cr3, cr0;\n" :"=r"(rp) );
++      printk("%lx\n",rp);
++
++      asm ("mrc       p15, 0, %0, cr13, cr0;\n" :"=r"(rp) );
++      printk("%lx\n",rp);
++
++      return sprintf(buf, "%d\n",prodval);
++}
++extern void tsc2101_print_miscdata(struct device *dev);
++extern struct platform_device tsc2101_device;
++
++static ssize_t test1_store(struct device *dev, const char *buf, size_t count)
++{
++      prodval = simple_strtoul(buf, NULL, 10);
++
++      tsc2101_print_miscdata(&tsc2101_device.dev);
++
++      return count;
++}
++
++static DEVICE_ATTR(test1, 0644, test1_show, test1_store);
++
++static ssize_t test2_show(struct device *dev, char *buf)
++{
++      printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2);
++      printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2);
++      printk(KERN_ERR "SSSR_P2:  %08x\n", SSSR_P2);
++      printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2);
++      printk(KERN_ERR "SSDR_P2:  %08x\n", SSDR_P2);
++      printk(KERN_ERR "SSTO_P2:  %08x\n", SSTO_P2);
++      printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2);
++
++      hx2750_ssp_init2();
++
++      printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2);
++      printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2);
++      printk(KERN_ERR "SSSR_P2:  %08x\n", SSSR_P2);
++      printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2);
++      printk(KERN_ERR "SSDR_P2:  %08x\n", SSDR_P2);
++      printk(KERN_ERR "SSTO_P2:  %08x\n", SSTO_P2);
++      printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2);
++
++      return sprintf(buf, "%d\n",0);
++}
++
++static DEVICE_ATTR(test2, 0444, test2_show, NULL);
++
++extern unsigned int hx2750_egpio_current;
++
++static ssize_t setegpio_show(struct device *dev, char *buf)
++{
++      return sprintf(buf, "%x\n",hx2750_egpio_current);
++}
++
++static ssize_t setegpio_store(struct device *dev, const char *buf, size_t count)
++{
++      unsigned int val = simple_strtoul(buf, NULL, 10);
++
++      hx2750_set_egpio(1 << val);
++
++      return count;
++}
++
++static DEVICE_ATTR(setegpio, 0644, setegpio_show, setegpio_store);
++
++static ssize_t clregpio_show(struct device *dev, char *buf)
++{
++      return sprintf(buf, "%x\n",hx2750_egpio_current);
++}
++
++static ssize_t gpio_show(struct device *dev, char *buf)
++{
++      int i;
++
++      printk(KERN_ERR "GPIO# D S A INTER\n");
++
++      for (i=0;i<119;i++) {
++              printk(KERN_ERR " %3d: ",i);
++              if (GPDR(i) & GPIO_bit(i))
++                      printk("O ");
++              else
++                      printk("I ");
++              printk("%d ",(GPLR(i) & GPIO_bit(i)) != 0);
++              printk("%d ",((GAFR(i) & (0x3 << (((i) & 0xf)*2)))) >> (((i) & 0xf)*2) );
++              if (GEDR(i) & GPIO_bit(i))
++                      printk("ED ");
++              if (GRER(i) & GPIO_bit(i))
++                      printk("RE ");
++              if (GFER(i) & GPIO_bit(i))
++                      printk("FE ");
++
++              printk("\n");
++      }
++      return sprintf(buf, "EGPIO: %x\n",hx2750_egpio_current);
++}
++
++static ssize_t clregpio_store(struct device *dev, const char *buf, size_t count)
++{
++      unsigned int val = simple_strtoul(buf, NULL, 10);
++
++      hx2750_clear_egpio(1 << val);
++
++      return count;
++}
++
++static DEVICE_ATTR(clregpio, 0644, clregpio_show, clregpio_store);
++
++
++static ssize_t gpioclr_store(struct device *dev, const char *buf, size_t count)
++{
++      int prod;
++      prod = simple_strtoul(buf, NULL, 10);
++
++      GPCR(prod) = GPIO_bit(prod);
++
++      return count;
++}
++
++static DEVICE_ATTR(gpioclr, 0644, gpio_show, gpioclr_store);
++
++static ssize_t gpioset_store(struct device *dev, const char *buf, size_t count)
++{
++      int prod;
++      prod = simple_strtoul(buf, NULL, 10);
++
++      GPSR(prod) = GPIO_bit(prod);
++
++      return count;
++}
++
++static DEVICE_ATTR(gpioset, 0644, gpio_show, gpioset_store);
++
++
++static ssize_t ssp2read_store(struct device *dev, const char *buf, size_t count)
++{
++      unsigned int val = simple_strtoul(buf, NULL, 16);
++
++      printk("Read: %08x\n",hx2750_ssp2_read(val));
++
++      return count;
++}
++
++static DEVICE_ATTR(ssp2read, 0200, NULL, ssp2read_store);\r
++\r
++static ssize_t ssp2write_store(struct device *dev, const char *buf, size_t count)
++{
++      unsigned int val = simple_strtoul(buf, NULL, 16);
++
++      printk("Write: %08x\n",hx2750_ssp2_write(val));
++
++      return count;
++}
++
++static DEVICE_ATTR(ssp2write, 0200, NULL, ssp2write_store);
++
++
++static ssize_t sspr_store(struct device *dev, const char *buf, size_t count)
++{
++      unsigned long val,ret;
++      val = simple_strtoul(buf, NULL, 0);
++
++      hx2750_tsc2101_send(1<<15,val,&ret,1);
++
++      printk("Response: %x\n",ret);
++
++      return count;
++}
++
++static DEVICE_ATTR(sspr, 0200, NULL, sspr_store);
++
++static ssize_t sspw_store(struct device *dev, const char *buf, size_t count)
++{
++      int val,ret;
++      sscanf(buf, "%lx %lx", &val, &ret);
++
++      hx2750_tsc2101_send(0,val,&ret,1);
++
++      return count;
++}
++
++static DEVICE_ATTR(sspw, 0200, NULL, sspw_store);
++
++
++extern struct pm_ops pxa_pm_ops;
++extern void pxa_cpu_resume(void);
++extern unsigned long pxa_pm_pspr_value;
++
++static int (*pxa_pm_enter_orig)(suspend_state_t state);
++
++//static struct {
++//    u32 ffier, fflcr, ffmcr, ffspr, ffisr, ffdll, ffdlh;
++//} sys_ctx;
++
++u32 resstruct[20];
++
++static int hx2750_pxa_pm_enter(suspend_state_t state)
++{
++      int i;
++      u32 save[10];
++
++      PWER = 0xC0000003;// | PWER_RTC;
++      PFER = 0x00000003;
++      PRER = 0x00000003;
++
++      PGSR0=0x00000018;
++      PGSR1=0x00000380;
++      PGSR2=0x00800000;
++      PGSR3=0x00500400;
++
++      //PVCR=0x494; or 0x14;
++      //PVCR=0x14;
++      //PCMD0=0x41f;
++      //i=PISR;
++      //PICR=0x00000062;
++
++      //PCFR=0x457;
++      //PCFR=0x70; // Does not resume from sleep
++      PCFR=0x077; // was 0x477
++      PSLR=0xff100004;
++
++      resstruct[0]=0x0000b4e6;
++      resstruct[1]=0x00000001;
++      resstruct[2]=virt_to_phys(pxa_cpu_resume);
++      resstruct[3]=0xffffffff; //value for r0
++
++      resstruct[14]=0x00000078;  //mcr        15, 0, r0, cr1, cr0, {0}
++      resstruct[15]=0x00000000;  //mcr        15, 0, r0, cr1, cr1, {0} 0xffffffff\r
++      resstruct[16]=0xa0000000;  //mcr        15, 0, r0, cr2, cr0, {0} 0xa0748000\r
++      resstruct[17]=0x00000001;  //mcr        15, 0, r0, cr3, cr0, {0} 0x00000015\r
++      resstruct[18]=0x00000000;  //mcr        15, 0, r0, cr13, cr0, {0} 0x00000000\r
++
++      pxa_pm_pspr_value=virt_to_phys(&resstruct[0]);
++
++      hx2750_send_egpio(3);
++
++      pxa_gpio_mode(87 | GPIO_OUT  | GPIO_DFLT_HIGH);
++
++      //sys_ctx.ffier = FFIER;
++      //sys_ctx.fflcr = FFLCR;
++      //sys_ctx.ffmcr = FFMCR;
++      //sys_ctx.ffspr = FFSPR;
++      //sys_ctx.ffisr = FFISR;
++      //FFLCR |= 0x80;
++      //sys_ctx.ffdll = FFDLL;
++      //sys_ctx.ffdlh = FFDLH;
++      //FFLCR &= 0xef;
++
++      pxa_pm_enter_orig(state);
++
++      //FFMCR = sys_ctx.ffmcr;
++      //FFSPR = sys_ctx.ffspr;
++      //FFLCR = sys_ctx.fflcr;
++      //FFLCR |= 0x80;
++      //FFDLH = sys_ctx.ffdlh;
++      //FFDLL = sys_ctx.ffdll;
++      //FFLCR = sys_ctx.fflcr;
++      //FFISR = sys_ctx.ffisr;
++      //FFLCR = 0x07;
++      //FFIER = sys_ctx.ffier;
++
++      return 0;
++}
++
++static irqreturn_t hx2750_charge_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      if ((GPLR(HX2750_GPIO_EXTPWR) & GPIO_bit(HX2750_GPIO_EXTPWR)) == 0) {
++              printk("Charging On\n");
++              GPCR(HX2750_GPIO_CHARGE);
++      } else {
++              printk("Charging Off\n");
++              GPSR(HX2750_GPIO_CHARGE);
++      }
++
++      return IRQ_HANDLED;
++}
++
++
++
++
++static irqreturn_t hx2750_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++    printk("Input %d changed.\n", irq-32);
++
++      return IRQ_HANDLED;
++}
++
++
++static int __init hx2750_test_probe(struct device *dev)
++{
++      pxa_gpio_mode(21 | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(HX2750_GPIO_CHARGE | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(83 | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(HX2750_GPIO_BIOPWR | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(116 | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(118 | GPIO_OUT | GPIO_DFLT_HIGH);
++
++
++      //pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(HX2750_GPIO_BTPWR | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(79 | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(85 | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(HX2750_GPIO_LEDMAIL | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(107 | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(114 | GPIO_OUT | GPIO_DFLT_LOW);
++
++      pxa_gpio_mode(HX2750_GPIO_BATTCOVER1 | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_BATTCOVER2 | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_CF_IRQ | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_USBCONNECT | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_CF_DETECT | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_EXTPWR | GPIO_IN);
++
++      pxa_gpio_mode(HX2750_GPIO_BATLVL | GPIO_IN);
++      //pxa_gpio_mode(HX2750_GPIO_CF_WIFIIRQ | GPIO_IN);
++      pxa_gpio_mode(80 | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_HP_JACK | GPIO_IN);
++      pxa_gpio_mode(115 | GPIO_IN);
++      pxa_gpio_mode(119 | GPIO_IN);
++
++      request_irq(IRQ_GPIO(HX2750_GPIO_BATLVL), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++      //request_irq(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++      request_irq(IRQ_GPIO(80), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++      request_irq(IRQ_GPIO(115), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++      request_irq(IRQ_GPIO(119), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++      request_irq(IRQ_GPIO(HX2750_GPIO_SR_CLK2), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++
++      //request_irq(IRQ_GPIO(10), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL);
++
++      set_irq_type(IRQ_GPIO(HX2750_GPIO_BATLVL),IRQT_BOTHEDGE);
++      //set_irq_type(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ),IRQT_BOTHEDGE);
++      set_irq_type(IRQ_GPIO(80),IRQT_BOTHEDGE);
++      set_irq_type(IRQ_GPIO(115),IRQT_BOTHEDGE);
++      set_irq_type(IRQ_GPIO(119),IRQT_BOTHEDGE);
++      set_irq_type(IRQ_GPIO(HX2750_GPIO_SR_CLK2),IRQT_BOTHEDGE);
++
++      //set_irq_type(IRQ_GPIO(10),IRQT_BOTHEDGE);
++
++      printk("hx2750 Test Code Initialized.\n");
++      device_create_file(dev, &dev_attr_test1);
++      device_create_file(dev, &dev_attr_test2);
++      device_create_file(dev, &dev_attr_setegpio);
++      device_create_file(dev, &dev_attr_clregpio);
++      device_create_file(dev, &dev_attr_gpioset);
++      device_create_file(dev, &dev_attr_gpioclr);
++      device_create_file(dev, &dev_attr_sspr);
++      device_create_file(dev, &dev_attr_sspw);
++      device_create_file(dev, &dev_attr_ssp2read);
++      device_create_file(dev, &dev_attr_ssp2write);
++
++      request_irq(HX2750_IRQ_GPIO_EXTPWR, hx2750_charge_int, SA_INTERRUPT, "hx2750_extpwr", NULL);
++      set_irq_type(HX2750_IRQ_GPIO_EXTPWR, IRQT_BOTHEDGE);
++
++      pxa_pm_enter_orig=pxa_pm_ops.enter;
++      pxa_pm_ops.enter=hx2750_pxa_pm_enter;
++
++      return 0;
++}
++
++static struct device_driver hx2750_test_driver = {
++      .name           = "hx2750-test",
++      .bus            = &platform_bus_type,
++      .probe          = hx2750_test_probe,
++//    .remove         = hx2750_bl_remove,
++//    .suspend        = hx2750_bl_suspend,
++//    .resume         = hx2750_bl_resume,
++};
++
++
++static int __init hx2750_test_init(void)
++{
++      return driver_register(&hx2750_test_driver);
++}
++
++
++static void __exit hx2750_test_exit(void)
++{
++      driver_unregister(&hx2750_test_driver);
++}
++
++module_init(hx2750_test_init);
++module_exit(hx2750_test_exit);
++
++MODULE_AUTHOR("Richard Purdie <richard@o-hand.com>");
++MODULE_DESCRIPTION("iPAQ hx2750 Backlight Driver");
++MODULE_LICENSE("GPLv2");
+--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Kconfig
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/Kconfig
+@@ -83,6 +83,15 @@
+       bool "Sharp PXA270 models (SL-Cxx00)"
+       select PXA27x
++config MACH_HX2750
++      bool "HP iPAQ hx2750"
++      select PXA27x
++      select PXA_KEYS
++      select MFD_TSC2101
++      select PXA_SSP
++      help
++        This enables support for the HP iPAQ HX2750 handheld.
++
+ endchoice
+ endif
+@@ -181,3 +190,4 @@
+       help
+         Enable support for PXA2xx SSP ports
+ endif
++
+--- /dev/null
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750.c
+@@ -0,0 +1,450 @@
++/*
++ * Machine definitions for HP iPAQ hx2750
++ *
++ * Copyright 2005 Openedhand Ltd.
++ *
++ * Author: Richard Purdie <richard@o-hand.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/input.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/mfd/tsc2101.h>
++
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/mach/arch.h>
++
++#include <asm/arch/hx2750.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa_keys.h>
++#include <asm/mach/map.h>
++#include <asm/arch/udc.h>
++#include <asm/arch/mmc.h>
++#include <asm/arch/audio.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/ssp.h>
++
++#include "generic.h"
++
++
++/*
++ * Keys Support
++ */
++static struct pxa_keys_button hx2750_button_table[] = {
++      { KEY_POWER, HX2750_GPIO_KEYPWR, PXAKEY_PWR_KEY },
++      { KEY_LEFT, HX2750_GPIO_KEYLEFT, 0 },
++      { KEY_RIGHT, HX2750_GPIO_KEYRIGHT, 0 },
++      { KEY_KP0, HX2750_GPIO_KEYCAL, 0 },
++      { KEY_KP1, HX2750_GPIO_KEYTASK, 0 },
++      { KEY_KP2, HX2750_GPIO_KEYSIDE, 0 },
++      { KEY_ENTER, HX2750_GPIO_KEYENTER, 0 },
++      { KEY_KP3, HX2750_GPIO_KEYCON, 0 }, //KEY_CONTACTS
++      { KEY_MAIL, HX2750_GPIO_KEYMAIL, 0 },
++      { KEY_UP, HX2750_GPIO_KEYUP, 0 },
++      { KEY_DOWN, HX2750_GPIO_KEYDOWN, 0 },
++};
++
++static struct pxa_keys_platform_data hx2750_pxa_keys_data = {
++      .buttons = hx2750_button_table,
++      .nbuttons = ARRAY_SIZE(hx2750_button_table),
++};
++
++static struct platform_device hx2750_pxa_keys = {
++      .name = "pxa2xx-keys",
++      .dev = {
++              .platform_data = &hx2750_pxa_keys_data,
++      },
++};
++
++
++/*
++ * Backlight Device
++ */
++extern struct platform_device pxafb_device;
++
++static struct platform_device hx2750_bl_device = {
++      .name           = "hx2750-bl",
++      .id             = -1,
++//    .dev    = {
++//            .parent = &pxafb_device.dev,
++//    }
++};
++
++
++/*
++ * UDC/USB
++ */
++static int hx2750_udc_is_connected (void)
++{
++      return GPLR0 & GPIO_bit(HX2750_GPIO_USBCONNECT);
++}
++
++//static void hx2750_udc_command (int cmd)
++//{
++//}
++
++static struct pxa2xx_udc_mach_info hx2750_udc_mach_info = {
++      .udc_is_connected = hx2750_udc_is_connected,
++//    .udc_command      = hx2750_udc_command,
++};
++
++
++/*
++ * SSP Devices Setup
++ */
++static struct ssp_dev hx2750_ssp_dev1;
++static struct ssp_dev hx2750_ssp_dev2;
++static struct ssp_dev hx2750_ssp_dev3;
++
++void hx2750_ssp_init(void)
++{
++      pxa_gpio_mode(HX2750_GPIO_TSC2101_SS | GPIO_OUT | GPIO_DFLT_HIGH);
++
++      if (ssp_init(&hx2750_ssp_dev1, 1, 0))
++              printk(KERN_ERR "Unable to register SSP1 handler!\n");
++      else {
++              ssp_disable(&hx2750_ssp_dev1);
++              ssp_config(&hx2750_ssp_dev1, (SSCR0_Motorola | (SSCR0_DSS & 0x0f )), SSCR1_SPH, 0, SSCR0_SerClkDiv(6));
++              ssp_enable(&hx2750_ssp_dev1);
++              hx2750_set_egpio(HX2750_EGPIO_TSC_PWR);
++      }
++
++//    if (ssp_init(&hx2750_ssp_dev2, 2, 0))
++//            printk(KERN_ERR "Unable to register SSP2 handler!\n");
++//    else {
++//            ssp_disable(&hx2750_ssp_dev2);
++//            ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )), 0, 0, SSCR0_SerClkDiv(140));
++//            ssp_enable(&hx2750_ssp_dev2);
++//    }
++//
++      if (ssp_init(&hx2750_ssp_dev3, 3, 0))
++              printk(KERN_ERR "Unable to register SSP3 handler!\n");
++      else {
++              ssp_disable(&hx2750_ssp_dev3);
++              ssp_config(&hx2750_ssp_dev3, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPO | SSCR1_SPH, 0, SSCR0_SerClkDiv(166));
++              ssp_enable(&hx2750_ssp_dev3);
++      }
++
++      printk("SSP Devices Initialised\n");
++
++      return;
++}
++
++struct ssp_state ssp1;
++
++void hx2750_ssp_suspend(void)
++{
++      ssp_disable(&hx2750_ssp_dev1);
++      ssp_save_state(&hx2750_ssp_dev1,&ssp1);
++      hx2750_clear_egpio(HX2750_EGPIO_TSC_PWR);
++}
++
++void hx2750_ssp_resume(void)
++{
++      hx2750_set_egpio(HX2750_EGPIO_TSC_PWR);
++      ssp_restore_state(&hx2750_ssp_dev1,&ssp1);
++      ssp_enable(&hx2750_ssp_dev1);
++}
++
++void hx2750_ssp_init2(void)
++{
++      printk("Stage 1: %x\n",CKEN);
++      if (ssp_init(&hx2750_ssp_dev2, 2, 0))
++              printk(KERN_ERR "Unable to register SSP2 handler!\n");
++      else {
++              printk("Stage 2: %x\n",CKEN);
++              ssp_disable(&hx2750_ssp_dev2);
++              printk("Stage 3: %x\n",CKEN);
++              ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )) | SSCR0_SSE, 0, 0, SSCR0_SerClkDiv(212));
++              printk("Stage 4: %x\n",CKEN);
++              ssp_enable(&hx2750_ssp_dev2);
++              printk("Stage 5: %x\n",CKEN);
++      }
++      printk("SSP Device2 Initialised\n");
++
++      printk("Sent: 0x3ff\n");
++      ssp_write_word(&hx2750_ssp_dev2,0x3ff);
++
++      return;
++}
++
++void hx2750_ssp2_reset(void)
++{
++      ssp_write_word(&hx2750_ssp_dev2,0x000);
++      ssp_write_word(&hx2750_ssp_dev2,0x000);
++
++}
++
++unsigned long hx2750_ssp2_read(void)
++{
++      u32 ret = 0;
++      ssp_read_word(&hx2750_ssp_dev2, &ret);
++      return ret;
++}
++
++void hx2750_ssp2_write(unsigned long data)
++{
++      ssp_write_word(&hx2750_ssp_dev2, data);
++}
++
++
++/*
++ * Extra hx2750 Specific GPIOs
++ */
++void hx2750_send_egpio(unsigned int val)
++{
++      int i;
++
++      GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
++      GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
++
++      for (i=0;i<12;i++) {
++              if (val & 0x01)
++                      GPSR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN);
++              else
++                      GPCR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN);
++              val >>= 1;
++              GPSR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
++              GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1);
++      }
++
++      GPSR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
++      GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE);
++}
++
++EXPORT_SYMBOL(hx2750_send_egpio);
++
++unsigned int hx2750_egpio_current;
++
++void hx2750_set_egpio(unsigned int gpio)
++{
++      hx2750_egpio_current|=gpio;
++
++      hx2750_send_egpio(hx2750_egpio_current);
++}
++EXPORT_SYMBOL(hx2750_set_egpio);
++
++void hx2750_clear_egpio(unsigned int gpio)
++{
++      hx2750_egpio_current&=~gpio;
++
++      hx2750_send_egpio(hx2750_egpio_current);
++}
++EXPORT_SYMBOL(hx2750_clear_egpio);
++
++
++/*
++ * Touchscreen/Sound/Battery Status
++ */
++void hx2750_tsc2101_send(int read, int command, int *values, int numval)
++{
++      u32 ret = 0;
++      int i;
++
++      GPCR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS);
++
++      ssp_write_word(&hx2750_ssp_dev1, command | read);
++      /* dummy read */
++      ssp_read_word(&hx2750_ssp_dev1, &ret);
++
++      for (i=0; i < numval; i++) {
++              if (read) {
++                      ssp_write_word(&hx2750_ssp_dev1, 0);
++                      ssp_read_word(&hx2750_ssp_dev1, &values[i]);
++              } else {
++                      ssp_write_word(&hx2750_ssp_dev1, values[i]);
++                      ssp_read_word(&hx2750_ssp_dev1, &ret);
++              }
++      }
++
++      GPSR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS);
++}
++
++static int hx2750_tsc2101_pendown(void)
++{
++      if ((GPLR(HX2750_GPIO_PENDOWN) & GPIO_bit(HX2750_GPIO_PENDOWN)) == 0)
++              return 1;
++      return 0;
++}
++
++static struct tsc2101_platform_info hx2750_tsc2101_info = {
++      .send     = hx2750_tsc2101_send,
++      .suspend  = hx2750_ssp_suspend,
++      .resume   = hx2750_ssp_resume,
++      .irq      = HX2750_IRQ_GPIO_PENDOWN,
++      .pendown  = hx2750_tsc2101_pendown,
++};
++
++struct platform_device tsc2101_device = {
++      .name           = "tsc2101",
++      .dev            = {
++              .platform_data  = &hx2750_tsc2101_info,
++              //.parent = &corgissp_device.dev,
++      },
++      .id             = -1,
++};
++
++
++/*
++ * MMC/SD Device
++ *
++ * The card detect interrupt isn't debounced so we delay it by 250ms
++ * to give the card a chance to fully insert/eject.
++ */
++static struct pxamci_platform_data hx2750_mci_platform_data;
++
++static int hx2750_mci_init(struct device *dev, irq_handler_t hx2750_detect_int, void *data)
++{
++      int err;
++
++      /*
++       * setup GPIO for PXA27x MMC controller
++       */
++      pxa_gpio_mode(GPIO32_MMCCLK_MD);
++      pxa_gpio_mode(GPIO112_MMCCMD_MD);
++      pxa_gpio_mode(GPIO92_MMCDAT0_MD);
++      pxa_gpio_mode(GPIO109_MMCDAT1_MD);
++      pxa_gpio_mode(GPIO110_MMCDAT2_MD);
++      pxa_gpio_mode(GPIO111_MMCDAT3_MD);
++      pxa_gpio_mode(HX2750_GPIO_SD_DETECT | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_SD_READONLY | GPIO_IN);
++
++      hx2750_mci_platform_data.detect_delay = msecs_to_jiffies(250);
++
++      err = request_irq(HX2750_IRQ_GPIO_SD_DETECT, hx2750_detect_int,
++                      IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                      "MMC card detect", data);
++      if (err) {
++              printk(KERN_ERR "hx2750_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++static void hx2750_mci_setpower(struct device *dev, unsigned int vdd)
++{
++      struct pxamci_platform_data* p_d = dev->platform_data;
++
++      if (( 1 << vdd) & p_d->ocr_mask)
++              hx2750_set_egpio(HX2750_EGPIO_SD_PWR);
++      else
++              hx2750_clear_egpio(HX2750_EGPIO_SD_PWR);
++}
++
++static void hx2750_mci_exit(struct device *dev, void *data)
++{
++      free_irq(HX2750_IRQ_GPIO_SD_DETECT, data);
++}
++
++static struct pxamci_platform_data hx2750_mci_platform_data = {
++      .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
++      .init           = hx2750_mci_init,
++      .setpower       = hx2750_mci_setpower,
++      .exit           = hx2750_mci_exit,
++};
++
++
++/*
++ * FrameBuffer
++ */
++static struct pxafb_mode_info hx2750_pxafb_modes = {
++      .pixclock       = 288462,
++      .xres           = 240,
++      .yres           = 320,
++      .bpp            = 16,
++      .hsync_len      = 20,
++      .left_margin    = 42,
++      .right_margin   = 18,
++      .vsync_len      = 4,
++      .upper_margin   = 3,
++      .lower_margin   = 4,
++      .sync           = 0,
++};
++
++static struct pxafb_mach_info hx2750_pxafb_info = {
++      .modes          = &hx2750_pxafb_modes,
++      .num_modes      = 1,
++      .fixed_modes    = 1,
++      .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++      .lccr3          = LCCR3_PixFlEdg | LCCR3_OutEnH,
++      .pxafb_backlight_power  = NULL,
++};
++
++
++/*
++ * Test Device
++ */
++static struct platform_device hx2750_test_device = {
++      .name           = "hx2750-test",
++      .id             = -1,
++};
++
++
++/* Initialization code */
++static struct platform_device *devices[] __initdata = {
++      &hx2750_bl_device,
++      &hx2750_test_device,
++      &hx2750_pxa_keys,
++      &tsc2101_device,
++};
++
++static void __init hx2750_init( void )
++{
++      PWER = 0xC0000003;// | PWER_RTC;
++      PFER = 0x00000003;
++      PRER = 0x00000003;
++
++      PGSR0=0x00000018;
++      PGSR1=0x00000380;
++      PGSR2=0x00800000;
++      PGSR3=0x00500400;
++
++      //PCFR |= PCFR_OPDE;
++      PCFR=0x77;
++      PSLR=0xff100000;
++      //PCFR=0x10; - does not return from suspend
++
++      //PCFR=  0x00004040;
++      //PSLR=  0xff400f04;
++
++      /* Setup Extra GPIO Bank access */
++      pxa_gpio_mode(HX2750_GPIO_GPIO_DIN | GPIO_OUT | GPIO_DFLT_HIGH);
++      pxa_gpio_mode(HX2750_GPIO_SR_CLK1 | GPIO_OUT | GPIO_DFLT_LOW);
++      pxa_gpio_mode(HX2750_GPIO_SR_CLK2 | GPIO_IN);
++      pxa_gpio_mode(HX2750_GPIO_SR_STROBE | GPIO_OUT | GPIO_DFLT_LOW);
++
++      /* Init Extra GPIOs - Bootloader reset default is 0x484 */
++      /* This is 0xe84 */
++      hx2750_set_egpio(HX2750_EGPIO_2 | HX2750_EGPIO_7 | HX2750_EGPIO_LCD_PWR | HX2750_EGPIO_BL_PWR | HX2750_EGPIO_WIFI_PWR);
++
++      pxa_set_udc_info(&hx2750_udc_mach_info);
++      pxa_set_mci_info(&hx2750_mci_platform_data);
++      set_pxa_fb_info(&hx2750_pxafb_info);
++      hx2750_ssp_init();
++      platform_add_devices (devices, ARRAY_SIZE (devices));
++}
++
++
++MACHINE_START(HX2750, "HP iPAQ HX2750")
++      .phys_io        = 0x40000000,
++      .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
++      .boot_params    = 0xa0000100,
++      .map_io         = pxa_map_io,
++        .init_irq     = pxa_init_irq,
++        .timer                = &pxa_timer,
++      .init_machine   = hx2750_init,
++MACHINE_END
++
+--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pm.c
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/pm.c
+@@ -17,6 +17,7 @@
+ #include <linux/time.h>
+ #include <asm/hardware.h>
++#include <asm/mach-types.h>
+ #include <asm/memory.h>
+ #include <asm/system.h>
+ #include <asm/arch/pm.h>
+@@ -91,6 +92,9 @@
+       .enter          = pxa_pm_enter,
+ };
++unsigned long pxa_pm_pspr_value;
++extern void pxa_cpu_resume(void);
++
+ static int __init pxa_pm_init(void)
+ {
+       if (!pxa_cpu_pm_fns) {
+@@ -104,6 +108,7 @@
+               return -ENOMEM;
+       }
++      pxa_pm_pspr_value=virt_to_phys(pxa_cpu_resume);
+       suspend_set_ops(&pxa_pm_ops);
+       return 0;
+ }
+--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa27x.c
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa27x.c
+@@ -259,6 +259,8 @@
+       RESTORE(PSTR);
+ }
++extern unsigned long pxa_pm_pspr_value;
++
+ void pxa27x_cpu_pm_enter(suspend_state_t state)
+ {
+       extern void pxa_cpu_standby(void);
+@@ -281,7 +283,7 @@
+               break;
+       case PM_SUSPEND_MEM:
+               /* set resume return address */
+-              PSPR = virt_to_phys(pxa_cpu_resume);
++              PSPR = pxa_pm_pspr_value;
+               pxa27x_cpu_suspend(PWRMODE_SLEEP);
+               break;
+       }
+--- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa25x.c
++++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa25x.c
+@@ -200,6 +200,8 @@
+       RESTORE(PSTR);
+ }
++extern unsigned long pxa_pm_pspr_value;
++
+ static void pxa25x_cpu_pm_enter(suspend_state_t state)
+ {
+       CKEN = 0;
+@@ -207,7 +209,7 @@
+       switch (state) {
+       case PM_SUSPEND_MEM:
+               /* set resume return address */
+-              PSPR = virt_to_phys(pxa_cpu_resume);
++              PSPR = pxa_pm_pspr_value;
+               pxa25x_cpu_suspend(PWRMODE_SLEEP);
+               break;
+       }
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pxa27x_overlay-r8.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/pxa27x_overlay-r8.patch
new file mode 100644 (file)
index 0000000..693ad20
--- /dev/null
@@ -0,0 +1,2427 @@
+ drivers/video/Kconfig               |   18 
+ drivers/video/Makefile              |    1 
+ drivers/video/pxafb.c               |  305 +++++--
+ drivers/video/pxafb.h               |   65 +
+ drivers/video/pxafb_overlay.c       | 1525 ++++++++++++++++++++++++++++++++++++
+ include/asm-arm/arch-pxa/pxa-regs.h |  111 ++
+ 6 files changed, 1969 insertions(+), 56 deletions(-)
+
+--- linux-2.6.24-rc1.orig/drivers/video/Kconfig
++++ linux-2.6.24-rc1/drivers/video/Kconfig
+@@ -1718,6 +1718,24 @@
+         If unsure, say N.
++choice
++      prompt "PXA LCD type"
++      depends on FB_PXA
++
++config FB_PXA_LCD_QVGA
++        bool "QVGA(320x240)"
++
++config FB_PXA_LCD_VGA
++        bool "VGA (640x480)"
++
++endchoice
++
++config FB_PXA_OVERLAY
++    tristate "PXA LCD overlay support"
++    depends on FB_PXA
++    ---help---
++        Frame buffer overlay driver for PXA27x
++
+ config FB_PXA_PARAMETERS
+       bool "PXA LCD command line parameters"
+       default n
+--- linux-2.6.24-rc1.orig/drivers/video/Makefile
++++ linux-2.6.24-rc1/drivers/video/Makefile
+@@ -96,6 +96,7 @@
+ obj-$(CONFIG_FB_CIRRUS)                 += cirrusfb.o
+ obj-$(CONFIG_FB_ASILIANT)       += asiliantfb.o
+ obj-$(CONFIG_FB_PXA)            += pxafb.o
++obj-$(CONFIG_FB_PXA_OVERLAY)    += pxafb_overlay.o
+ obj-$(CONFIG_FB_W100)           += w100fb.o
+ obj-$(CONFIG_FB_AU1100)                 += au1100fb.o
+ obj-$(CONFIG_FB_AU1200)                 += au1200fb.o
+--- linux-2.6.24-rc1.orig/drivers/video/pxafb.c
++++ linux-2.6.24-rc1/drivers/video/pxafb.c
+@@ -59,17 +59,49 @@
+ #define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
+ #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
++wait_queue_head_t fcs_wait_eof;
++int fcs_in_eof;
++static DECLARE_MUTEX(fcs_lcd_sem);
++
+ static void (*pxafb_backlight_power)(int);
+ static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
+ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
++void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+ #ifdef CONFIG_FB_PXA_PARAMETERS
+ #define PXAFB_OPTIONS_SIZE 256
+ static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
+ #endif
++static struct pxafb_rgb def_rgb_8 = {
++      red:    { offset: 0,  length: 8, },
++      green:  { offset: 0,  length: 8, },
++      blue:   { offset: 0,  length: 8, },
++      transp: { offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgb_16 = {
++      red:    { offset: 11, length: 5, },
++      green:  { offset: 5,  length: 6, },
++      blue:   { offset: 0,  length: 5, },
++      transp: { offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgb_18 = {
++      red:    { offset: 12, length: 6, },
++      green:  { offset: 6,  length: 6, },
++      blue:   { offset: 0,  length: 6, },
++      transp: { offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgb_24 = {
++      red:    { offset: 16, length: 8, },
++      green:  { offset: 8,  length: 8, },
++      blue:   { offset: 0,  length: 8, },
++      transp: { offset: 0,  length: 0, },
++};
++
+ static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
+ {
+       unsigned long flags;
+@@ -209,6 +241,10 @@
+         case 4:  ret = LCCR3_4BPP; break;
+         case 8:  ret = LCCR3_8BPP; break;
+         case 16: ret = LCCR3_16BPP; break;
++        case 18: ret = LCCR3_18BPP; break;
++        case 19: ret = LCCR3_19BPP; break;
++        case 24: ret = LCCR3_24BPP; break;
++        case 25: ret = LCCR3_25BPP; break;
+         }
+         return ret;
+ }
+@@ -320,18 +356,34 @@
+        * The pixel packing format is described on page 7-11 of the
+        * PXA2XX Developer's Manual.
+          */
+-      if (var->bits_per_pixel == 16) {
+-              var->red.offset   = 11; var->red.length   = 5;
+-              var->green.offset = 5;  var->green.length = 6;
+-              var->blue.offset  = 0;  var->blue.length  = 5;
+-              var->transp.offset = var->transp.length = 0;
+-      } else {
+-              var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+-              var->red.length   = 8;
+-              var->green.length = 8;
+-              var->blue.length  = 8;
+-              var->transp.length = 0;
+-      }
++      switch (var->bits_per_pixel) {
++      case 16:
++              /* 2 pixels per line */
++              var->red    = def_rgb_16.red;
++              var->green  = def_rgb_16.green;
++              var->blue   = def_rgb_16.blue;
++              var->transp = def_rgb_16.transp;
++              break;
++      case 18:
++      case 19:
++              var->red    = def_rgb_18.red;
++              var->green  = def_rgb_18.green;
++              var->blue   = def_rgb_18.blue;
++              var->transp = def_rgb_18.transp;
++              break;
++      case 24:
++      case 25:
++              var->red    = def_rgb_24.red;
++              var->green  = def_rgb_24.green;
++              var->blue   = def_rgb_24.blue;
++              var->transp = def_rgb_24.transp;
++              break;
++       default:
++              var->red    = def_rgb_8.red;
++              var->green  = def_rgb_8.green;
++              var->blue   = def_rgb_8.blue;
++              var->transp = def_rgb_8.transp;
++    }
+ #ifdef CONFIG_CPU_FREQ
+       pr_debug("pxafb: dma period = %d ps, clock = %d kHz\n",
+@@ -345,7 +397,7 @@
+ static inline void pxafb_set_truecolor(u_int is_true_color)
+ {
+       pr_debug("pxafb: true_color = %d\n", is_true_color);
+-      // do your machine-specific setup if needed
++      /* do your machine-specific setup if needed */
+ }
+ /*
+@@ -360,7 +412,8 @@
+       pr_debug("pxafb: set_par\n");
+-      if (var->bits_per_pixel == 16)
++      if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
++        || var->bits_per_pixel == 24 || var->bits_per_pixel == 25)
+               fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+       else if (!fbi->cmap_static)
+               fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+@@ -373,12 +426,25 @@
+               fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+       }
+-      fbi->fb.fix.line_length = var->xres_virtual *
+-                                var->bits_per_pixel / 8;
+-      if (var->bits_per_pixel == 16)
+-              fbi->palette_size = 0;
+-      else
+-              fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
++      switch (var->bits_per_pixel) {
++      case 16:
++              fbi->fb.fix.line_length = var->xres_virtual * 2;
++              fbi->palette_size = 0;
++              break;
++      case 18:
++      case 19:
++              fbi->fb.fix.line_length = var->xres_virtual * 3;
++              fbi->palette_size = 0;
++              break;
++      case 24:
++      case 25:
++              fbi->fb.fix.line_length = var->xres_virtual * 4;
++              fbi->palette_size = 0;
++              break;
++      default:
++              fbi->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
++              fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
++      }
+       if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+               palette_mem_size = fbi->palette_size * sizeof(u16);
+@@ -395,7 +461,8 @@
+        */
+       pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+-      if (fbi->fb.var.bits_per_pixel == 16)
++      if (fbi->fb.var.bits_per_pixel == 16 || fbi->fb.var.bits_per_pixel == 18 ||fbi->fb.var.bits_per_pixel == 19
++        || fbi->fb.var.bits_per_pixel == 24 || fbi->fb.var.bits_per_pixel == 25)
+               fb_dealloc_cmap(&fbi->fb.cmap);
+       else
+               fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
+@@ -441,7 +508,7 @@
+  *    16 bpp mode does not really use the palette, so this will not
+  *      blank the display in all modes.
+  */
+-static int pxafb_blank(int blank, struct fb_info *info)
++int pxafb_blank(int blank, struct fb_info *info)
+ {
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       int i;
+@@ -458,19 +525,20 @@
+                       for (i = 0; i < fbi->palette_size; i++)
+                               pxafb_setpalettereg(i, 0, 0, 0, 0, info);
+-              pxafb_schedule_work(fbi, C_DISABLE);
+-              //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
++              pxafb_schedule_work(fbi, C_BLANK);
++              /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
+               break;
+       case FB_BLANK_UNBLANK:
+-              //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
++              /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
+               if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+                   fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+                       fb_set_cmap(&fbi->fb.cmap, info);
+-              pxafb_schedule_work(fbi, C_ENABLE);
++              pxafb_schedule_work(fbi, C_UNBLANK);
+       }
+       return 0;
+ }
++EXPORT_SYMBOL(pxafb_blank);
+ static int pxafb_mmap(struct fb_info *info,
+                     struct vm_area_struct *vma)
+@@ -606,6 +674,10 @@
+       case 4:
+       case 8:
+       case 16:
++      case 18:
++      case 19:
++      case 24:
++      case 25:
+               break;
+       default:
+               printk(KERN_ERR "%s: invalid bit depth %d\n",
+@@ -637,7 +709,10 @@
+       new_regs.lccr0 = fbi->lccr0 |
+               (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+-                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
++#ifdef CONFIG_PXA27x  /* Enable overlay for PXA27x */
++               LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM |
++#endif
++                 LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
+       new_regs.lccr1 =
+               LCCR1_DisWdth(var->xres) +
+@@ -696,7 +771,7 @@
+       fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
+       fbi->dmadesc_fbhigh_cpu->fidr = 0;
+-      fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
++      fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL | LDCMD_EOFINT;
+       fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
+       fbi->dmadesc_palette_cpu->fidr  = 0;
+@@ -708,7 +783,8 @@
+                                                       sizeof(u32);
+       fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
+-      if (var->bits_per_pixel == 16) {
++      if (var->bits_per_pixel == 16 || var->bits_per_pixel == 18 ||var->bits_per_pixel == 19
++        || var->bits_per_pixel == 24 || var->bits_per_pixel == 25) {
+               /* palette shouldn't be loaded in true-color mode */
+               fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
+               fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
+@@ -763,8 +839,8 @@
+ }
+ /*
+- * NOTE!  The following functions are purely helpers for set_ctrlr_state.
+- * Do not call them directly; set_ctrlr_state does the correct serialisation
++ * NOTE!  The following functions are purely helpers for pxafb_set_ctrlr_state.
++ * Do not call them directly; pxafb_set_ctrlr_state does the correct serialisation
+  * to ensure that things happen in the right way 100% of time time.
+  *    -- rmk
+  */
+@@ -786,7 +862,8 @@
+ static void pxafb_setup_gpio(struct pxafb_info *fbi)
+ {
+-      int gpio, ldd_bits;
++      int gpio;
++      int ldd_bits = 0;
+         unsigned int lccr0 = fbi->lccr0;
+       /*
+@@ -796,28 +873,56 @@
+       /* 4 bit interface */
+       if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+           (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
+-          (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
++          (lccr0 & LCCR0_DPD) == LCCR0_4PixMono) {
+               ldd_bits = 4;
+-
++      }
+       /* 8 bit interface */
+         else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+                 ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+                  ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+-                (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
++                (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) {
+               ldd_bits = 8;
+-
++      }
+       /* 16 bit interface */
+-      else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+-               ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+-              ldd_bits = 16;
++      else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
++              ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act)) {
++              switch (fbi->fb.var.bits_per_pixel) {
++              case 16:
++#ifdef CONFIG_PXA27x
++                      /* bits 58-77 */
++                      GPDR1 |= (0x3f << 26);
++                      GPDR2 |= 0x00003fff;
++                      GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++                      GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
++#endif
++                      ldd_bits = 16;
++                      break;
++              case 18:
++              case 19:
++              case 24:
++              case 25:
++#ifdef CONFIG_PXA27x
++                      /* bits 58-77 and 86, 87 */
++                      GPDR1 |= (0x3f << 26);
++                      GPDR2 |= 0x00c03fff;
++
++                      GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++                      GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
++                      GAFR2_U = (GAFR2_U & 0xffff0fff) | 0xa000;
++#endif
++                      ldd_bits = 25;
++                      break;
++              }
++      }
+       else {
+               printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+               return;
+         }
+-      for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
++      for (gpio = 58; ldd_bits > 0; gpio++, ldd_bits--) {
+               pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
++      }
+       pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
+       pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
+       pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
+@@ -837,6 +942,7 @@
+       /* enable LCD controller clock */
+       clk_enable(fbi->clk);
++      down(&fcs_lcd_sem);
+       /* Sequence from 11.7.10 */
+       LCCR3 = fbi->reg_lccr3;
+       LCCR2 = fbi->reg_lccr2;
+@@ -847,6 +953,8 @@
+       FDADR1 = fbi->fdadr1;
+       LCCR0 |= LCCR0_ENB;
++      up(&fcs_lcd_sem);
++
+       pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
+       pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
+       pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
+@@ -862,6 +970,7 @@
+       pr_debug("pxafb: disabling LCD controller\n");
++      down(&fcs_lcd_sem);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(&fbi->ctrlr_wait, &wait);
+@@ -871,6 +980,7 @@
+       schedule_timeout(200 * HZ / 1000);
+       remove_wait_queue(&fbi->ctrlr_wait, &wait);
++      up(&fcs_lcd_sem);
+       /* disable LCD controller clock */
+       clk_disable(fbi->clk);
+@@ -888,6 +998,11 @@
+               LCCR0 |= LCCR0_LDM;
+               wake_up(&fbi->ctrlr_wait);
+       }
++      if (lcsr & LCSR_EOF && fcs_in_eof) {
++              LCCR0 |= LCCR0_EFM;
++              fcs_in_eof = 0;
++              wake_up(&fcs_wait_eof);
++      }
+       LCSR = lcsr;
+       return IRQ_HANDLED;
+@@ -898,7 +1013,7 @@
+  * sleep when disabling the LCD controller, or if we get two contending
+  * processes trying to alter state.
+  */
+-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
++void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state)
+ {
+       u_int old_state;
+@@ -920,7 +1035,9 @@
+                */
+               if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
+                       fbi->state = state;
+-                      //TODO __pxafb_lcd_power(fbi, 0);
++                      /* TODO __pxafb_lcd_power(fbi, 0); */
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
+                       pxafb_disable_controller(fbi);
+               }
+               break;
+@@ -934,6 +1051,8 @@
+                       fbi->state = state;
+                       __pxafb_backlight_power(fbi, 0);
+                       __pxafb_lcd_power(fbi, 0);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
+                       if (old_state != C_DISABLE_CLKCHANGE)
+                               pxafb_disable_controller(fbi);
+               }
+@@ -947,7 +1066,9 @@
+               if (old_state == C_DISABLE_CLKCHANGE) {
+                       fbi->state = C_ENABLE;
+                       pxafb_enable_controller(fbi);
+-                      //TODO __pxafb_lcd_power(fbi, 1);
++                      /* TODO __pxafb_lcd_power(fbi, 1); */
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
+               }
+               break;
+@@ -959,9 +1080,13 @@
+                */
+               if (old_state == C_ENABLE) {
+                       __pxafb_lcd_power(fbi, 0);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
+                       pxafb_disable_controller(fbi);
+                       pxafb_setup_gpio(fbi);
+                       pxafb_enable_controller(fbi);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
+                       __pxafb_lcd_power(fbi, 1);
+               }
+               break;
+@@ -987,11 +1112,46 @@
+                       pxafb_enable_controller(fbi);
+                       __pxafb_lcd_power(fbi, 1);
+                       __pxafb_backlight_power(fbi, 1);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
+               }
+               break;
++
++      case C_BLANK:
++              /*
++               * Disable controller, blank overlays if exist.
++               */
++              if ((old_state != C_DISABLE) && (old_state != C_BLANK)) {
++                      fbi->state = state;
++                      __pxafb_backlight_power(fbi, 0);
++                      __pxafb_lcd_power(fbi, 0);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_BLANK);
++                      if (old_state != C_DISABLE_CLKCHANGE)
++                              pxafb_disable_controller(fbi);
++              }
++              break;
++
++      case C_UNBLANK:
++              /*
++               * Power up the LCD screen, enable controller, and
++               * turn on the backlight, unblank overlays if exist.
++               */
++              if ((old_state != C_ENABLE) && (old_state != C_UNBLANK)) {
++                      fbi->state = C_UNBLANK;
++                      pxafb_setup_gpio(fbi);
++                      pxafb_enable_controller(fbi);
++                      __pxafb_lcd_power(fbi, 1);
++                      __pxafb_backlight_power(fbi, 1);
++                      if(fbi->set_overlay_ctrlr_state)
++                              fbi->set_overlay_ctrlr_state(fbi, C_UNBLANK);
++              }
++              break;
++
+       }
+       up(&fbi->ctrlr_sem);
+ }
++EXPORT_SYMBOL(pxafb_set_ctrlr_state);
+ /*
+  * Our LCD controller task (which is called when we blank or unblank)
+@@ -1003,7 +1163,7 @@
+               container_of(work, struct pxafb_info, task);
+       u_int state = xchg(&fbi->task_state, -1);
+-      set_ctrlr_state(fbi, state);
++      pxafb_set_ctrlr_state(fbi, state);
+ }
+ #ifdef CONFIG_CPU_FREQ
+@@ -1018,19 +1178,29 @@
+ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
+ {
+       struct pxafb_info *fbi = TO_INF(nb, freq_transition);
+-      //TODO struct cpufreq_freqs *f = data;
++      /* TODO struct cpufreq_freqs *f = data; */
++      struct cpufreq_freqs *clkinfo;
+       u_int pcd;
++      u_int lccr3;
+       switch (val) {
+       case CPUFREQ_PRECHANGE:
+-              set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
++              pxafb_set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+               break;
+       case CPUFREQ_POSTCHANGE:
+-              pcd = get_pcd(fbi, fbi->fb.var.pixclock);
++              clkinfo = (struct cpufreq_freqs *)data;
++              /* If leaving a 13kHz state with the LCD sustained */
++              if ((clkinfo->old == 13000))
++                      break;
++
++              pcd = get_pcd(fbi->fb.var.pixclock);
++              lccr3 = fbi->reg_lccr3;
+               set_hsync_time(fbi, pcd);
+               fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+-              set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
++              pxafb_set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
++              if (lccr3 != fbi->reg_lccr3 && !((LCCR0 & LCCR0_DIS) || !(LCCR0 & LCCR0_ENB)))
++                      LCCR3 = fbi->reg_lccr3;
+               break;
+       }
+       return 0;
+@@ -1049,7 +1219,7 @@
+               printk(KERN_DEBUG "min dma period: %d ps, "
+                       "new clock %d kHz\n", pxafb_display_dma_period(var),
+                       policy->max);
+-              // TODO: fill in min/max values
++              /* TODO: fill in min/max values */
+               break;
+ #if 0
+       case CPUFREQ_NOTIFY:
+@@ -1075,7 +1245,7 @@
+ {
+       struct pxafb_info *fbi = platform_get_drvdata(dev);
+-      set_ctrlr_state(fbi, C_DISABLE_PM);
++      pxafb_set_ctrlr_state(fbi, C_DISABLE_PM);
+       return 0;
+ }
+@@ -1083,7 +1253,11 @@
+ {
+       struct pxafb_info *fbi = platform_get_drvdata(dev);
+-      set_ctrlr_state(fbi, C_ENABLE_PM);
++      pxafb_set_ctrlr_state(fbi, C_ENABLE_PM);
++//RP#ifdef CONFIG_PXA27x
++//RP  LCCR4 |= (1 << 31); /* Disable the PCD Divisor, PCDDIV */
++//RP  LCCR4 |= (5 << 17); /* Undocumented feature */
++//RP#endif
+       return 0;
+ }
+ #else
+@@ -1197,11 +1371,21 @@
+       fbi->task_state                 = (u_char)-1;
+       for (i = 0; i < inf->num_modes; i++) {
+-              smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
++              if (mode[i].bpp <= 16) {       /* 8, 16 bpp */
++                      smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
++              } else if ( mode[i].bpp > 19 ) { /* 24, 25 bpp */
++                      smemlen = mode[i].xres * mode[i].yres * 4;
++              } else {                          /* 18, 19 bpp */
++                      /* packed format */
++                      smemlen = mode[i].xres * mode[i].yres * 3;
++              }
++
+               if (smemlen > fbi->fb.fix.smem_len)
+                       fbi->fb.fix.smem_len = smemlen;
+       }
++      fbi->set_overlay_ctrlr_state    = NULL;
++
+       init_waitqueue_head(&fbi->ctrlr_wait);
+       INIT_WORK(&fbi->task, pxafb_task);
+       init_MUTEX(&fbi->ctrlr_sem);
+@@ -1268,6 +1452,10 @@
+                               case 4:
+                               case 8:
+                               case 16:
++                              case 18:
++                              case 19:
++                              case 24:
++                              case 25:
+                                       inf->modes[0].bpp = bpp;
+                                       dev_info(dev, "overriding bit depth: %d\n", bpp);
+                                       break;
+@@ -1416,7 +1604,7 @@
+       fbi = pxafb_init_fbinfo(&dev->dev);
+       if (!fbi) {
+               dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
+-              ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
++              ret = -ENOMEM; /* only reason for pxafb_init_fbinfo to fail is kmalloc */
+               goto failed;
+       }
+@@ -1451,7 +1639,7 @@
+       }
+ #ifdef CONFIG_PM
+-      // TODO
++      /* TODO */
+ #endif
+ #ifdef CONFIG_CPU_FREQ
+@@ -1464,7 +1652,12 @@
+       /*
+        * Ok, now enable the LCD controller
+        */
+-      set_ctrlr_state(fbi, C_ENABLE);
++      pxafb_set_ctrlr_state(fbi, C_ENABLE);
++//#ifdef CONFIG_PXA27x
++//    LCCR4 |= (1 << 31); /* Disabel the PCD Divisor, PCDDIV */
++//    LCCR4 |= (5 << 17); /* Undocumented feature */
++//#endif
++      init_waitqueue_head(&fcs_wait_eof);
+       return 0;
+--- linux-2.6.24-rc1.orig/drivers/video/pxafb.h
++++ linux-2.6.24-rc1/drivers/video/pxafb.h
+@@ -29,6 +29,60 @@
+       unsigned int lccr3;
+ };
++struct pxafb_rgb {
++      struct fb_bitfield      red;
++      struct fb_bitfield      green;
++      struct fb_bitfield      blue;
++      struct fb_bitfield      transp;
++};
++
++#ifdef CONFIG_PXA27x
++/* PXA Overlay Framebuffer Support */
++struct overlayfb_info
++{
++      struct fb_info  fb;
++
++      struct fb_var_screeninfo old_var;
++
++      struct semaphore mutex;
++      unsigned long    refcount;
++
++      struct pxafb_info *basefb;
++
++      unsigned long   map_cpu;
++      unsigned long   screen_cpu;
++      unsigned long   palette_cpu;
++      unsigned long   map_size;
++      unsigned long   palette_size;
++
++      dma_addr_t      screen_dma;
++      dma_addr_t      map_dma;
++      dma_addr_t      palette_dma;
++
++      volatile u_char state;
++
++      /* overlay specific info */
++      unsigned long   xpos;           /* screen position (x, y)*/
++      unsigned long   ypos;
++      unsigned long   format;
++
++      /* additional */
++      union {
++              struct pxafb_dma_descriptor *dma0;
++              struct pxafb_dma_descriptor *dma1;
++              struct {
++                      struct pxafb_dma_descriptor *dma2;
++                      struct pxafb_dma_descriptor *dma3;
++                      struct pxafb_dma_descriptor *dma4;
++              };
++              struct {
++                      struct pxafb_dma_descriptor *dma5_pal;
++                      struct pxafb_dma_descriptor *dma5_frame;
++              };
++      };
++};
++#endif
++
+ /* PXA LCD DMA descriptor */
+ struct pxafb_dma_descriptor {
+       unsigned int fdadr;
+@@ -90,6 +144,14 @@
+       wait_queue_head_t       ctrlr_wait;
+       struct work_struct      task;
++#ifdef CONFIG_PXA27x
++      /* PXA Overlay Framebuffer Support */
++      struct overlayfb_info  *overlay1fb;
++      struct overlayfb_info  *overlay2fb;
++      struct overlayfb_info  *cursorfb;
++#endif
++      void (*set_overlay_ctrlr_state)(struct pxafb_info *, u_int);
++
+ #ifdef CONFIG_CPU_FREQ
+       struct notifier_block   freq_transition;
+       struct notifier_block   freq_policy;
+@@ -109,6 +171,9 @@
+ #define C_DISABLE_PM          (5)
+ #define C_ENABLE_PM           (6)
+ #define C_STARTUP             (7)
++#define C_BLANK               (8)
++#define C_UNBLANK             (9)
++
+ #define PXA_NAME      "PXA"
+--- /dev/null
++++ linux-2.6.24-rc1/drivers/video/pxafb_overlay.c
+@@ -0,0 +1,1525 @@
++/*
++ *  linux/drivers/video/pxafb_overlay.c
++ *
++ *  Copyright (c) 2004, Intel Corporation
++ *
++ *    Code Status:
++ *    2004/10/28: <yan.yin@intel.com>
++ *      - Ported to 2.6 kernel
++ *      - Made overlay driver a loadable module
++ *      - Merged overlay optimized patch
++ *    2004/03/10: <stanley.cai@intel.com>
++ *      - Fixed Bugs
++ *      - Added workaround for overlay1&2
++ *    2003/08/27: <yu.tang@intel.com>
++ *      - Added Overlay 1 & Overlay2 & Hardware Cursor support
++ *
++ *
++ *    This software program is licensed subject to the GNU Lesser General
++ *    Public License (LGPL). Version 2.1, February 1999, available at
++ *    http://www.gnu.org/copyleft/lesser.html
++ *
++ *    Intel PXA27x LCD Controller Frame Buffer Overlay Driver
++ *
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/cpufreq.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/arch/bitfield.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/pxa-regs.h>
++
++#include "pxafb.h"
++
++/* LCD enhancement : Overlay 1 & 2 & Hardware Cursor */
++
++/*
++ * LCD enhancement : Overlay 1
++ *
++ * Features:
++ * - support 16bpp (No palette)
++ */
++/*
++ * debugging?
++ */
++#define DEBUG 0
++
++#ifdef  DEBUG
++#define dbg(fmt,arg...) printk(KERN_ALERT "%s(): " fmt "\n", __FUNCTION__, ##arg)
++#else
++#define dbg(fmt,arg...)
++#endif
++
++static int overlay1fb_enable(struct fb_info *info);
++static int overlay2fb_enable(struct fb_info *info);
++static int cursorfb_enable(struct fb_info *info);
++
++static int overlay1fb_disable(struct fb_info *info);
++static int overlay2fb_disable(struct fb_info *info);
++static int cursorfb_disable(struct fb_info *info);
++
++static int overlay1fb_blank(int blank, struct fb_info *info);
++static int overlay2fb_blank(int blank, struct fb_info *info);
++static int cursorfb_blank(int blank, struct fb_info *info);
++
++extern void pxafb_set_ctrlr_state(struct pxafb_info *fbi, u_int state);
++extern int pxafb_blank(int blank, struct fb_info *info);
++
++static struct pxafb_rgb def_rgb_18 = {
++      red:    { offset: 12, length: 6, },
++      green:  { offset: 6,  length: 6, },
++      blue:   { offset: 0,  length: 6, },
++      transp: { offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgbt_16 = {
++      red:    { offset: 10, length: 5, },
++      green:  { offset: 5,  length: 5, },
++      blue:   { offset: 0,  length: 5, },
++      transp: { offset: 15,  length: 1, },
++};
++
++static struct pxafb_rgb  def_rgbt_19 = {
++      red:    { offset: 12, length: 6, },
++      green:  { offset: 6,  length: 6, },
++      blue:   { offset: 0,  length: 6, },
++      transp: { offset: 18, length: 1, },
++};
++
++static struct pxafb_rgb def_rgbt_24 = {
++      red:    { offset: 16, length: 7, },
++      green:  { offset: 8,  length: 8, },
++      blue:   { offset: 0,  length: 8, },
++      transp: { offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgbt_25 = {
++      red:    { offset: 16, length: 8, },
++      green:  { offset: 8,  length: 8, },
++      blue:   { offset: 0,  length: 8, },
++      transp: { offset: 24, length: 1, },
++};
++
++#define CLEAR_LCD_INTR(reg, intr) do {  \
++      reg = (intr);                   \
++}while(0)
++
++#define WAIT_FOR_LCD_INTR(reg,intr,timeout) ({        \
++      int __done =0;                          \
++      int __t = timeout;                      \
++      while (__t) {                           \
++              __done = (reg) & (intr);        \
++              if (__done) break;              \
++              mdelay(10);                     \
++              __t--;                          \
++      }                                       \
++      if (!__t) dbg("wait " #intr " timeount");\
++      __done;                                 \
++})
++
++#define DISABLE_OVERLAYS(fbi) do {                                    \
++      if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) {  \
++              overlay1fb_disable((struct fb_info*)fbi->overlay1fb);   \
++      }                                                               \
++      if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) {  \
++              overlay2fb_disable((struct fb_info*)fbi->overlay2fb);   \
++      }                                                               \
++      if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) {      \
++              cursorfb_disable((struct fb_info*)fbi->cursorfb);       \
++      }                                                               \
++}while(0)
++
++#define ENABLE_OVERLAYS(fbi) do {                                     \
++      if (fbi->overlay1fb && (fbi->overlay1fb->state == C_DISABLE)) { \
++              overlay1fb_enable((struct fb_info*)fbi->overlay1fb);    \
++      }                                                               \
++      if (fbi->overlay2fb && (fbi->overlay2fb->state == C_DISABLE)) { \
++              overlay2fb_enable((struct fb_info*)fbi->overlay2fb);    \
++      }                                                               \
++      if (fbi->cursorfb && (fbi->cursorfb->state == C_DISABLE)) {     \
++              cursorfb_enable((struct fb_info*)fbi->cursorfb);        \
++      }                                                               \
++}while(0)
++
++#define BLANK_OVERLAYS(fbi) do {                                      \
++      if (fbi->overlay1fb && (fbi->overlay1fb->state == C_ENABLE)) {  \
++              overlay1fb_disable((struct fb_info*)fbi->overlay1fb);   \
++              fbi->overlay1fb->state = C_BLANK;                       \
++      }                                                               \
++      if (fbi->overlay2fb && (fbi->overlay2fb->state == C_ENABLE)) {  \
++              overlay2fb_disable((struct fb_info*)fbi->overlay2fb);   \
++              fbi->overlay2fb->state = C_BLANK;                       \
++      }                                                               \
++      if (fbi->cursorfb && (fbi->cursorfb->state == C_ENABLE)) {      \
++              cursorfb_disable((struct fb_info*)fbi->cursorfb);       \
++              fbi->cursorfb->state = C_BLANK;                 \
++      }                                                               \
++}while(0)
++
++#define UNBLANK_OVERLAYS(fbi) do {                                    \
++      if (fbi->overlay1fb && (fbi->overlay1fb->state == C_BLANK)) {   \
++              overlay1fb_enable((struct fb_info*)fbi->overlay1fb);    \
++              fbi->overlay1fb->state = C_ENABLE;                      \
++      }                                                               \
++      if (fbi->overlay2fb && (fbi->overlay2fb->state == C_BLANK)) {   \
++              overlay2fb_enable((struct fb_info*)fbi->overlay2fb);    \
++              fbi->overlay2fb->state = C_ENABLE;                      \
++      }                                                               \
++      if (fbi->cursorfb && (fbi->cursorfb->state == C_BLANK)) {       \
++              cursorfb_enable((struct fb_info*)fbi->cursorfb);        \
++              fbi->cursorfb->state = C_ENABLE;                        \
++      }                                                               \
++}while(0)
++
++static int overlay1fb_open(struct fb_info *info, int user)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      int ret = 0;
++
++/* If basefb is disable, enable fb. */
++      if (fbi->basefb && fbi->basefb->state != C_ENABLE)
++              pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
++
++      down(&fbi->mutex);
++
++      if (fbi->refcount)
++              ret = -EACCES;
++      else
++              fbi->refcount ++;
++
++      up(&fbi->mutex);
++
++      /* Initialize the variables in overlay1 framebuffer. */
++      fbi->fb.var.xres = fbi->fb.var.yres = 0;
++      fbi->fb.var.bits_per_pixel = 0;
++
++      return ret;
++}
++
++static int overlay1fb_release(struct fb_info *info, int user)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      down(&fbi->mutex);
++
++      if (fbi->refcount)
++              fbi->refcount --;
++
++      up(&fbi->mutex);
++      /* disable overlay when released */
++      overlay1fb_blank(1, info);
++
++      return 0;
++}
++
++static int overlay1fb_map_video_memory(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++
++      if (fbi->map_cpu)
++              dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu,  fbi->map_dma);
++      fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
++
++      fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
++                                             &fbi->map_dma, GFP_KERNEL );
++
++      if (!fbi->map_cpu) return -ENOMEM;
++
++      fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
++      fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
++
++      fbi->fb.fix.smem_start = fbi->screen_dma;
++
++      /* setup dma descriptor */
++      fbi->dma1 = (struct pxafb_dma_descriptor*)
++              (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
++
++      fbi->dma1->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma1->fsadr = fbi->screen_dma;
++      fbi->dma1->fidr  = 0;
++      fbi->dma1->ldcmd = fbi->fb.fix.smem_len;
++
++      return 0;
++}
++
++static int overlay1fb_enable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      unsigned long bpp1;
++
++      if (!fbi->map_cpu) return -EINVAL;
++
++      switch (fbi->fb.var.bits_per_pixel) {
++      case 16:
++              bpp1 = 0x4;
++              break;
++      case 18:
++              bpp1 = 0x6;
++              break;
++      case 19:
++              bpp1 = 0x8;
++              break;
++      case 24:
++              bpp1 = 0x9;
++              break;
++      case 25:
++              bpp1 = 0xa;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      /* disable branch/start/end of frame interrupt */
++      LCCR5 |= (LCCR5_IUM1 | LCCR5_BSM1 | LCCR5_EOFM1 | LCCR5_SOFM1);
++
++      if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
++              FDADR1 = (fbi->dma1->fdadr);
++      else
++              FBR1 = fbi->dma1->fdadr | 0x1;
++
++      /* enable overlay 1 window */
++      OVL1C2 = (fbi->ypos << 10) | fbi->xpos;
++      OVL1C1 = OVL1C1_O1EN | (bpp1 << 20) | ((fbi->fb.var.yres-1)<<10) | (fbi->fb.var.xres-1);
++
++      fbi->state = C_ENABLE;
++
++      return 0;
++}
++
++static int overlay1fb_disable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*)info;
++      int done;
++
++      if ((fbi->state == C_DISABLE) || (fbi->state == C_BLANK))
++               return 0;
++
++      fbi->state = C_DISABLE;
++
++      /* clear O1EN */
++      OVL1C1 &= ~OVL1C1_O1EN;
++
++      CLEAR_LCD_INTR(LCSR1, LCSR1_BS1);
++      FBR1 = 0x3;
++      done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS1, 100);
++
++      if (!done) {
++              pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
++              return -1;
++      }
++      return 0;
++}
++
++static int overlay1fb_blank(int blank, struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      int err=0;
++
++      switch (blank) {
++      case 0:
++              err = overlay1fb_enable(info);
++              if (err) {
++                      fbi->state = C_DISABLE;
++                      pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
++              }
++              break;
++      case 1:
++              err = overlay1fb_disable(info);
++              if (err) {
++                      fbi->state = C_DISABLE;
++                      pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
++              }
++              break;
++      default:
++              break;
++      }
++
++      return err;
++}
++
++static int overlay1fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
++{
++      int xpos, ypos;
++      struct overlayfb_info *fbi=(struct overlayfb_info*)info;
++
++      /* must in base frame */
++      xpos = (var->nonstd & 0x3ff);
++      ypos = ((var->nonstd>>10) & 0x3ff);
++
++      if ( (xpos + var->xres) > fbi->basefb->fb.var.xres )
++              return -EINVAL;
++
++      if ( (ypos + var->yres) > fbi->basefb->fb.var.yres )
++              return -EINVAL;
++
++      switch (var->bits_per_pixel) {
++      case 16:
++              if ( var->xres & 0x1 ) {
++                      printk("xres should be a multiple of 2 pixels!\n");
++                      return -EINVAL;
++              }
++              break;
++      case 18:
++      case 19:
++              if ( var->xres & 0x7 ) {
++                      printk("xres should be a multiple of 8 pixels!\n");
++                      return -EINVAL;
++              }
++              break;
++      default:
++              break;
++      }
++
++      fbi->old_var=*var;
++
++      var->activate=FB_ACTIVATE_NOW;
++
++      return 0;
++}
++
++
++static int overlay1fb_set_par(struct fb_info *info)
++{
++      int nbytes=0, err=0, pixels_per_line=0;
++
++      struct overlayfb_info *fbi=(struct overlayfb_info*)info;
++      struct fb_var_screeninfo *var = &fbi->fb.var;
++
++      info->flags &= ~FBINFO_MISC_USEREVENT;
++
++      if (fbi->state == C_BLANK)
++              return 0;
++
++      if (fbi->state == C_DISABLE)
++              goto out1;
++
++      /* only xpos & ypos change */
++      if ( (var->xres == fbi->old_var.xres) &&
++              (var->yres == fbi->old_var.yres) &&
++              (var->bits_per_pixel == fbi->old_var.bits_per_pixel) )
++              goto out2;
++
++out1:
++      switch(var->bits_per_pixel) {
++              case 16:
++                      /* 2 pixels per line */
++                      pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
++                      nbytes = 2;
++
++                      var->red    = def_rgbt_16.red;
++                      var->green  = def_rgbt_16.green;
++                      var->blue   = def_rgbt_16.blue;
++                      var->transp = def_rgbt_16.transp;
++
++                      break;
++              case 18:
++                      /* 8 pixels per line */
++                      pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
++                      nbytes = 3;
++
++                      var->red    = def_rgb_18.red;
++                      var->green  = def_rgb_18.green;
++                      var->blue   = def_rgb_18.blue;
++                      var->transp = def_rgb_18.transp;
++
++                      break;
++              case 19:
++                      /* 8 pixels per line */
++                      pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
++                      nbytes = 3;
++
++                      var->red    = def_rgbt_19.red;
++                      var->green  = def_rgbt_19.green;
++                      var->blue   = def_rgbt_19.blue;
++                      var->transp = def_rgbt_19.transp;
++
++                      break;
++              case 24:
++                      pixels_per_line = fbi->fb.var.xres;
++                      nbytes = 4;
++
++                      var->red    = def_rgbt_24.red;
++                      var->green  = def_rgbt_24.green;
++                      var->blue   = def_rgbt_24.blue;
++                      var->transp = def_rgbt_24.transp;
++
++                      break;
++              case 25:
++                      pixels_per_line = fbi->fb.var.xres;
++                      nbytes = 4;
++
++                      var->red    = def_rgbt_25.red;
++                      var->green  = def_rgbt_25.green;
++                      var->blue   = def_rgbt_25.blue;
++                      var->transp = def_rgbt_25.transp;
++
++                      break;
++              }
++
++              fbi->fb.fix.line_length = nbytes * pixels_per_line;
++              fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
++
++              err= overlay1fb_map_video_memory((struct fb_info*)fbi);
++
++              if (err)
++                      return err;
++
++out2:
++              fbi->xpos = var->nonstd & 0x3ff;
++              fbi->ypos = (var->nonstd>>10) & 0x3ff;
++
++              overlay1fb_enable(info);
++
++              return 0;
++
++}
++
++static struct fb_ops overlay1fb_ops = {
++      .owner                  = THIS_MODULE,
++      .fb_open                = overlay1fb_open,
++      .fb_release             = overlay1fb_release,
++      .fb_check_var           = overlay1fb_check_var,
++      .fb_set_par             = overlay1fb_set_par,
++      .fb_blank               = overlay1fb_blank,
++      .fb_fillrect            = cfb_fillrect,
++      .fb_copyarea            = cfb_copyarea,
++      .fb_imageblit           = cfb_imageblit,
++};
++
++ /*
++ * LCD enhancement : Overlay 2
++ *
++ * Features:
++ * - support planar YCbCr420/YCbCr422/YCbCr444;
++ */
++static int overlay2fb_open(struct fb_info *info, int user)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      int ret = 0;
++
++      /* if basefb is disable, enable fb. */
++      if (fbi->basefb && fbi->basefb->state != C_ENABLE)
++              pxafb_blank(VESA_NO_BLANKING, (struct fb_info *)(fbi->basefb));
++
++      down(&fbi->mutex);
++
++      if (fbi->refcount)
++              ret = -EACCES;
++      else
++              fbi->refcount ++;
++
++      up(&fbi->mutex);
++      fbi->fb.var.xres = fbi->fb.var.yres = 0;
++
++      return ret;
++}
++
++static int overlay2fb_release(struct fb_info *info, int user)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++
++      down(&fbi->mutex);
++
++      if (fbi->refcount)
++              fbi->refcount --;
++
++      up(&fbi->mutex);
++
++      /* disable overlay when released */
++      overlay2fb_blank(1, info);
++
++      return 0;
++}
++
++static int overlay2fb_map_YUV_memory( struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      unsigned int ylen, cblen, crlen, aylen, acblen, acrlen;
++      unsigned int yoff, cboff, croff;
++      unsigned int xres,yres;
++      unsigned int nbytes;
++
++      ylen = cblen = crlen = aylen = acblen = acrlen = 0;
++      yoff = cboff = croff = 0;
++
++      if (fbi->map_cpu)
++              dma_free_writecombine(NULL, fbi->map_size, (void*)fbi->map_cpu,  fbi->map_dma);
++
++      yres = fbi->fb.var.yres;
++
++      switch(fbi->format) {
++      case 0x4: /* YCbCr 4:2:0 planar */
++              pr_debug("420 planar\n");
++              /* 16 pixels per line */
++              xres = (fbi->fb.var.xres + 0xf) & (~0xf);
++              fbi->fb.fix.line_length = xres;
++
++              nbytes = xres * yres;
++              ylen = nbytes;
++              cblen = crlen = (nbytes/4);
++
++              break;
++      case 0x3: /* YCbCr 4:2:2 planar */
++              /* 8 pixles per line */
++              pr_debug("422 planar\n");
++              xres = (fbi->fb.var.xres + 0x7) & (~0x7);
++              fbi->fb.fix.line_length = xres;
++
++              nbytes = xres * yres;
++              ylen  = nbytes;
++              cblen = crlen = (nbytes/2);
++
++              break;
++      case 0x2: /* YCbCr 4:4:4 planar */
++              /* 4 pixels per line */
++              pr_debug("444 planar\n");
++              xres = (fbi->fb.var.xres + 0x3) & (~0x3);
++              fbi->fb.fix.line_length = xres;
++
++              nbytes = xres * yres;
++              ylen  = cblen = crlen = nbytes;
++              break;
++      }
++
++      /* 16-bytes alignment for DMA */
++      aylen  = (ylen + 0xf) & (~0xf);
++      acblen = (cblen + 0xf) & (~0xf);
++      acrlen = (crlen + 0xf) & (~0xf);
++
++      fbi->fb.fix.smem_len = aylen + acblen + acrlen;
++
++      /* alloc memory */
++
++      fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
++      fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
++                                             &fbi->map_dma, GFP_KERNEL );
++
++      if (!fbi->map_cpu) return -ENOMEM;
++
++      fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
++      fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
++
++      fbi->fb.fix.smem_start = fbi->screen_dma;
++
++      /* setup dma for Planar format */
++      fbi->dma2 = (struct pxafb_dma_descriptor*)
++              (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma3 = fbi->dma2 - 1;
++      fbi->dma4 = fbi->dma3 - 1;
++
++      /* offset */
++      yoff = 0;
++      cboff = aylen;
++      croff = cboff + acblen;
++
++      /* Y vector */
++      fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma2->fsadr = fbi->screen_dma + yoff;
++      fbi->dma2->fidr  = 0;
++      fbi->dma2->ldcmd = ylen;
++
++      /* Cb vector */
++      fbi->dma3->fdadr = (fbi->dma2->fdadr - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma3->fsadr = (fbi->screen_dma + cboff);
++      fbi->dma3->fidr  = 0;
++      fbi->dma3->ldcmd = cblen;
++
++      /* Cr vector */
++
++      fbi->dma4->fdadr = (fbi->dma3->fdadr - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma4->fsadr = (fbi->screen_dma + croff);
++      fbi->dma4->fidr  = 0;
++      fbi->dma4->ldcmd = crlen;
++
++      /* adjust for user */
++      fbi->fb.var.red.length   = ylen;
++      fbi->fb.var.red.offset   = yoff;
++      fbi->fb.var.green.length = cblen;
++      fbi->fb.var.green.offset = cboff;
++      fbi->fb.var.blue.length  = crlen;
++      fbi->fb.var.blue.offset  = croff;
++
++      return 0;
++};
++
++static int overlay2fb_map_RGB_memory( struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      struct fb_var_screeninfo *var = &fbi->fb.var;
++      int pixels_per_line=0 , nbytes=0;
++
++      if (fbi->map_cpu)
++              dma_free_writecombine(NULL,  fbi->map_size, (void*)fbi->map_cpu, fbi->map_dma);
++
++      switch(var->bits_per_pixel) {
++      case 16:
++              /* 2 pixels per line */
++              pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
++              nbytes = 2;
++
++              var->red    = def_rgbt_16.red;
++              var->green  = def_rgbt_16.green;
++              var->blue   = def_rgbt_16.blue;
++              var->transp = def_rgbt_16.transp;
++              break;
++
++      case 18:
++              /* 8 pixels per line */
++              pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
++              nbytes = 3;
++
++              var->red    = def_rgb_18.red;
++              var->green  = def_rgb_18.green;
++              var->blue   = def_rgb_18.blue;
++              var->transp = def_rgb_18.transp;
++
++              break;
++      case 19:
++              /* 8 pixels per line */
++              pixels_per_line = (fbi->fb.var.xres + 0x7 ) & (~0x7);
++              nbytes = 3;
++
++              var->red    = def_rgbt_19.red;
++              var->green  = def_rgbt_19.green;
++              var->blue   = def_rgbt_19.blue;
++              var->transp = def_rgbt_19.transp;
++
++              break;
++      case 24:
++              pixels_per_line = fbi->fb.var.xres;
++              nbytes = 4;
++
++              var->red    = def_rgbt_24.red;
++              var->green  = def_rgbt_24.green;
++              var->blue   = def_rgbt_24.blue;
++              var->transp = def_rgbt_24.transp;
++
++              break;
++
++      case 25:
++              pixels_per_line = fbi->fb.var.xres;
++              nbytes = 4;
++
++              var->red    = def_rgbt_25.red;
++              var->green  = def_rgbt_25.green;
++              var->blue   = def_rgbt_25.blue;
++              var->transp = def_rgbt_25.transp;
++
++              break;
++      }
++
++      fbi->fb.fix.line_length = nbytes * pixels_per_line;
++      fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
++
++      fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
++      fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
++                                             &fbi->map_dma, GFP_KERNEL );
++
++      if (!fbi->map_cpu) return -ENOMEM;
++
++      fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
++      fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
++
++      fbi->fb.fix.smem_start = fbi->screen_dma;
++
++      /* setup dma descriptor */
++      fbi->dma2 = (struct pxafb_dma_descriptor*)
++              (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
++
++      fbi->dma2->fdadr = (fbi->screen_dma - sizeof(struct pxafb_dma_descriptor));
++      fbi->dma2->fsadr = fbi->screen_dma;
++      fbi->dma2->fidr  = 0;
++      fbi->dma2->ldcmd = fbi->fb.fix.smem_len;
++
++      return 0;
++}
++
++static int overlay2fb_enable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      unsigned long bpp2;
++      unsigned int xres, yres;
++
++      if (!fbi->map_cpu) return -EINVAL;
++
++      switch(fbi->fb.var.bits_per_pixel) {
++      case 16:
++              bpp2 = 0x4;
++              break;
++      case 18:
++              bpp2 = 0x6;
++              break;
++      case 19:
++              bpp2 = 0x8;
++              break;
++      case 24:
++              bpp2 = 0x9;
++              break;
++      case 25:
++              bpp2 = 0xa;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++        /* disable branch/start/end of frame interrupt */
++      LCCR5 |= (LCCR5_IUM4 | LCCR5_IUM3 | LCCR5_IUM2 |
++                LCCR5_BSM4 | LCCR5_BSM3 | LCCR5_BSM2 |
++                LCCR5_EOFM4 | LCCR5_EOFM3 | LCCR5_EOFM2 |
++                LCCR5_SOFM4 | LCCR5_SOFM3 | LCCR5_SOFM2);
++
++      if (fbi->format == 0) {
++              /* overlay2 RGB resolution, RGB and YUV have different xres value*/
++              xres = fbi->fb.var.xres;
++              yres = fbi->fb.var.yres;
++
++              OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
++              OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
++              /* setup RGB DMA */
++              if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
++                      FDADR2 = fbi->dma2->fdadr;
++              else
++                      FBR2 = fbi->dma2->fdadr | 0x1;
++      } else {
++              /* overlay2 YUV resolution */
++              xres = fbi->fb.fix.line_length;
++              yres = fbi->fb.var.yres;
++
++              OVL2C2 = (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos;
++              OVL2C1 = OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1);
++
++              if (fbi->state == C_DISABLE || fbi->state == C_BLANK) {
++                      FDADR2 = fbi->dma2->fdadr;
++                      FDADR3 = fbi->dma3->fdadr;
++                      FDADR4 = fbi->dma4->fdadr;
++              } else {
++                      FBR2 = fbi->dma2->fdadr | 0x01;
++                      FBR3 = fbi->dma3->fdadr | 0x01;
++                      FBR4 = fbi->dma4->fdadr | 0x01;
++              }
++      }
++
++      fbi->state = C_ENABLE;
++      return 0;
++}
++
++static int overlay2fb_disable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*)info;
++      int done;
++
++      if (fbi->state == C_DISABLE)
++              return 0;
++      if (fbi->state == C_BLANK) {
++              fbi->state = C_DISABLE;
++              return 0;
++      }
++
++      fbi->state = C_DISABLE;
++
++      /* clear O2EN */
++      OVL2C1 &= ~OVL2C1_O2EN;
++
++      /* Make overlay2 can't disable/enable
++       * correctly sometimes.
++       */
++      CLEAR_LCD_INTR(LCSR1, LCSR1_BS2);
++
++      if (fbi->format == 0)
++              FBR2 = 0x3;
++      else {
++              FBR2 = 0x3;
++              FBR3 = 0x3;
++              FBR4 = 0x3;
++      }
++
++      done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS2, 100);
++
++      if (!done) {
++              pr_debug(KERN_INFO "%s: timeout\n", __FUNCTION__);
++              return -1;
++      }
++      return 0;
++}
++
++static int overlay2fb_blank(int blank, struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      int err=0;
++
++      switch(blank)
++      {
++      case 0:
++              err = overlay2fb_enable(info);
++              if (err) {
++                      fbi->state = C_DISABLE;
++                      pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
++              }
++              break;
++      case 1:
++              err = overlay2fb_disable(info);
++              if (err) {
++                      fbi->state = C_DISABLE;
++                      pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
++              }
++              break;
++      default:
++              /* reserved */
++              break;
++      }
++
++      return err;
++}
++
++
++static int overlay2fb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
++{
++      int xpos, ypos, xres, yres;
++      int format;
++      struct overlayfb_info *fbi=(struct overlayfb_info*)info;
++
++      xres=yres=0;
++
++      xpos = (var->nonstd & 0x3ff);
++      ypos = (var->nonstd >> 10) & 0x3ff;
++      format = (var->nonstd >>20) & 0x7;
++
++
++      /* Palnar YCbCr444, YCbCr422, YCbCr420 */
++      if ( (format != 0x4) && (format != 0x3) && (format != 0x2) && (format !=0x0))
++              return -EINVAL;
++
++      /* dummy pixels */
++      switch(format) {
++      case 0x0: /* RGB */
++              xres = var->xres;
++              break;
++      case 0x2: /* 444 */
++              xres = (var->xres + 0x3) & ~(0x3);
++              break;
++      case 0x3: /* 422 */
++              xres = (var->xres + 0x7) & ~(0x7);
++              break;
++      case 0x4: /* 420 */
++              xres = (var->xres + 0xf) & ~(0xf);
++              break;
++      }
++      yres = var->yres;
++
++      if ( (xpos + xres) > fbi->basefb->fb.var.xres )
++              return -EINVAL;
++
++      if ( (ypos + yres) > fbi->basefb->fb.var.yres )
++              return -EINVAL;
++
++      fbi->old_var=*var;
++
++      var->activate=FB_ACTIVATE_NOW;
++
++      return 0;
++
++}
++
++
++/*
++ * overlay2fb_set_var()
++ *
++ * var.nonstd is used as YCbCr format.
++ * var.red/green/blue is used as (Y/Cb/Cr) vector
++ */
++
++static int overlay2fb_set_par(struct fb_info *info)
++{
++      unsigned int xpos, ypos;
++      int format, err;
++
++      struct overlayfb_info *fbi=(struct overlayfb_info*)info;
++      struct fb_var_screeninfo *var = &fbi->fb.var;
++
++      info->flags &= ~FBINFO_MISC_USEREVENT;
++
++      if (fbi->state == C_BLANK)
++              return 0;
++
++      if (fbi->state == C_DISABLE)
++              goto out1;
++
++      if ( (var->xres == fbi->old_var.xres) &&
++              (var->yres == fbi->old_var.yres) &&
++              (var->bits_per_pixel == fbi->old_var.bits_per_pixel) &&
++              (((var->nonstd>>20) & 0x7) == fbi->format) )
++              goto out2;
++
++out1:
++      xpos = var->nonstd & 0x3ff;
++      ypos = (var->nonstd>>10) & 0x3ff;
++      format = (var->nonstd>>20) & 0x7;
++
++
++      fbi->format = format;
++      if ( fbi->format==0 )
++              err = overlay2fb_map_RGB_memory(info);
++      else
++              err = overlay2fb_map_YUV_memory(info);
++
++      if (err) return err;
++
++out2:
++      /* position */
++      fbi->xpos = var->nonstd & 0x3ff;
++      fbi->ypos = (var->nonstd>>10) & 0x3ff;
++
++      overlay2fb_enable(info);
++
++      return 0;
++}
++
++static struct fb_ops overlay2fb_ops = {
++      .owner                  = THIS_MODULE,
++      .fb_open                = overlay2fb_open,
++      .fb_release             = overlay2fb_release,
++      .fb_check_var           = overlay2fb_check_var,
++      .fb_set_par             = overlay2fb_set_par,
++      .fb_blank               = overlay2fb_blank,
++      .fb_fillrect            = cfb_fillrect,
++      .fb_copyarea            = cfb_copyarea,
++      .fb_imageblit           = cfb_imageblit,
++};
++
++/* Hardware cursor */
++
++/* Bulverde Cursor Modes */
++struct cursorfb_mode{
++      int xres;
++      int yres;
++      int bpp;
++};
++
++static struct cursorfb_mode cursorfb_modes[]={
++      { 32,  32, 2},
++      { 32,  32, 2},
++      { 32,  32, 2},
++      { 64,  64, 2},
++      { 64,  64, 2},
++      { 64,  64, 2},
++      {128, 128, 1},
++      {128, 128, 1}
++};
++
++static int cursorfb_enable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++
++      if (!fbi->map_cpu) return -EINVAL;
++
++      CCR &= ~CCR_CEN;
++
++      /* set palette format
++       *
++       * FIXME: if only cursor uses palette
++       */
++      LCCR4 = (LCCR4 & (~(0x3<<15))) | (0x1<<15);
++
++      /* disable branch/start/end of frame interrupt */
++      LCCR5 |= (LCCR5_IUM5 | LCCR5_BSM5 | LCCR5_EOFM5 | LCCR5_SOFM5);
++
++      /* load palette and frame data */
++      if (fbi->state == C_DISABLE) {
++              FDADR5 = fbi->dma5_pal->fdadr;
++              udelay(1);
++              FDADR5 = fbi->dma5_frame->fdadr;
++              udelay(1);
++
++      }
++      else {
++              FBR5 = fbi->dma5_pal->fdadr | 0x1;
++              udelay(1);
++              FBR5 = fbi->dma5_frame->fdadr | 0x1;
++              udelay(1);
++      }
++
++      CCR = CCR_CEN | (fbi->ypos << 15) | (fbi->xpos << 5) | (fbi->format);
++
++      fbi->state = C_ENABLE;
++
++      return 0;
++}
++
++static int cursorfb_disable(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*)info;
++      int done, ret = 0;
++
++      fbi->state = C_DISABLE;
++
++      done = WAIT_FOR_LCD_INTR(LCSR1, LCSR1_BS5, 100);
++      if (!done) ret = -1;
++
++      CCR &= ~CCR_CEN;
++
++      return ret;
++}
++
++static int cursorfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++                     u_int trans, struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info *)info;
++      u_int val, ret = 1;
++      u_int *pal=(u_int*) fbi->palette_cpu;
++
++      /* 25bit with Transparcy for 16bpp format */
++      if (regno < fbi->palette_size) {
++              val = ((trans << 24)  & 0x1000000);
++              val |= ((red << 16)  & 0x0ff0000);
++              val |= ((green << 8 ) & 0x000ff00);
++              val |= ((blue << 0) & 0x00000ff);
++
++              pal[regno] = val;
++              ret = 0;
++      }
++      return ret;
++}
++
++int cursorfb_blank(int blank, struct fb_info *info)
++{
++      switch(blank)
++      {
++      case 0:
++              cursorfb_enable(info);
++              break;
++      case 1:
++              cursorfb_disable(info);
++              break;
++      default:
++              /* reserved */
++              break;
++      }
++      return 0;
++}
++
++static int cursorfb_check_var( struct fb_var_screeninfo *var, struct fb_info *info)
++{
++      int xpos, ypos, xres, yres;
++      int mode;
++      struct cursorfb_mode *cursor;
++      struct overlayfb_info *fbi=(struct overlayfb_info*)info;
++
++      mode = var->nonstd & 0x7;
++      xpos = (var->nonstd>>5) & 0x3ff;
++      ypos = (var->nonstd>>15) & 0x3ff;
++
++      if (mode>7 || mode <0 )
++              return -EINVAL;
++
++      cursor = cursorfb_modes + mode;
++
++      xres = cursor->xres;
++      yres = cursor->yres;
++
++      if ( (xpos + xres) > fbi->basefb->fb.var.xres )
++              return -EINVAL;
++
++      if ( (ypos + yres) > fbi->basefb->fb.var.yres )
++              return -EINVAL;
++
++      return 0;
++
++}
++
++static int cursorfb_set_par(struct fb_info *info)
++{
++      struct overlayfb_info *fbi = (struct overlayfb_info*) info;
++      struct fb_var_screeninfo *var = &fbi->fb.var;
++      struct cursorfb_mode *cursor;
++      int mode, xpos, ypos;
++      int err;
++
++      info->flags &= ~FBINFO_MISC_USEREVENT;
++
++      mode = var->nonstd & 0x7;
++      xpos = (var->nonstd>>5) & 0x3ff;
++      ypos = (var->nonstd>>15) & 0x3ff;
++
++      if (mode != fbi->format) {
++              cursor = cursorfb_modes + mode;
++
++              /* update "var" info */
++              fbi->fb.var.xres = cursor->xres;
++              fbi->fb.var.yres = cursor->yres;
++              fbi->fb.var.bits_per_pixel = cursor->bpp;
++
++              /* alloc video memory
++               *
++               * 4k is engouh for 128x128x1 cursor,
++               * - 2k for cursor pixels,
++               * - 2k for palette data, plus 2 dma descriptor
++               */
++              if (!fbi->map_cpu) {
++                      fbi->map_size = PAGE_SIZE;
++                      fbi->map_cpu = (unsigned long)dma_alloc_writecombine(NULL, fbi->map_size,
++                                             &fbi->map_dma, GFP_KERNEL );
++                      if (!fbi->map_cpu) return -ENOMEM;
++              }
++
++              cursor = cursorfb_modes + mode;
++
++              /* update overlay & fix "info" */
++              fbi->screen_cpu         = fbi->map_cpu;
++              fbi->palette_cpu        = fbi->map_cpu + (PAGE_SIZE/2);
++              fbi->screen_dma         = fbi->map_dma;
++              fbi->palette_dma        = fbi->map_dma + (PAGE_SIZE/2);
++
++              fbi->format             = mode;
++              fbi->palette_size       = (1<<cursor->bpp);
++              fbi->fb.fix.smem_start  = fbi->screen_dma;
++              fbi->fb.fix.smem_len    = cursor->xres * cursor->yres * cursor->bpp / 8;
++              fbi->fb.fix.line_length = cursor->xres * cursor->bpp / 8;
++
++              fbi->dma5_pal           = (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 16 );
++              fbi->dma5_pal->fdadr    = (fbi->map_dma + PAGE_SIZE - 16);
++              fbi->dma5_pal->fsadr    = fbi->palette_dma;
++              fbi->dma5_pal->fidr     = 0;
++              fbi->dma5_pal->ldcmd    = (fbi->palette_size<<2) | LDCMD_PAL;
++
++              fbi->dma5_frame                 = (struct pxafb_dma_descriptor*)(fbi->map_cpu + PAGE_SIZE - 32 );
++              fbi->dma5_frame->fdadr  = (fbi->map_dma + PAGE_SIZE - 32);
++              fbi->dma5_frame->fsadr  = fbi->screen_dma;
++              fbi->dma5_frame->fidr   = 0;
++              fbi->dma5_frame->ldcmd  = fbi->fb.fix.smem_len;
++
++              /* alloc & set default cmap */
++              err = fb_alloc_cmap(&fbi->fb.cmap, fbi->palette_size, 0);
++              if (err) return err;
++              err = fb_set_cmap(&fbi->fb.cmap, info);
++              if (err) return err;
++      }
++
++      /* update overlay info */
++      if ( (xpos != fbi->xpos) || (ypos != fbi->ypos) ) {
++              fbi->xpos = xpos;
++              fbi->ypos = ypos;
++      }
++
++      cursorfb_enable(info);
++      pxafb_set_ctrlr_state(fbi->basefb, C_REENABLE);
++
++      return 0;
++}
++
++static struct fb_ops cursorfb_ops = {
++      .owner                  = THIS_MODULE,
++      .fb_check_var           = cursorfb_check_var,
++      .fb_set_par             = cursorfb_set_par,
++      .fb_blank               = cursorfb_blank,
++      .fb_fillrect            = cfb_fillrect,
++      .fb_copyarea            = cfb_copyarea,
++      .fb_imageblit           = cfb_imageblit,
++      .fb_setcolreg           = cursorfb_setcolreg,
++};
++
++static struct overlayfb_info * __init overlay1fb_init_fbinfo(void)
++{
++      struct overlayfb_info *fbi;
++
++      fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
++      if (!fbi)
++              return NULL;
++
++      memset(fbi, 0, sizeof(struct overlayfb_info) );
++
++      fbi->refcount = 0;
++      init_MUTEX(&fbi->mutex);
++
++      strcpy(fbi->fb.fix.id, "overlay1");
++
++      fbi->fb.fix.type                = FB_TYPE_PACKED_PIXELS;
++      fbi->fb.fix.type_aux            = 0;
++      fbi->fb.fix.xpanstep            = 0;
++      fbi->fb.fix.ypanstep            = 0;
++      fbi->fb.fix.ywrapstep           = 0;
++      fbi->fb.fix.accel               = FB_ACCEL_NONE;
++
++      fbi->fb.var.nonstd              = 0;
++      fbi->fb.var.activate            = FB_ACTIVATE_NOW;
++      fbi->fb.var.height              = -1;
++      fbi->fb.var.width               = -1;
++      fbi->fb.var.accel_flags = 0;
++      fbi->fb.var.vmode               = FB_VMODE_NONINTERLACED;
++
++
++      fbi->fb.fbops                   = &overlay1fb_ops;
++      fbi->fb.flags                   = FBINFO_FLAG_DEFAULT;
++      fbi->fb.node                    = -1;
++      fbi->fb.pseudo_palette          = NULL;
++
++      fbi->xpos                       = 0;
++      fbi->ypos                       = 0;
++      fbi->format                     = -1;
++      fbi->state                      = C_DISABLE;
++
++      return fbi;
++}
++
++static struct overlayfb_info * __init overlay2fb_init_fbinfo(void)
++{
++      struct overlayfb_info *fbi;
++
++      fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
++      if (!fbi)
++              return NULL;
++
++      memset(fbi, 0, sizeof(struct overlayfb_info) );
++
++      fbi->refcount = 0;
++      init_MUTEX(&fbi->mutex);
++
++      strcpy(fbi->fb.fix.id, "overlay2");
++
++      fbi->fb.fix.type                = FB_TYPE_PACKED_PIXELS;
++      fbi->fb.fix.type_aux            = 0;
++      fbi->fb.fix.xpanstep            = 0;
++      fbi->fb.fix.ypanstep            = 0;
++      fbi->fb.fix.ywrapstep           = 0;
++      fbi->fb.fix.accel               = FB_ACCEL_NONE;
++
++      fbi->fb.var.nonstd              = 0;
++      fbi->fb.var.activate            = FB_ACTIVATE_NOW;
++      fbi->fb.var.height              = -1;
++      fbi->fb.var.width               = -1;
++      fbi->fb.var.accel_flags         = 0;
++      fbi->fb.var.vmode               = FB_VMODE_NONINTERLACED;
++
++      fbi->fb.fbops                   = &overlay2fb_ops;
++      fbi->fb.flags                   = FBINFO_FLAG_DEFAULT;
++      fbi->fb.node                    = -1;
++      fbi->fb.pseudo_palette          = NULL;
++
++      fbi->xpos                       = 0;
++      fbi->ypos                       = 0;
++      fbi->format                     = -1;
++      fbi->state                      = C_DISABLE;
++
++      return fbi;
++}
++
++static struct overlayfb_info * __init cursorfb_init_fbinfo(void)
++{
++      struct overlayfb_info *fbi;
++
++      fbi = kmalloc(sizeof(struct overlayfb_info) + sizeof(u16) * 16, GFP_KERNEL);
++      if (!fbi)
++              return NULL;
++
++      memset(fbi, 0, sizeof(struct overlayfb_info) );
++
++      fbi->refcount = 0;
++      init_MUTEX(&fbi->mutex);
++
++      strcpy(fbi->fb.fix.id, "cursor");
++
++      fbi->fb.fix.type                = FB_TYPE_PACKED_PIXELS;
++      fbi->fb.fix.type_aux            = 0;
++      fbi->fb.fix.xpanstep            = 0;
++      fbi->fb.fix.ypanstep            = 0;
++      fbi->fb.fix.ywrapstep           = 0;
++      fbi->fb.fix.accel               = FB_ACCEL_NONE;
++
++      fbi->fb.var.nonstd              = 0;
++      fbi->fb.var.activate            = FB_ACTIVATE_NOW;
++      fbi->fb.var.height              = -1;
++      fbi->fb.var.width               = -1;
++      fbi->fb.var.accel_flags         = 0;
++      fbi->fb.var.vmode               = FB_VMODE_NONINTERLACED;
++
++      fbi->fb.fbops                   = &cursorfb_ops;
++      fbi->fb.flags                   = FBINFO_FLAG_DEFAULT;
++      fbi->fb.node                    = -1;
++      fbi->fb.pseudo_palette          = NULL;
++
++
++      fbi->xpos                       = 0;
++      fbi->ypos                       = 0;
++      fbi->format                     = -1;
++      fbi->state                      = C_DISABLE;
++
++      return fbi;
++}
++
++
++void pxa_set_overlay_ctrlr_state(struct pxafb_info *fbi, u_int state)
++{
++      switch (state) {
++      case C_DISABLE:
++                      DISABLE_OVERLAYS(fbi);
++                      break;
++      case C_ENABLE:
++                      ENABLE_OVERLAYS(fbi);
++                      break;
++      case C_BLANK:
++                      BLANK_OVERLAYS(fbi);
++                      break;
++      case C_UNBLANK:
++                      UNBLANK_OVERLAYS(fbi);
++                      break;
++      default:
++                      break;
++      }
++}
++
++static int is_pxafb_device(struct device * dev, void * data)
++{
++      struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++
++      return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0);
++}
++
++static int __devinit pxafb_overlay_init(void)
++{
++      int ret;
++      struct overlayfb_info *overlay1fb, *overlay2fb, *cursorfb;
++      struct pxafb_info *fbi;
++      struct device *dev;
++
++      ret = -1;
++      overlay1fb = overlay2fb = cursorfb = NULL;
++      fbi = NULL;
++
++      dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
++      if (!dev) {
++              printk(KERN_INFO "Base framebuffer not exists, failed to load overlay driver!\n");
++              return ret;
++      }
++
++      fbi = dev_get_drvdata(dev);
++      if (fbi == NULL) {
++              printk(KERN_INFO "Base framebuffer not initialized, failed to load overlay driver!\n");
++              return ret;
++      }
++
++      /* Overlay 1 windows */
++      overlay1fb = overlay1fb_init_fbinfo();
++
++      if (!overlay1fb) {
++              ret = -ENOMEM;
++              printk("overlay1fb_init_fbinfo failed\n");
++              goto failed;
++      }
++
++      ret = register_framebuffer(&overlay1fb->fb);
++      if (ret < 0)
++              goto failed;
++
++      /* Overlay 2 window */
++      overlay2fb = overlay2fb_init_fbinfo();
++
++      if (!overlay2fb) {
++              ret = -ENOMEM;
++              printk("overlay2fb_init_fbinfo failed\n");
++              goto failed;
++      }
++
++      ret = register_framebuffer(&overlay2fb->fb);
++      if (ret < 0) goto failed;
++
++      /* Hardware cursor window */
++      cursorfb = cursorfb_init_fbinfo();
++
++      if (!cursorfb) {
++              ret = -ENOMEM;
++              printk("cursorfb_init_fbinfo failed\n");
++              goto failed;
++      }
++
++      ret = register_framebuffer(&cursorfb->fb);
++      if (ret < 0) goto failed;
++
++
++      /* set refernce to Overlays  */
++      fbi->overlay1fb  = overlay1fb;
++      fbi->overlay2fb  = overlay2fb;
++      fbi->cursorfb    = cursorfb;
++      fbi->set_overlay_ctrlr_state=pxa_set_overlay_ctrlr_state;
++
++      /* set refernce to BaseFrame */
++      overlay1fb->basefb = fbi;
++      overlay2fb->basefb = fbi;
++      cursorfb->basefb = fbi;
++
++      printk(KERN_INFO "Load PXA Overlay driver successfully!\n");
++
++      return 0;
++
++failed:
++      if (overlay1fb)
++              kfree(overlay1fb);
++      if (overlay2fb)
++              kfree(overlay2fb);
++      if (cursorfb)
++              kfree(cursorfb);
++      printk(KERN_INFO "Load PXA Overlay driver failed!\n");
++      return ret;
++}
++
++static void __exit pxafb_overlay_exit(void)
++{
++      struct pxafb_info *fbi;
++      struct device *dev;
++
++      dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
++      if (!dev)
++              return;
++
++      fbi = dev_get_drvdata(dev);
++      if (!fbi)
++              return;
++
++      if (fbi->overlay1fb) {
++              unregister_framebuffer(&(fbi->overlay1fb->fb));
++              kfree(fbi->overlay1fb);
++              fbi->overlay1fb  = NULL;
++      }
++
++      if (fbi->overlay2fb) {
++              unregister_framebuffer(&(fbi->overlay2fb->fb));
++              kfree(fbi->overlay2fb);
++              fbi->overlay2fb  = NULL;
++      }
++
++      if (fbi->cursorfb) {
++              unregister_framebuffer(&(fbi->cursorfb->fb));
++              kfree(fbi->cursorfb);
++              fbi->cursorfb  = NULL;
++      }
++
++      fbi->set_overlay_ctrlr_state = NULL;
++
++      printk(KERN_INFO "Unload PXA Overlay driver successfully!\n");
++      return;
++}
++
++
++module_init(pxafb_overlay_init);
++module_exit(pxafb_overlay_exit);
++
++MODULE_DESCRIPTION("Loadable framebuffer overlay driver for PXA");
++MODULE_LICENSE("GPL");
++
+--- linux-2.6.24-rc1.orig/include/asm-arm/arch-pxa/pxa-regs.h
++++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -789,11 +789,18 @@
+ #define UDC_INT_PACKETCMP  (0x1)
+ #define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
++/* Older defines, do not use. */
+ #define UDCICR1_IECC  (1 << 31)       /* IntEn - Configuration Change */
+ #define UDCICR1_IESOF (1 << 30)       /* IntEn - Start of Frame */
+ #define UDCICR1_IERU  (1 << 29)       /* IntEn - Resume */
+ #define UDCICR1_IESU  (1 << 28)       /* IntEn - Suspend */
+ #define UDCICR1_IERS  (1 << 27)       /* IntEn - Reset */
++/* New defines. */
++#define UDCISR1_IRCC  (1 << 31)       /* IntEn - Configuration Change */
++#define UDCISR1_IRSOF (1 << 30)       /* IntEn - Start of Frame */
++#define UDCISR1_IRRU  (1 << 29)       /* IntEn - Resume */
++#define UDCISR1_IRSU  (1 << 28)       /* IntEn - Suspend */
++#define UDCISR1_IRRS  (1 << 27)       /* IntEn - Reset */
+ #define UDCISR0         __REG(0x4060000C) /* UDC Interrupt Status Register 0 */
+ #define UDCISR1         __REG(0x40600010) /* UDC Interrupt Status Register 1 */
+@@ -1827,6 +1834,8 @@
+ #define DFBR0         __REG(0x44000020)  /* DMA Channel 0 Frame Branch Register */
+ #define DFBR1         __REG(0x44000024)  /* DMA Channel 1 Frame Branch Register */
+ #define LCSR          __REG(0x44000038)  /* LCD Controller Status Register */
++#define LCSR0         __REG(0x44000038)  /* LCD Controller Status Register */
++#define LCSR1         __REG(0x44000034)  /* LCD Controller Status Register */
+ #define LIIDR         __REG(0x4400003C)  /* LCD Controller Interrupt ID Register */
+ #define TMEDRGBR      __REG(0x44000040)  /* TMED RGB Seed Register */
+ #define TMEDCR                __REG(0x44000044)  /* TMED Control Register */
+@@ -1836,6 +1845,10 @@
+ #define LCCR3_4BPP (2 << 24)
+ #define LCCR3_8BPP (3 << 24)
+ #define LCCR3_16BPP (4 << 24)
++#define LCCR3_18BPP (6 << 24)
++#define LCCR3_19BPP (8 << 24)
++#define LCCR3_24BPP (9 << 24)
++#define LCCR3_25BPP (10<< 24)
+ #define LCCR3_PDFOR_0 (0 << 30)
+ #define LCCR3_PDFOR_1 (1 << 30)
+@@ -2010,6 +2023,104 @@
+ #define LDCMD_PAL     (1 << 26)       /* instructs DMA to load palette buffer */
++/* Overlay1 & Overlay2 & Hardware Cursor */
++#define LCSR1_SOF1    (1 << 0)
++#define LCSR1_SOF2    (1 << 1)
++#define LCSR1_SOF3    (1 << 2)
++#define LCSR1_SOF4    (1 << 3)
++#define LCSR1_SOF5    (1 << 4)
++#define LCSR1_SOF6    (1 << 5)
++
++#define LCSR1_EOF1    (1 << 8)
++#define LCSR1_EOF2    (1 << 9)
++#define LCSR1_EOF3    (1 << 10)
++#define LCSR1_EOF4    (1 << 11)
++#define LCSR1_EOF5    (1 << 12)
++#define LCSR1_EOF6    (1 << 13)
++
++#define LCSR1_BS1     (1 << 16)
++#define LCSR1_BS2     (1 << 17)
++#define LCSR1_BS3     (1 << 18)
++#define LCSR1_BS4     (1 << 19)
++#define LCSR1_BS5     (1 << 20)
++#define LCSR1_BS6     (1 << 21)
++
++#define LCSR1_IU2     (1 << 25)
++#define LCSR1_IU3     (1 << 26)
++#define LCSR1_IU4     (1 << 27)
++#define LCSR1_IU5     (1 << 28)
++#define LCSR1_IU6     (1 << 29)
++
++#define LDCMD_SOFINT  (1 << 22)
++#define LDCMD_EOFINT  (1 << 21)
++
++
++#define LCCR5_SOFM1   (1<<0)          /* Start Of Frame Mask for Overlay 1 (channel 1) */
++#define LCCR5_SOFM2   (1<<1)          /* Start Of Frame Mask for Overlay 2 (channel 2) */
++#define LCCR5_SOFM3   (1<<2)          /* Start Of Frame Mask for Overlay 2 (channel 3) */
++#define LCCR5_SOFM4   (1<<3)          /* Start Of Frame Mask for Overlay 2 (channel 4) */
++#define LCCR5_SOFM5   (1<<4)          /* Start Of Frame Mask for cursor (channel 5) */
++#define LCCR5_SOFM6   (1<<5)          /* Start Of Frame Mask for command data (channel 6) */
++
++#define LCCR5_EOFM1   (1<<8)          /* End Of Frame Mask for Overlay 1 (channel 1) */
++#define LCCR5_EOFM2   (1<<9)          /* End Of Frame Mask for Overlay 2 (channel 2) */
++#define LCCR5_EOFM3   (1<<10)         /* End Of Frame Mask for Overlay 2 (channel 3) */
++#define LCCR5_EOFM4   (1<<11)         /* End Of Frame Mask for Overlay 2 (channel 4) */
++#define LCCR5_EOFM5   (1<<12)         /* End Of Frame Mask for cursor (channel 5) */
++#define LCCR5_EOFM6   (1<<13)         /* End Of Frame Mask for command data (channel 6) */
++
++#define LCCR5_BSM1    (1<<16)         /* Branch mask for Overlay 1 (channel 1) */
++#define LCCR5_BSM2    (1<<17)         /* Branch mask for Overlay 2 (channel 2) */
++#define LCCR5_BSM3    (1<<18)         /* Branch mask for Overlay 2 (channel 3) */
++#define LCCR5_BSM4    (1<<19)         /* Branch mask for Overlay 2 (channel 4) */
++#define LCCR5_BSM5    (1<<20)         /* Branch mask for cursor (channel 5) */
++#define LCCR5_BSM6    (1<<21)         /* Branch mask for data command  (channel 6) */
++
++#define LCCR5_IUM1    (1<<24)         /* Input FIFO Underrun Mask for Overlay 1  */
++#define LCCR5_IUM2    (1<<25)         /* Input FIFO Underrun Mask for Overlay 2  */
++#define LCCR5_IUM3    (1<<26)         /* Input FIFO Underrun Mask for Overlay 2  */
++#define LCCR5_IUM4    (1<<27)         /* Input FIFO Underrun Mask for Overlay 2  */
++#define LCCR5_IUM5    (1<<28)         /* Input FIFO Underrun Mask for cursor */
++#define LCCR5_IUM6    (1<<29)         /* Input FIFO Underrun Mask for data command */
++
++#define OVL1C1_O1EN   (1<<31)         /* Enable bit for Overlay 1 */
++#define OVL2C1_O2EN   (1<<31)         /* Enable bit for Overlay 2 */
++#define CCR_CEN               (1<<31)         /* Enable bit for Cursor */
++
++/* LCD registers */
++#define LCCR4         __REG(0x44000010)  /* LCD Controller Control Register 4 */
++#define LCCR5         __REG(0x44000014)  /* LCD Controller Control Register 5 */
++#define FBR0          __REG(0x44000020)  /* DMA Channel 0 Frame Branch Register */
++#define FBR1          __REG(0x44000024)  /* DMA Channel 1 Frame Branch Register */
++#define FBR2          __REG(0x44000028)  /* DMA Channel 2 Frame Branch Register */
++#define FBR3          __REG(0x4400002C)  /* DMA Channel 3 Frame Branch Register */
++#define FBR4          __REG(0x44000030)  /* DMA Channel 4 Frame Branch Register */
++#define FDADR2                __REG(0x44000220)  /* DMA Channel 2 Frame Descriptor Address Register */
++#define FSADR2                __REG(0x44000224)  /* DMA Channel 2 Frame Source Address Register */
++#define FIDR2         __REG(0x44000228)  /* DMA Channel 2 Frame ID Register */
++#define LDCMD2                __REG(0x4400022C)  /* DMA Channel 2 Command Register */
++#define FDADR3                __REG(0x44000230)  /* DMA Channel 3 Frame Descriptor Address Register */
++#define FSADR3                __REG(0x44000234)  /* DMA Channel 3 Frame Source Address Register */
++#define FIDR3         __REG(0x44000238)  /* DMA Channel 3 Frame ID Register */
++#define LDCMD3                __REG(0x4400023C)  /* DMA Channel 3 Command Register */
++#define FDADR4                __REG(0x44000240)  /* DMA Channel 4 Frame Descriptor Address Register */
++#define FSADR4                __REG(0x44000244)  /* DMA Channel 4 Frame Source Address Register */
++#define FIDR4         __REG(0x44000248)  /* DMA Channel 4 Frame ID Register */
++#define LDCMD4                __REG(0x4400024C)  /* DMA Channel 4 Command Register */
++#define FDADR5                __REG(0x44000250)  /* DMA Channel 5 Frame Descriptor Address Register */
++#define FSADR5                __REG(0x44000254)  /* DMA Channel 5 Frame Source Address Register */
++#define FIDR5         __REG(0x44000258)  /* DMA Channel 5 Frame ID Register */
++#define LDCMD5                __REG(0x4400025C)  /* DMA Channel 5 Command Register */
++
++#define OVL1C1                __REG(0x44000050)  /* Overlay 1 Control Register 1 */
++#define OVL1C2                __REG(0x44000060)  /* Overlay 1 Control Register 2 */
++#define OVL2C1                __REG(0x44000070)  /* Overlay 2 Control Register 1 */
++#define OVL2C2                __REG(0x44000080)  /* Overlay 2 Control Register 2 */
++#define CCR           __REG(0x44000090)  /* Cursor Control Register */
++
++#define FBR5          __REG(0x44000110)  /* DMA Channel 5 Frame Branch Register */
++#define FBR6          __REG(0x44000114)  /* DMA Channel 6 Frame Branch Register */
++
+ /*
+  * Memory controller
+  */
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/squashfs3.2-2.6.20-r0.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc1/squashfs3.2-2.6.20-r0.patch
new file mode 100644 (file)
index 0000000..3870b31
--- /dev/null
@@ -0,0 +1,4376 @@
+--- linux-2.6.24-rc1.orig/fs/Kconfig
++++ linux-2.6.24-rc1/fs/Kconfig
+@@ -1405,6 +1405,71 @@
+         If unsure, say N.
++config SQUASHFS
++      tristate "SquashFS 3.2 - Squashed file system support"
++      select ZLIB_INFLATE
++      help
++        Saying Y here includes support for SquashFS 3.2 (a Compressed Read-Only File
++        System).  Squashfs is a highly compressed read-only filesystem for Linux.
++        It uses zlib compression to compress both files, inodes and directories.
++        Inodes in the system are very small and all blocks are packed to minimise
++        data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
++        SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full
++        uid/gid information, hard links and timestamps.
++
++        Squashfs is intended for general read-only filesystem use, for archival
++        use (i.e. in cases where a .tar.gz file may be used), and in embedded
++        systems where low overhead is needed.  Further information and filesystem tools
++        are available from http://squashfs.sourceforge.net.
++
++        If you want to compile this as a module ( = code which can be
++        inserted in and removed from the running kernel whenever you want),
++        say M here and read <file:Documentation/modules.txt>.  The module
++        will be called squashfs.  Note that the root file system (the one
++        containing the directory /) cannot be compiled as a module.
++
++        If unsure, say N.
++
++config SQUASHFS_EMBEDDED
++
++      bool "Additional options for memory-constrained systems" 
++      depends on SQUASHFS
++      default n
++      help
++        Saying Y here allows you to specify cache sizes and how Squashfs
++        allocates memory.  This is only intended for memory constrained
++        systems.
++
++        If unsure, say N.
++
++config SQUASHFS_FRAGMENT_CACHE_SIZE
++      int "Number of fragments cached" if SQUASHFS_EMBEDDED
++      depends on SQUASHFS
++      default "3"
++      help
++        By default SquashFS caches the last 3 fragments read from
++        the filesystem.  Increasing this amount may mean SquashFS
++        has to re-read fragments less often from disk, at the expense
++        of extra system memory.  Decreasing this amount will mean
++        SquashFS uses less memory at the expense of extra reads from disk.
++
++        Note there must be at least one cached fragment.  Anything
++        much more than three will probably not make much difference.
++
++config SQUASHFS_VMALLOC
++      bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
++      depends on SQUASHFS
++      default n
++      help
++        By default SquashFS uses kmalloc to obtain fragment cache memory.
++        Kmalloc memory is the standard kernel allocator, but it can fail
++        on memory constrained systems.  Because of the way Vmalloc works,
++        Vmalloc can succeed when kmalloc fails.  Specifying this option
++        will make SquashFS always use Vmalloc to allocate the
++        fragment cache memory.
++
++        If unsure, say N.
++
+ config VXFS_FS
+       tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+       depends on BLOCK
+--- linux-2.6.24-rc1.orig/fs/Makefile
++++ linux-2.6.24-rc1/fs/Makefile
+@@ -72,6 +72,7 @@
+ obj-$(CONFIG_JBD2)            += jbd2/
+ obj-$(CONFIG_EXT2_FS)         += ext2/
+ obj-$(CONFIG_CRAMFS)          += cramfs/
++obj-$(CONFIG_SQUASHFS)                += squashfs/
+ obj-y                         += ramfs/
+ obj-$(CONFIG_HUGETLBFS)               += hugetlbfs/
+ obj-$(CONFIG_CODA_FS)         += coda/
+--- /dev/null
++++ linux-2.6.24-rc1/fs/squashfs/inode.c
+@@ -0,0 +1,2329 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * inode.c
++ */
++
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/zlib.h>
++#include <linux/fs.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/vmalloc.h>
++#include <linux/smp_lock.h>
++
++#include "squashfs.h"
++
++static void vfs_read_inode(struct inode *i);
++static struct dentry *squashfs_get_parent(struct dentry *child);
++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
++static int squashfs_statfs(struct dentry *, struct kstatfs *);
++static int squashfs_symlink_readpage(struct file *file, struct page *page);
++static long long read_blocklist(struct inode *inode, int index,
++                              int readahead_blks, char *block_list,
++                              unsigned short **block_p, unsigned int *bsize);
++static int squashfs_readpage(struct file *file, struct page *page);
++static int squashfs_readpage4K(struct file *file, struct page *page);
++static int squashfs_readdir(struct file *, void *, filldir_t);
++static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
++                              struct nameidata *);
++static int squashfs_remount(struct super_block *s, int *flags, char *data);
++static void squashfs_put_super(struct super_block *);
++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
++                              struct vfsmount *);
++static struct inode *squashfs_alloc_inode(struct super_block *sb);
++static void squashfs_destroy_inode(struct inode *inode);
++static int init_inodecache(void);
++static void destroy_inodecache(void);
++
++static struct file_system_type squashfs_fs_type = {
++      .owner = THIS_MODULE,
++      .name = "squashfs",
++      .get_sb = squashfs_get_sb,
++      .kill_sb = kill_block_super,
++      .fs_flags = FS_REQUIRES_DEV
++};
++
++static const unsigned char squashfs_filetype_table[] = {
++      DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static struct super_operations squashfs_super_ops = {
++      .alloc_inode = squashfs_alloc_inode,
++      .destroy_inode = squashfs_destroy_inode,
++      .statfs = squashfs_statfs,
++      .put_super = squashfs_put_super,
++      .remount_fs = squashfs_remount
++};
++
++static struct super_operations squashfs_export_super_ops = {
++      .alloc_inode = squashfs_alloc_inode,
++      .destroy_inode = squashfs_destroy_inode,
++      .statfs = squashfs_statfs,
++      .put_super = squashfs_put_super,
++      .read_inode = vfs_read_inode
++};
++
++static struct export_operations squashfs_export_ops = {
++      .get_parent = squashfs_get_parent
++};
++
++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
++      .readpage = squashfs_symlink_readpage
++};
++
++SQSH_EXTERN const struct address_space_operations squashfs_aops = {
++      .readpage = squashfs_readpage
++};
++
++SQSH_EXTERN const struct address_space_operations squashfs_aops_4K = {
++      .readpage = squashfs_readpage4K
++};
++
++static const struct file_operations squashfs_dir_ops = {
++      .read = generic_read_dir,
++      .readdir = squashfs_readdir
++};
++
++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
++      .lookup = squashfs_lookup
++};
++
++
++static struct buffer_head *get_block_length(struct super_block *s,
++                              int *cur_index, int *offset, int *c_byte)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      unsigned short temp;
++      struct buffer_head *bh;
++
++      if (!(bh = sb_bread(s, *cur_index)))
++              goto out;
++
++      if (msblk->devblksize - *offset == 1) {
++              if (msblk->swap)
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset));
++              else
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset));
++              brelse(bh);
++              if (!(bh = sb_bread(s, ++(*cur_index))))
++                      goto out;
++              if (msblk->swap)
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              bh->b_data); 
++              else
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              bh->b_data); 
++              *c_byte = temp;
++              *offset = 1;
++      } else {
++              if (msblk->swap) {
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset));
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset + 1)); 
++              } else {
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset));
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset + 1)); 
++              }
++              *c_byte = temp;
++              *offset += 2;
++      }
++
++      if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
++              if (*offset == msblk->devblksize) {
++                      brelse(bh);
++                      if (!(bh = sb_bread(s, ++(*cur_index))))
++                              goto out;
++                      *offset = 0;
++              }
++              if (*((unsigned char *) (bh->b_data + *offset)) !=
++                                              SQUASHFS_MARKER_BYTE) {
++                      ERROR("Metadata block marker corrupt @ %x\n",
++                                              *cur_index);
++                      brelse(bh);
++                      goto out;
++              }
++              (*offset)++;
++      }
++      return bh;
++
++out:
++      return NULL;
++}
++
++
++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++                      long long index, unsigned int length,
++                      long long *next_index, int srclength)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
++                      msblk->devblksize_log2) + 2];
++      unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
++      unsigned int cur_index = index >> msblk->devblksize_log2;
++      int bytes, avail_bytes, b = 0, k = 0;
++      unsigned int compressed;
++      unsigned int c_byte = length;
++
++      if (c_byte) {
++              bytes = msblk->devblksize - offset;
++              compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
++              c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
++
++              TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed
++                                      ? "" : "un", (unsigned int) c_byte, srclength);
++
++              if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
++                      goto read_failure;
++
++              if (!(bh[0] = sb_getblk(s, cur_index)))
++                      goto block_release;
++
++              for (b = 1; bytes < c_byte; b++) {
++                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                              goto block_release;
++                      bytes += msblk->devblksize;
++              }
++              ll_rw_block(READ, b, bh);
++      } else {
++              if (index < 0 || (index + 2) > sblk->bytes_used)
++                      goto read_failure;
++
++              if (!(bh[0] = get_block_length(s, &cur_index, &offset,
++                                                              &c_byte)))
++                      goto read_failure;
++
++              bytes = msblk->devblksize - offset;
++              compressed = SQUASHFS_COMPRESSED(c_byte);
++              c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
++
++              TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++                                      ? "" : "un", (unsigned int) c_byte);
++
++              if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
++                      goto read_failure;
++
++              for (b = 1; bytes < c_byte; b++) {
++                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                              goto block_release;
++                      bytes += msblk->devblksize;
++              }
++              ll_rw_block(READ, b - 1, bh + 1);
++      }
++
++      if (compressed) {
++              int zlib_err = 0;
++
++              /*
++              * uncompress block
++              */
++
++              mutex_lock(&msblk->read_data_mutex);
++
++              msblk->stream.next_out = buffer;
++              msblk->stream.avail_out = srclength;
++
++              for (bytes = 0; k < b; k++) {
++                      avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
++                                      msblk->devblksize - offset :
++                                      c_byte - bytes;
++                      wait_on_buffer(bh[k]);
++                      if (!buffer_uptodate(bh[k]))
++                              goto release_mutex;
++
++                      msblk->stream.next_in = bh[k]->b_data + offset;
++                      msblk->stream.avail_in = avail_bytes;
++
++                      if (k == 0) {
++                              zlib_err = zlib_inflateInit(&msblk->stream);
++                              if (zlib_err != Z_OK) {
++                                      ERROR("zlib_inflateInit returned unexpected result 0x%x, srclength %d\n",
++                                              zlib_err, srclength);
++                                      goto release_mutex;
++                              }
++
++                              if (avail_bytes == 0) {
++                                      offset = 0;
++                                      brelse(bh[k]);
++                                      continue;
++                              }
++                      }
++
++                      zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
++                      if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
++                              ERROR("zlib_inflate returned unexpected result 0x%x, srclength %d, avail_in %d, avail_out %d\n",
++                                      zlib_err, srclength, msblk->stream.avail_in, msblk->stream.avail_out);
++                              goto release_mutex;
++                      }
++
++                      bytes += avail_bytes;
++                      offset = 0;
++                      brelse(bh[k]);
++              }
++
++              if (zlib_err != Z_STREAM_END)
++                      goto release_mutex;
++
++              zlib_err = zlib_inflateEnd(&msblk->stream);
++              if (zlib_err != Z_OK) {
++                      ERROR("zlib_inflateEnd returned unexpected result 0x%x, srclength %d\n",
++                              zlib_err, srclength);
++                      goto release_mutex;
++              }
++              bytes = msblk->stream.total_out;
++              mutex_unlock(&msblk->read_data_mutex);
++      } else {
++              int i;
++
++              for(i = 0; i < b; i++) {
++                      wait_on_buffer(bh[i]);
++                      if(!buffer_uptodate(bh[i]))
++                              goto block_release;
++              }
++
++              for (bytes = 0; k < b; k++) {
++                      avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
++                                      msblk->devblksize - offset :
++                                      c_byte - bytes;
++                      memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
++                      bytes += avail_bytes;
++                      offset = 0;
++                      brelse(bh[k]);
++              }
++      }
++
++      if (next_index)
++              *next_index = index + c_byte + (length ? 0 :
++                              (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
++                               ? 3 : 2));
++      return bytes;
++
++release_mutex:
++      mutex_unlock(&msblk->read_data_mutex);
++
++block_release:
++      for (; k < b; k++)
++              brelse(bh[k]);
++
++read_failure:
++      ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++      return 0;
++}
++
++
++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
++                              long long block, unsigned int offset,
++                              int length, long long *next_block,
++                              unsigned int *next_offset)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      int n, i, bytes, return_length = length;
++      long long next_index;
++
++      TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
++
++      while ( 1 ) {
++              for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 
++                      if (msblk->block_cache[i].block == block)
++                              break; 
++              
++              mutex_lock(&msblk->block_cache_mutex);
++
++              if (i == SQUASHFS_CACHED_BLKS) {
++                      /* read inode header block */
++                      for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
++                                      n ; n --, i = (i + 1) %
++                                      SQUASHFS_CACHED_BLKS)
++                              if (msblk->block_cache[i].block !=
++                                                      SQUASHFS_USED_BLK)
++                                      break;
++
++                      if (n == 0) {
++                              wait_queue_t wait;
++
++                              init_waitqueue_entry(&wait, current);
++                              add_wait_queue(&msblk->waitq, &wait);
++                              set_current_state(TASK_UNINTERRUPTIBLE);
++                              mutex_unlock(&msblk->block_cache_mutex);
++                              schedule();
++                              set_current_state(TASK_RUNNING);
++                              remove_wait_queue(&msblk->waitq, &wait);
++                              continue;
++                      }
++                      msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
++
++                      if (msblk->block_cache[i].block ==
++                                                      SQUASHFS_INVALID_BLK) {
++                              if (!(msblk->block_cache[i].data =
++                                              kmalloc(SQUASHFS_METADATA_SIZE,
++                                              GFP_KERNEL))) {
++                                      ERROR("Failed to allocate cache"
++                                                      "block\n");
++                                      mutex_unlock(&msblk->block_cache_mutex);
++                                      goto out;
++                              }
++                      }
++      
++                      msblk->block_cache[i].block = SQUASHFS_USED_BLK;
++                      mutex_unlock(&msblk->block_cache_mutex);
++
++                      msblk->block_cache[i].length = squashfs_read_data(s,
++                              msblk->block_cache[i].data, block, 0, &next_index, SQUASHFS_METADATA_SIZE);
++                      if (msblk->block_cache[i].length == 0) {
++                              ERROR("Unable to read cache block [%llx:%x]\n",
++                                              block, offset);
++                              mutex_lock(&msblk->block_cache_mutex);
++                              msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++                              kfree(msblk->block_cache[i].data);
++                              wake_up(&msblk->waitq);
++                              mutex_unlock(&msblk->block_cache_mutex);
++                              goto out;
++                      }
++
++                      mutex_lock(&msblk->block_cache_mutex);
++                      wake_up(&msblk->waitq);
++                      msblk->block_cache[i].block = block;
++                      msblk->block_cache[i].next_index = next_index;
++                      TRACE("Read cache block [%llx:%x]\n", block, offset);
++              }
++
++              if (msblk->block_cache[i].block != block) {
++                      mutex_unlock(&msblk->block_cache_mutex);
++                      continue;
++              }
++
++              bytes = msblk->block_cache[i].length - offset;
++
++              if (bytes < 1) {
++                      mutex_unlock(&msblk->block_cache_mutex);
++                      goto out;
++              } else if (bytes >= length) {
++                      if (buffer)
++                              memcpy(buffer, msblk->block_cache[i].data +
++                                              offset, length);
++                      if (msblk->block_cache[i].length - offset == length) {
++                              *next_block = msblk->block_cache[i].next_index;
++                              *next_offset = 0;
++                      } else {
++                              *next_block = block;
++                              *next_offset = offset + length;
++                      }
++                      mutex_unlock(&msblk->block_cache_mutex);
++                      goto finish;
++              } else {
++                      if (buffer) {
++                              memcpy(buffer, msblk->block_cache[i].data +
++                                              offset, bytes);
++                              buffer += bytes;
++                      }
++                      block = msblk->block_cache[i].next_index;
++                      mutex_unlock(&msblk->block_cache_mutex);
++                      length -= bytes;
++                      offset = 0;
++              }
++      }
++
++finish:
++      return return_length;
++out:
++      return 0;
++}
++
++
++static int get_fragment_location(struct super_block *s, unsigned int fragment,
++                              long long *fragment_start_block,
++                              unsigned int *fragment_size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      long long start_block =
++              msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
++      int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
++      struct squashfs_fragment_entry fragment_entry;
++
++      if (msblk->swap) {
++              struct squashfs_fragment_entry sfragment_entry;
++
++              if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++                                      start_block, offset,
++                                      sizeof(sfragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++              SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
++      } else
++              if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++                                      start_block, offset,
++                                      sizeof(fragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++
++      *fragment_start_block = fragment_entry.start_block;
++      *fragment_size = fragment_entry.size;
++
++      return 1;
++
++out:
++      return 0;
++}
++
++
++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++                                      squashfs_fragment_cache *fragment)
++{
++      mutex_lock(&msblk->fragment_mutex);
++      fragment->locked --;
++      wake_up(&msblk->fragment_wait_queue);
++      mutex_unlock(&msblk->fragment_mutex);
++}
++
++
++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++                                      *s, long long start_block,
++                                      int length)
++{
++      int i, n;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      while ( 1 ) {
++              mutex_lock(&msblk->fragment_mutex);
++
++              for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
++                              msblk->fragment[i].block != start_block; i++);
++
++              if (i == SQUASHFS_CACHED_FRAGMENTS) {
++                      for (i = msblk->next_fragment, n =
++                              SQUASHFS_CACHED_FRAGMENTS; n &&
++                              msblk->fragment[i].locked; n--, i = (i + 1) %
++                              SQUASHFS_CACHED_FRAGMENTS);
++
++                      if (n == 0) {
++                              wait_queue_t wait;
++
++                              init_waitqueue_entry(&wait, current);
++                              add_wait_queue(&msblk->fragment_wait_queue,
++                                                                      &wait);
++                              set_current_state(TASK_UNINTERRUPTIBLE);
++                              mutex_unlock(&msblk->fragment_mutex);
++                              schedule();
++                              set_current_state(TASK_RUNNING);
++                              remove_wait_queue(&msblk->fragment_wait_queue,
++                                                                      &wait);
++                              continue;
++                      }
++                      msblk->next_fragment = (msblk->next_fragment + 1) %
++                              SQUASHFS_CACHED_FRAGMENTS;
++                      
++                      if (msblk->fragment[i].data == NULL)
++                              if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
++                                              (SQUASHFS_FILE_MAX_SIZE))) {
++                                      ERROR("Failed to allocate fragment "
++                                                      "cache block\n");
++                                      mutex_unlock(&msblk->fragment_mutex);
++                                      goto out;
++                              }
++
++                      msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++                      msblk->fragment[i].locked = 1;
++                      mutex_unlock(&msblk->fragment_mutex);
++
++                      if (!(msblk->fragment[i].length = squashfs_read_data(s,
++                                              msblk->fragment[i].data,
++                                              start_block, length, NULL, sblk->block_size))) {
++                              ERROR("Unable to read fragment cache block "
++                                                      "[%llx]\n", start_block);
++                              msblk->fragment[i].locked = 0;
++                              smp_mb();
++                              goto out;
++                      }
++
++                      mutex_lock(&msblk->fragment_mutex);
++                      msblk->fragment[i].block = start_block;
++                      TRACE("New fragment %d, start block %lld, locked %d\n",
++                                              i, msblk->fragment[i].block,
++                                              msblk->fragment[i].locked);
++                      mutex_unlock(&msblk->fragment_mutex);
++                      break;
++              }
++
++              msblk->fragment[i].locked++;
++              mutex_unlock(&msblk->fragment_mutex);
++              TRACE("Got fragment %d, start block %lld, locked %d\n", i,
++                                              msblk->fragment[i].block,
++                                              msblk->fragment[i].locked);
++              break;
++      }
++
++      return &msblk->fragment[i];
++
++out:
++      return NULL;
++}
++
++
++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
++              struct squashfs_base_inode_header *inodeb)
++{
++      i->i_ino = inodeb->inode_number;
++      i->i_mtime.tv_sec = inodeb->mtime;
++      i->i_atime.tv_sec = inodeb->mtime;
++      i->i_ctime.tv_sec = inodeb->mtime;
++      i->i_uid = msblk->uid[inodeb->uid];
++      i->i_mode = inodeb->mode;
++      i->i_size = 0;
++      if (inodeb->guid == SQUASHFS_GUIDS)
++              i->i_gid = i->i_uid;
++      else
++              i->i_gid = msblk->guid[inodeb->guid];
++}
++
++
++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
++      int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
++      squashfs_inode_t inode;
++
++      TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
++
++      if (msblk->swap) {
++              squashfs_inode_t sinode;
++
++              if (!squashfs_get_cached_block(s, (char *) &sinode, start, offset,
++                                      sizeof(sinode), &start, &offset))
++                      goto out;
++              SQUASHFS_SWAP_INODE_T((&inode), &sinode);
++      } else if (!squashfs_get_cached_block(s, (char *) &inode, start, offset,
++                                      sizeof(inode), &start, &offset))
++                      goto out;
++
++      TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
++
++      return inode;
++
++out:
++      return SQUASHFS_INVALID_BLK;
++}
++      
++
++static void vfs_read_inode(struct inode *i)
++{
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino);
++
++      TRACE("Entered vfs_read_inode\n");
++
++      if(inode != SQUASHFS_INVALID_BLK)
++              (msblk->read_inode)(i, inode);
++}
++
++
++static struct dentry *squashfs_get_parent(struct dentry *child)
++{
++      struct inode *i = child->d_inode;
++      struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);
++      struct dentry *rv;
++
++      TRACE("Entered squashfs_get_parent\n");
++
++      if(parent == NULL) {
++              rv = ERR_PTR(-EACCES);
++              goto out;
++      }
++
++      rv = d_alloc_anon(parent);
++      if(rv == NULL)
++              rv = ERR_PTR(-ENOMEM);
++
++out:
++      return rv;
++}
++
++      
++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct inode *i = iget_locked(s, inode_number);
++
++      TRACE("Entered squashfs_iget\n");
++
++      if(i && (i->i_state & I_NEW)) {
++              (msblk->read_inode)(i, inode);
++              unlock_new_inode(i);
++      }
++
++      return i;
++}
++
++
++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
++{
++      struct super_block *s = i->i_sb;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long block = SQUASHFS_INODE_BLK(inode) +
++              sblk->inode_table_start;
++      unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++      long long next_block;
++      unsigned int next_offset;
++      union squashfs_inode_header id, sid;
++      struct squashfs_base_inode_header *inodeb = &id.base,
++                                        *sinodeb = &sid.base;
++
++      TRACE("Entered squashfs_read_inode\n");
++
++      if (msblk->swap) {
++              if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++                                      offset, sizeof(*sinodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++              SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
++                                      sizeof(*sinodeb));
++      } else
++              if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++                                      offset, sizeof(*inodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++
++      squashfs_new_inode(msblk, i, inodeb);
++
++      switch(inodeb->inode_type) {
++              case SQUASHFS_FILE_TYPE: {
++                      unsigned int frag_size;
++                      long long frag_blk;
++                      struct squashfs_reg_inode_header *inodep = &id.reg;
++                      struct squashfs_reg_inode_header *sinodep = &sid.reg;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      i->i_nlink = 1;
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %llx, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_LREG_TYPE: {
++                      unsigned int frag_size;
++                      long long frag_blk;
++                      struct squashfs_lreg_inode_header *inodep = &id.lreg;
++                      struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %llx, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_DIR_TYPE: {
++                      struct squashfs_dir_inode_header *inodep = &id.dir;
++                      struct squashfs_dir_inode_header *sinodep = &sid.dir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops;
++                      i->i_fop = &squashfs_dir_ops;
++                      i->i_mode |= S_IFDIR;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++                      SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++                      TRACE("Directory inode %x:%x, start_block %x, offset "
++                                      "%x\n", SQUASHFS_INODE_BLK(inode),
++                                      offset, inodep->start_block,
++                                      inodep->offset);
++                      break;
++              }
++              case SQUASHFS_LDIR_TYPE: {
++                      struct squashfs_ldir_inode_header *inodep = &id.ldir;
++                      struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
++                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops;
++                      i->i_fop = &squashfs_dir_ops;
++                      i->i_mode |= S_IFDIR;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++                      SQUASHFS_I(i)->u.s2.directory_index_offset =
++                                                              next_offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count =
++                                                              inodep->i_count;
++                      SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++                      TRACE("Long directory inode %x:%x, start_block %x, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, inodep->offset);
++                      break;
++              }
++              case SQUASHFS_SYMLINK_TYPE: {
++                      struct squashfs_symlink_inode_header *inodep =
++                                                              &id.symlink;
++                      struct squashfs_symlink_inode_header *sinodep =
++                                                              &sid.symlink;
++      
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
++                                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->symlink_size;
++                      i->i_op = &page_symlink_inode_operations;
++                      i->i_data.a_ops = &squashfs_symlink_aops;
++                      i->i_mode |= S_IFLNK;
++                      SQUASHFS_I(i)->start_block = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++
++                      TRACE("Symbolic link inode %x:%x, start_block %llx, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      next_block, next_offset);
++                      break;
++               }
++               case SQUASHFS_BLKDEV_TYPE:
++               case SQUASHFS_CHRDEV_TYPE: {
++                      struct squashfs_dev_inode_header *inodep = &id.dev;
++                      struct squashfs_dev_inode_header *sinodep = &sid.dev;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_mode |= (inodeb->inode_type ==
++                                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
++                                      S_IFBLK;
++                      init_special_inode(i, i->i_mode,
++                                      old_decode_dev(inodep->rdev));
++
++                      TRACE("Device inode %x:%x, rdev %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->rdev);
++                      break;
++               }
++               case SQUASHFS_FIFO_TYPE:
++               case SQUASHFS_SOCKET_TYPE: {
++                      struct squashfs_ipc_inode_header *inodep = &id.ipc;
++                      struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++                                                      ? S_IFIFO : S_IFSOCK;
++                      init_special_inode(i, i->i_mode, 0);
++                      break;
++               }
++               default:
++                      ERROR("Unknown inode type %d in squashfs_iget!\n",
++                                      inodeb->inode_type);
++                      goto failed_read1;
++      }
++      
++      return 1;
++
++failed_read:
++      ERROR("Unable to read inode [%llx:%x]\n", block, offset);
++
++failed_read1:
++      make_bad_inode(i);
++      return 0;
++}
++
++
++static int read_inode_lookup_table(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
++
++      TRACE("In read_inode_lookup_table, length %d\n", length);
++
++      /* Allocate inode lookup table */
++      if (!(msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL))) {
++              ERROR("Failed to allocate inode lookup table\n");
++              return 0;
++      }
++   
++      if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
++                      sblk->lookup_table_start, length |
++                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
++              ERROR("unable to read inode lookup table\n");
++              return 0;
++      }
++
++      if (msblk->swap) {
++              int i;
++              long long block;
++
++              for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
++                      SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
++                                              &msblk->inode_lookup_table[i], 1);
++                      msblk->inode_lookup_table[i] = block;
++              }
++      }
++
++      return 1;
++}
++
++
++static int read_fragment_index_table(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
++
++      if(length == 0)
++              return 1;
++
++      /* Allocate fragment index table */
++      if (!(msblk->fragment_index = kmalloc(length, GFP_KERNEL))) {
++              ERROR("Failed to allocate fragment index table\n");
++              return 0;
++      }
++   
++      if (!squashfs_read_data(s, (char *) msblk->fragment_index,
++                      sblk->fragment_table_start, length |
++                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
++              ERROR("unable to read fragment index table\n");
++              return 0;
++      }
++
++      if (msblk->swap) {
++              int i;
++              long long fragment;
++
++              for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
++                      SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
++                                              &msblk->fragment_index[i], 1);
++                      msblk->fragment_index[i] = fragment;
++              }
++      }
++
++      return 1;
++}
++
++
++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
++{
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      msblk->read_inode = squashfs_read_inode;
++      msblk->read_blocklist = read_blocklist;
++      msblk->read_fragment_index_table = read_fragment_index_table;
++
++      if (sblk->s_major == 1) {
++              if (!squashfs_1_0_supported(msblk)) {
++                      SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
++                              "are unsupported\n");
++                      SERROR("Please recompile with "
++                              "Squashfs 1.0 support enabled\n");
++                      return 0;
++              }
++      } else if (sblk->s_major == 2) {
++              if (!squashfs_2_0_supported(msblk)) {
++                      SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
++                              "are unsupported\n");
++                      SERROR("Please recompile with "
++                              "Squashfs 2.0 support enabled\n");
++                      return 0;
++              }
++      } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
++                      SQUASHFS_MINOR) {
++              SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
++                              "filesystem\n", sblk->s_major, sblk->s_minor);
++              SERROR("Please update your kernel\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++
++static int squashfs_fill_super(struct super_block *s, void *data, int silent)
++{
++      struct squashfs_sb_info *msblk;
++      struct squashfs_super_block *sblk;
++      int i;
++      char b[BDEVNAME_SIZE];
++      struct inode *root;
++
++      TRACE("Entered squashfs_read_superblock\n");
++
++      if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
++                                              GFP_KERNEL))) {
++              ERROR("Failed to allocate superblock\n");
++              goto failure;
++      }
++      memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
++      msblk = s->s_fs_info;
++      if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
++              ERROR("Failed to allocate zlib workspace\n");
++              goto failure;
++      }
++      sblk = &msblk->sblk;
++      
++      msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
++      msblk->devblksize_log2 = ffz(~msblk->devblksize);
++
++      mutex_init(&msblk->read_data_mutex);
++      mutex_init(&msblk->read_page_mutex);
++      mutex_init(&msblk->block_cache_mutex);
++      mutex_init(&msblk->fragment_mutex);
++      mutex_init(&msblk->meta_index_mutex);
++      
++      init_waitqueue_head(&msblk->waitq);
++      init_waitqueue_head(&msblk->fragment_wait_queue);
++
++      sblk->bytes_used = sizeof(struct squashfs_super_block);
++      if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
++                                      sizeof(struct squashfs_super_block) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
++              SERROR("unable to read superblock\n");
++              goto failed_mount;
++      }
++
++      /* Check it is a SQUASHFS superblock */
++      msblk->swap = 0;
++      if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
++              if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
++                      struct squashfs_super_block ssblk;
++
++                      WARNING("Mounting a different endian SQUASHFS "
++                              "filesystem on %s\n", bdevname(s->s_bdev, b));
++
++                      SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
++                      memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
++                      msblk->swap = 1;
++              } else  {
++                      SERROR("Can't find a SQUASHFS superblock on %s\n",
++                                                      bdevname(s->s_bdev, b));
++                      goto failed_mount;
++              }
++      }
++
++      /* Check the MAJOR & MINOR versions */
++      if(!supported_squashfs_filesystem(msblk, silent))
++              goto failed_mount;
++
++      /* Check the filesystem does not extend beyond the end of the
++         block device */
++      if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
++              goto failed_mount;
++
++      /* Check the root inode for sanity */
++      if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
++              goto failed_mount;
++
++      TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
++      TRACE("Inodes are %scompressed\n",
++                                      SQUASHFS_UNCOMPRESSED_INODES
++                                      (sblk->flags) ? "un" : "");
++      TRACE("Data is %scompressed\n",
++                                      SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
++                                      ? "un" : "");
++      TRACE("Check data is %s present in the filesystem\n",
++                                      SQUASHFS_CHECK_DATA(sblk->flags) ?
++                                      "" : "not");
++      TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
++      TRACE("Block size %d\n", sblk->block_size);
++      TRACE("Number of inodes %d\n", sblk->inodes);
++      if (sblk->s_major > 1)
++              TRACE("Number of fragments %d\n", sblk->fragments);
++      TRACE("Number of uids %d\n", sblk->no_uids);
++      TRACE("Number of gids %d\n", sblk->no_guids);
++      TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
++      TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
++      if (sblk->s_major > 1)
++              TRACE("sblk->fragment_table_start %llx\n",
++                                      sblk->fragment_table_start);
++      TRACE("sblk->uid_start %llx\n", sblk->uid_start);
++
++      s->s_flags |= MS_RDONLY;
++      s->s_op = &squashfs_super_ops;
++
++      /* Init inode_table block pointer array */
++      if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
++                                      SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
++              ERROR("Failed to allocate block cache\n");
++              goto failed_mount;
++      }
++
++      for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++              msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++      msblk->next_cache = 0;
++
++      /* Allocate read_page block */
++      if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
++              ERROR("Failed to allocate read_page block\n");
++              goto failed_mount;
++      }
++
++      /* Allocate uid and gid tables */
++      if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
++                                      sizeof(unsigned int), GFP_KERNEL))) {
++              ERROR("Failed to allocate uid/gid table\n");
++              goto failed_mount;
++      }
++      msblk->guid = msblk->uid + sblk->no_uids;
++   
++      if (msblk->swap) {
++              unsigned int suid[sblk->no_uids + sblk->no_guids];
++
++              if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
++                                      ((sblk->no_uids + sblk->no_guids) *
++                                       sizeof(unsigned int)) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
++                      ERROR("unable to read uid/gid table\n");
++                      goto failed_mount;
++              }
++
++              SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
++                      sblk->no_guids), (sizeof(unsigned int) * 8));
++      } else
++              if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
++                                      ((sblk->no_uids + sblk->no_guids) *
++                                       sizeof(unsigned int)) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
++                      ERROR("unable to read uid/gid table\n");
++                      goto failed_mount;
++              }
++
++
++      if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
++              goto allocate_root;
++
++      if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
++                              SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
++              ERROR("Failed to allocate fragment block cache\n");
++              goto failed_mount;
++      }
++
++      for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
++              msblk->fragment[i].locked = 0;
++              msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++              msblk->fragment[i].data = NULL;
++      }
++
++      msblk->next_fragment = 0;
++
++      /* Allocate and read fragment index table */
++      if (msblk->read_fragment_index_table(s) == 0)
++              goto failed_mount;
++
++      if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
++              goto allocate_root;
++
++      /* Allocate and read inode lookup table */
++      if (read_inode_lookup_table(s) == 0)
++              goto failed_mount;
++
++      s->s_op = &squashfs_export_super_ops;
++      s->s_export_op = &squashfs_export_ops;
++
++allocate_root:
++      root = new_inode(s);
++      if ((msblk->read_inode)(root, sblk->root_inode) == 0)
++              goto failed_mount;
++      insert_inode_hash(root);
++
++      if ((s->s_root = d_alloc_root(root)) == NULL) {
++              ERROR("Root inode create failed\n");
++              iput(root);
++              goto failed_mount;
++      }
++
++      TRACE("Leaving squashfs_read_super\n");
++      return 0;
++
++failed_mount:
++      kfree(msblk->inode_lookup_table);
++      kfree(msblk->fragment_index);
++      kfree(msblk->fragment);
++      kfree(msblk->uid);
++      kfree(msblk->read_page);
++      kfree(msblk->block_cache);
++      kfree(msblk->fragment_index_2);
++      vfree(msblk->stream.workspace);
++      kfree(s->s_fs_info);
++      s->s_fs_info = NULL;
++      return -EINVAL;
++
++failure:
++      return -ENOMEM;
++}
++
++
++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++      struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      TRACE("Entered squashfs_statfs\n");
++
++      buf->f_type = SQUASHFS_MAGIC;
++      buf->f_bsize = sblk->block_size;
++      buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
++      buf->f_bfree = buf->f_bavail = 0;
++      buf->f_files = sblk->inodes;
++      buf->f_ffree = 0;
++      buf->f_namelen = SQUASHFS_NAME_LEN;
++
++      return 0;
++}
++
++
++static int squashfs_symlink_readpage(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
++      long long block = SQUASHFS_I(inode)->start_block;
++      int offset = SQUASHFS_I(inode)->offset;
++      void *pageaddr = kmap(page);
++
++      TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
++                              "%llx, offset %x\n", page->index,
++                              SQUASHFS_I(inode)->start_block,
++                              SQUASHFS_I(inode)->offset);
++
++      for (length = 0; length < index; length += bytes) {
++              if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
++                              block, offset, PAGE_CACHE_SIZE, &block,
++                              &offset))) {
++                      ERROR("Unable to read symbolic link [%llx:%x]\n", block,
++                                      offset);
++                      goto skip_read;
++              }
++      }
++
++      if (length != index) {
++              ERROR("(squashfs_symlink_readpage) length != index\n");
++              bytes = 0;
++              goto skip_read;
++      }
++
++      bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
++                                      i_size_read(inode) - length;
++
++      if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
++                                      offset, bytes, &block, &offset)))
++              ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
++
++skip_read:
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap(page);
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      return 0;
++}
++
++
++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
++{
++      struct meta_index *meta = NULL;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      int i;
++
++      mutex_lock(&msblk->meta_index_mutex);
++
++      TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
++
++      if(msblk->meta_index == NULL)
++              goto not_allocated;
++
++      for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
++              if (msblk->meta_index[i].inode_number == inode->i_ino &&
++                              msblk->meta_index[i].offset >= offset &&
++                              msblk->meta_index[i].offset <= index &&
++                              msblk->meta_index[i].locked == 0) {
++                      TRACE("locate_meta_index: entry %d, offset %d\n", i,
++                                      msblk->meta_index[i].offset);
++                      meta = &msblk->meta_index[i];
++                      offset = meta->offset;
++              }
++
++      if (meta)
++              meta->locked = 1;
++
++not_allocated:
++      mutex_unlock(&msblk->meta_index_mutex);
++
++      return meta;
++}
++
++
++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
++{
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct meta_index *meta = NULL;
++      int i;
++
++      mutex_lock(&msblk->meta_index_mutex);
++
++      TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
++
++      if(msblk->meta_index == NULL) {
++              if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
++                                      SQUASHFS_META_NUMBER, GFP_KERNEL))) {
++                      ERROR("Failed to allocate meta_index\n");
++                      goto failed;
++              }
++              for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
++                      msblk->meta_index[i].inode_number = 0;
++                      msblk->meta_index[i].locked = 0;
++              }
++              msblk->next_meta_index = 0;
++      }
++
++      for(i = SQUASHFS_META_NUMBER; i &&
++                      msblk->meta_index[msblk->next_meta_index].locked; i --)
++              msblk->next_meta_index = (msblk->next_meta_index + 1) %
++                      SQUASHFS_META_NUMBER;
++
++      if(i == 0) {
++              TRACE("empty_meta_index: failed!\n");
++              goto failed;
++      }
++
++      TRACE("empty_meta_index: returned meta entry %d, %p\n",
++                      msblk->next_meta_index,
++                      &msblk->meta_index[msblk->next_meta_index]);
++
++      meta = &msblk->meta_index[msblk->next_meta_index];
++      msblk->next_meta_index = (msblk->next_meta_index + 1) %
++                      SQUASHFS_META_NUMBER;
++
++      meta->inode_number = inode->i_ino;
++      meta->offset = offset;
++      meta->skip = skip;
++      meta->entries = 0;
++      meta->locked = 1;
++
++failed:
++      mutex_unlock(&msblk->meta_index_mutex);
++      return meta;
++}
++
++
++void release_meta_index(struct inode *inode, struct meta_index *meta)
++{
++      meta->locked = 0;
++      smp_mb();
++}
++
++
++static int read_block_index(struct super_block *s, int blocks, char *block_list,
++              long long *start_block, int *offset)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      unsigned int *block_listp;
++      int block = 0;
++      
++      if (msblk->swap) {
++              char sblock_list[blocks << 2];
++
++              if (!squashfs_get_cached_block(s, sblock_list, *start_block,
++                              *offset, blocks << 2, start_block, offset)) {
++                      ERROR("Unable to read block list [%llx:%x]\n",
++                              *start_block, *offset);
++                      goto failure;
++              }
++              SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
++                              ((unsigned int *)sblock_list), blocks);
++      } else
++              if (!squashfs_get_cached_block(s, block_list, *start_block,
++                              *offset, blocks << 2, start_block, offset)) {
++                      ERROR("Unable to read block list [%llx:%x]\n",
++                              *start_block, *offset);
++                      goto failure;
++              }
++
++      for (block_listp = (unsigned int *) block_list; blocks;
++                              block_listp++, blocks --)
++              block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
++
++      return block;
++
++failure:
++      return -1;
++}
++
++
++#define SIZE 256
++
++static inline int calculate_skip(int blocks) {
++      int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
++      return skip >= 7 ? 7 : skip + 1;
++}
++
++
++static int get_meta_index(struct inode *inode, int index,
++              long long *index_block, int *index_offset,
++              long long *data_block, char *block_list)
++{
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
++      int offset = 0;
++      struct meta_index *meta;
++      struct meta_entry *meta_entry;
++      long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
++      int cur_offset = SQUASHFS_I(inode)->offset;
++      long long cur_data_block = SQUASHFS_I(inode)->start_block;
++      int i;
++ 
++      index /= SQUASHFS_META_INDEXES * skip;
++
++      while ( offset < index ) {
++              meta = locate_meta_index(inode, index, offset + 1);
++
++              if (meta == NULL) {
++                      if ((meta = empty_meta_index(inode, offset + 1,
++                                                      skip)) == NULL)
++                              goto all_done;
++              } else {
++                      if(meta->entries == 0)
++                              goto failed;
++                      offset = index < meta->offset + meta->entries ? index :
++                              meta->offset + meta->entries - 1;
++                      meta_entry = &meta->meta_entry[offset - meta->offset];
++                      cur_index_block = meta_entry->index_block + sblk->inode_table_start;
++                      cur_offset = meta_entry->offset;
++                      cur_data_block = meta_entry->data_block;
++                      TRACE("get_meta_index: offset %d, meta->offset %d, "
++                              "meta->entries %d\n", offset, meta->offset,
++                              meta->entries);
++                      TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
++                              " data_block 0x%llx\n", cur_index_block,
++                              cur_offset, cur_data_block);
++              }
++
++              for (i = meta->offset + meta->entries; i <= index &&
++                              i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
++                      int blocks = skip * SQUASHFS_META_INDEXES;
++
++                      while (blocks) {
++                              int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
++                                      blocks;
++                              int res = read_block_index(inode->i_sb, block,
++                                      block_list, &cur_index_block,
++                                      &cur_offset);
++
++                              if (res == -1)
++                                      goto failed;
++
++                              cur_data_block += res;
++                              blocks -= block;
++                      }
++
++                      meta_entry = &meta->meta_entry[i - meta->offset];
++                      meta_entry->index_block = cur_index_block - sblk->inode_table_start;
++                      meta_entry->offset = cur_offset;
++                      meta_entry->data_block = cur_data_block;
++                      meta->entries ++;
++                      offset ++;
++              }
++
++              TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
++                              meta->offset, meta->entries);
++
++              release_meta_index(inode, meta);
++      }
++
++all_done:
++      *index_block = cur_index_block;
++      *index_offset = cur_offset;
++      *data_block = cur_data_block;
++
++      return offset * SQUASHFS_META_INDEXES * skip;
++
++failed:
++      release_meta_index(inode, meta);
++      return -1;
++}
++
++
++static long long read_blocklist(struct inode *inode, int index,
++                              int readahead_blks, char *block_list,
++                              unsigned short **block_p, unsigned int *bsize)
++{
++      long long block_ptr;
++      int offset;
++      long long block;
++      int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
++              block_list);
++
++      TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
++                     " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
++                     block);
++
++      if(res == -1)
++              goto failure;
++
++      index -= res;
++
++      while ( index ) {
++              int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
++              int res = read_block_index(inode->i_sb, blocks, block_list,
++                      &block_ptr, &offset);
++              if (res == -1)
++                      goto failure;
++              block += res;
++              index -= blocks;
++      }
++
++      if (read_block_index(inode->i_sb, 1, block_list,
++                      &block_ptr, &offset) == -1)
++              goto failure;
++      *bsize = *((unsigned int *) block_list);
++
++      return block;
++
++failure:
++      return 0;
++}
++
++
++static int squashfs_readpage(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned char *block_list;
++      long long block;
++      unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
++      int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
++      void *pageaddr;
++      struct squashfs_fragment_cache *fragment = NULL;
++      char *data_ptr = msblk->read_page;
++      
++      int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
++      int start_index = page->index & ~mask;
++      int end_index = start_index | mask;
++
++      TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
++                                      page->index,
++                                      SQUASHFS_I(inode)->start_block);
++
++      if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
++              ERROR("Failed to allocate block_list\n");
++              goto skip_read;
++      }
++
++      if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++                                      PAGE_CACHE_SHIFT))
++              goto skip_read;
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || index < (i_size_read(inode) >>
++                                      sblk->block_log)) {
++              if ((block = (msblk->read_blocklist)(inode, index, 1,
++                                      block_list, NULL, &bsize)) == 0)
++                      goto skip_read;
++
++              mutex_lock(&msblk->read_page_mutex);
++              
++              if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
++                                      block, bsize, NULL, sblk->block_size))) {
++                      ERROR("Unable to read page, block %llx, size %x\n", block,
++                                      bsize);
++                      mutex_unlock(&msblk->read_page_mutex);
++                      goto skip_read;
++              }
++      } else {
++              if ((fragment = get_cached_fragment(inode->i_sb,
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      SQUASHFS_I(inode)->u.s1.fragment_size))
++                                      == NULL) {
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      (int) SQUASHFS_I(inode)->
++                                      u.s1.fragment_size);
++                      goto skip_read;
++              }
++              bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
++                                      (i_size_read(inode) & (sblk->block_size
++                                      - 1));
++              byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
++              data_ptr = fragment->data;
++      }
++
++      for (i = start_index; i <= end_index && byte_offset < bytes;
++                                      i++, byte_offset += PAGE_CACHE_SIZE) {
++              struct page *push_page;
++              int avail = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
++                                      PAGE_CACHE_SIZE : bytes - byte_offset;
++
++              TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
++                                      bytes, i, byte_offset, avail);
++
++              push_page = (i == page->index) ? page :
++                      grab_cache_page_nowait(page->mapping, i);
++
++              if (!push_page)
++                      continue;
++
++              if (PageUptodate(push_page))
++                      goto skip_page;
++
++              pageaddr = kmap_atomic(push_page, KM_USER0);
++              memcpy(pageaddr, data_ptr + byte_offset, avail);
++              memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
++              kunmap_atomic(pageaddr, KM_USER0);
++              flush_dcache_page(push_page);
++              SetPageUptodate(push_page);
++skip_page:
++              unlock_page(push_page);
++              if(i != page->index)
++                      page_cache_release(push_page);
++      }
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || index < (i_size_read(inode) >>
++                                      sblk->block_log))
++              mutex_unlock(&msblk->read_page_mutex);
++      else
++              release_cached_fragment(msblk, fragment);
++
++      kfree(block_list);
++      return 0;
++
++skip_read:
++      pageaddr = kmap_atomic(page, KM_USER0);
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap_atomic(pageaddr, KM_USER0);
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      kfree(block_list);
++      return 0;
++}
++
++
++static int squashfs_readpage4K(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned char *block_list;
++      long long block;
++      unsigned int bsize, bytes = 0;
++      void *pageaddr;
++      
++      TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
++                                      page->index,
++                                      SQUASHFS_I(inode)->start_block);
++
++      if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++                                      PAGE_CACHE_SHIFT)) {
++              block_list = NULL;
++              goto skip_read;
++      }
++
++      if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
++              ERROR("Failed to allocate block_list\n");
++              goto skip_read;
++      }
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || page->index < (i_size_read(inode) >>
++                                      sblk->block_log)) {
++              block = (msblk->read_blocklist)(inode, page->index, 1,
++                                      block_list, NULL, &bsize);
++              if(block == 0)
++                      goto skip_read;
++
++              mutex_lock(&msblk->read_page_mutex);
++              bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
++                                      bsize, NULL, sblk->block_size);
++              if (bytes) {
++                      pageaddr = kmap_atomic(page, KM_USER0);
++                      memcpy(pageaddr, msblk->read_page, bytes);
++                      kunmap_atomic(pageaddr, KM_USER0);
++              } else
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      block, bsize);
++              mutex_unlock(&msblk->read_page_mutex);
++      } else {
++              struct squashfs_fragment_cache *fragment =
++                      get_cached_fragment(inode->i_sb,
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      SQUASHFS_I(inode)-> u.s1.fragment_size);
++              if (fragment) {
++                      bytes = i_size_read(inode) & (sblk->block_size - 1);
++                      pageaddr = kmap_atomic(page, KM_USER0);
++                      memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
++                                      u.s1.fragment_offset, bytes);
++                      kunmap_atomic(pageaddr, KM_USER0);
++                      release_cached_fragment(msblk, fragment);
++              } else
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block, (int)
++                                      SQUASHFS_I(inode)-> u.s1.fragment_size);
++      }
++
++skip_read:
++      pageaddr = kmap_atomic(page, KM_USER0);
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap_atomic(pageaddr, KM_USER0);
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      kfree(block_list);
++      return 0;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long 
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              long long f_pos)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index index;
++
++      TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++                                      i_count, (unsigned int) f_pos);
++
++      f_pos =- 3;
++      if (f_pos == 0)
++              goto finish;
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) &index,
++                                      index_start, index_offset,
++                                      sizeof(index), &index_start,
++                                      &index_offset);
++
++              if (index.index > f_pos)
++                      break;
++
++              squashfs_get_cached_block(s, NULL, index_start, index_offset,
++                                      index.size + 1, &index_start,
++                                      &index_offset);
++
++              length = index.index;
++              *next_block = index.start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++      return length + 3;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              const char *name, int size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index *index;
++      char *str;
++
++      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++      if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
++              (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_index\n");
++              goto failure;
++      }
++
++      index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
++      strncpy(str, name, size);
++      str[size] = '\0';
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) index,
++                                      index_start, index_offset,
++                                      sizeof(struct squashfs_dir_index),
++                                      &index_start, &index_offset);
++
++              squashfs_get_cached_block(s, index->name, index_start,
++                                      index_offset, index->size + 1,
++                                      &index_start, &index_offset);
++
++              index->name[index->size + 1] = '\0';
++
++              if (strcmp(index->name, str) > 0)
++                      break;
++
++              length = index->index;
++              *next_block = index->start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++      kfree(str);
++failure:
++      return length + 3;
++}
++
++              
++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++      struct inode *i = file->f_dentry->d_inode;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++              dir_count;
++      struct squashfs_dir_header dirh;
++      struct squashfs_dir_entry *dire;
++
++      TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto finish;
++      }
++
++      while(file->f_pos < 3) {
++              char *name;
++              int size, i_ino;
++
++              if(file->f_pos == 0) {
++                      name = ".";
++                      size = 1;
++                      i_ino = i->i_ino;
++              } else {
++                      name = "..";
++                      size = 2;
++                      i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
++              }
++              TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
++                              (unsigned int) dirent, name, size, (int)
++                              file->f_pos, i_ino,
++                              squashfs_filetype_table[1]);
++
++              if (filldir(dirent, name, size,
++                              file->f_pos, i_ino,
++                              squashfs_filetype_table[1]) < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++              }
++              file->f_pos += size;
++      }
++
++      length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count,
++                              file->f_pos);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header sdirh;
++                      
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block, next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block, next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                              next_block, next_offset,
++                                              dire->size + 1, &next_block,
++                                              &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (file->f_pos >= length)
++                              continue;
++
++                      dire->name[dire->size + 1] = '\0';
++
++                      TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
++                                      (unsigned int) dirent, dire->name,
++                                      dire->size + 1, (int) file->f_pos,
++                                      dirh.start_block, dire->offset,
++                                      dirh.inode_number + dire->inode_number,
++                                      squashfs_filetype_table[dire->type]);
++
++                      if (filldir(dirent, dire->name, dire->size + 1,
++                                      file->f_pos,
++                                      dirh.inode_number + dire->inode_number,
++                                      squashfs_filetype_table[dire->type])
++                                      < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++                      }
++                      file->f_pos = length;
++              }
++      }
++
++finish:
++      kfree(dire);
++      return 0;
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      kfree(dire);
++      return 0;
++}
++
++
++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
++                              struct nameidata *nd)
++{
++      const unsigned char *name = dentry->d_name.name;
++      int len = dentry->d_name.len;
++      struct inode *inode = NULL;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++                              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++                              dir_count;
++      struct squashfs_dir_header dirh;
++      struct squashfs_dir_entry *dire;
++
++      TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto exit_lookup;
++      }
++
++      if (len > SQUASHFS_NAME_LEN)
++              goto exit_lookup;
++
++      length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count, name,
++                              len);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header sdirh;
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block,next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block,next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                      next_block, next_offset, dire->size + 1,
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (name[0] < dire->name[0])
++                              goto exit_lookup;
++
++                      if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
++                              squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
++                                                              dire->offset);
++
++                              TRACE("calling squashfs_iget for directory "
++                                      "entry %s, inode %x:%x, %d\n", name,
++                                      dirh.start_block, dire->offset,
++                                      dirh.inode_number + dire->inode_number);
++
++                              inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
++
++                              goto exit_lookup;
++                      }
++              }
++      }
++
++exit_lookup:
++      kfree(dire);
++      if (inode)
++              return d_splice_alias(inode, dentry);
++      d_add(dentry, inode);
++      return ERR_PTR(0);
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      goto exit_lookup;
++}
++
++
++static int squashfs_remount(struct super_block *s, int *flags, char *data)
++{
++      *flags |= MS_RDONLY;
++      return 0;
++}
++
++
++static void squashfs_put_super(struct super_block *s)
++{
++      int i;
++
++      if (s->s_fs_info) {
++              struct squashfs_sb_info *sbi = s->s_fs_info;
++              if (sbi->block_cache)
++                      for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++                              if (sbi->block_cache[i].block !=
++                                                      SQUASHFS_INVALID_BLK)
++                                      kfree(sbi->block_cache[i].data);
++              if (sbi->fragment)
++                      for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 
++                              SQUASHFS_FREE(sbi->fragment[i].data);
++              kfree(sbi->fragment);
++              kfree(sbi->block_cache);
++              kfree(sbi->read_page);
++              kfree(sbi->uid);
++              kfree(sbi->fragment_index);
++              kfree(sbi->fragment_index_2);
++              kfree(sbi->meta_index);
++              vfree(sbi->stream.workspace);
++              kfree(s->s_fs_info);
++              s->s_fs_info = NULL;
++      }
++}
++
++
++static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
++                              const char *dev_name, void *data,
++                              struct vfsmount *mnt)
++{
++      return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
++                              mnt);
++}
++
++
++static int __init init_squashfs_fs(void)
++{
++      int err = init_inodecache();
++      if (err)
++              goto out;
++
++      printk(KERN_INFO "squashfs: version 3.2-r2 (2007/01/15) "
++              "Phillip Lougher\n");
++
++      if ((err = register_filesystem(&squashfs_fs_type)))
++              destroy_inodecache();
++
++out:
++      return err;
++}
++
++
++static void __exit exit_squashfs_fs(void)
++{
++      unregister_filesystem(&squashfs_fs_type);
++      destroy_inodecache();
++}
++
++
++static struct kmem_cache * squashfs_inode_cachep;
++
++
++static struct inode *squashfs_alloc_inode(struct super_block *sb)
++{
++      struct squashfs_inode_info *ei;
++      ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
++      if (!ei)
++              return NULL;
++      return &ei->vfs_inode;
++}
++
++
++static void squashfs_destroy_inode(struct inode *inode)
++{
++      kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
++}
++
++
++static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
++{
++      struct squashfs_inode_info *ei = foo;
++
++      if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++                                                      SLAB_CTOR_CONSTRUCTOR)
++              inode_init_once(&ei->vfs_inode);
++}
++ 
++
++static int __init init_inodecache(void)
++{
++      squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
++           sizeof(struct squashfs_inode_info),
++           0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
++           init_once, NULL);
++      if (squashfs_inode_cachep == NULL)
++              return -ENOMEM;
++      return 0;
++}
++
++
++static void destroy_inodecache(void)
++{
++      kmem_cache_destroy(squashfs_inode_cachep);
++}
++
++
++module_init(init_squashfs_fs);
++module_exit(exit_squashfs_fs);
++MODULE_DESCRIPTION("squashfs 3.2-r2, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ linux-2.6.24-rc1/fs/squashfs/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the linux squashfs routines.
++#
++
++obj-$(CONFIG_SQUASHFS) += squashfs.o
++squashfs-y += inode.o
++squashfs-y += squashfs2_0.o
+--- /dev/null
++++ linux-2.6.24-rc1/fs/squashfs/squashfs2_0.c
+@@ -0,0 +1,742 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs2_0.c
++ */
++
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/zlib.h>
++#include <linux/fs.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++
++#include "squashfs.h"
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
++                              struct nameidata *);
++
++static struct file_operations squashfs_dir_ops_2 = {
++      .read = generic_read_dir,
++      .readdir = squashfs_readdir_2
++};
++
++static struct inode_operations squashfs_dir_inode_ops_2 = {
++      .lookup = squashfs_lookup_2
++};
++
++static unsigned char squashfs_filetype_table[] = {
++      DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static int read_fragment_index_table_2(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
++                                      (sblk->fragments), GFP_KERNEL))) {
++              ERROR("Failed to allocate uid/gid table\n");
++              return 0;
++      }
++   
++      if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
++                                      !squashfs_read_data(s, (char *)
++                                      msblk->fragment_index_2,
++                                      sblk->fragment_table_start,
++                                      SQUASHFS_FRAGMENT_INDEX_BYTES_2
++                                      (sblk->fragments) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
++              ERROR("unable to read fragment index table\n");
++              return 0;
++      }
++
++      if (msblk->swap) {
++              int i;
++              unsigned int fragment;
++
++              for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
++                                                                      i++) {
++                      SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
++                                              &msblk->fragment_index_2[i], 1);
++                      msblk->fragment_index_2[i] = fragment;
++              }
++      }
++
++      return 1;
++}
++
++
++static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
++                              long long *fragment_start_block,
++                              unsigned int *fragment_size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      long long start_block =
++              msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
++      int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
++      struct squashfs_fragment_entry_2 fragment_entry;
++
++      if (msblk->swap) {
++              struct squashfs_fragment_entry_2 sfragment_entry;
++
++              if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++                                      start_block, offset,
++                                      sizeof(sfragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++              SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
++      } else
++              if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++                                      start_block, offset,
++                                      sizeof(fragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++
++      *fragment_start_block = fragment_entry.start_block;
++      *fragment_size = fragment_entry.size;
++
++      return 1;
++
++out:
++      return 0;
++}
++
++
++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
++              struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
++{
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      i->i_ino = ino;
++      i->i_mtime.tv_sec = sblk->mkfs_time;
++      i->i_atime.tv_sec = sblk->mkfs_time;
++      i->i_ctime.tv_sec = sblk->mkfs_time;
++      i->i_uid = msblk->uid[inodeb->uid];
++      i->i_mode = inodeb->mode;
++      i->i_nlink = 1;
++      i->i_size = 0;
++      if (inodeb->guid == SQUASHFS_GUIDS)
++              i->i_gid = i->i_uid;
++      else
++              i->i_gid = msblk->guid[inodeb->guid];
++}
++
++
++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
++{
++      struct super_block *s = i->i_sb;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned int block = SQUASHFS_INODE_BLK(inode) +
++              sblk->inode_table_start;
++      unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++      unsigned int ino = i->i_ino;
++      long long next_block;
++      unsigned int next_offset;
++      union squashfs_inode_header_2 id, sid;
++      struct squashfs_base_inode_header_2 *inodeb = &id.base,
++                                        *sinodeb = &sid.base;
++
++      TRACE("Entered squashfs_iget\n");
++
++      if (msblk->swap) {
++              if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++                                      offset, sizeof(*sinodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++              SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
++                                      sizeof(*sinodeb));
++      } else
++              if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++                                      offset, sizeof(*inodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++
++      squashfs_new_inode(msblk, i, inodeb, ino);
++
++      switch(inodeb->inode_type) {
++              case SQUASHFS_FILE_TYPE: {
++                      struct squashfs_reg_inode_header_2 *inodep = &id.reg;
++                      struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
++                      long long frag_blk;
++                      unsigned int frag_size = 0;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location_2(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %x, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_DIR_TYPE: {
++                      struct squashfs_dir_inode_header_2 *inodep = &id.dir;
++                      struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops_2;
++                      i->i_fop = &squashfs_dir_ops_2;
++                      i->i_mode |= S_IFDIR;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++                      SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++                      TRACE("Directory inode %x:%x, start_block %x, offset "
++                                      "%x\n", SQUASHFS_INODE_BLK(inode),
++                                      offset, inodep->start_block,
++                                      inodep->offset);
++                      break;
++              }
++              case SQUASHFS_LDIR_TYPE: {
++                      struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
++                      struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
++                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops_2;
++                      i->i_fop = &squashfs_dir_ops_2;
++                      i->i_mode |= S_IFDIR;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++                      SQUASHFS_I(i)->u.s2.directory_index_offset =
++                                                              next_offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count =
++                                                              inodep->i_count;
++                      SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++                      TRACE("Long directory inode %x:%x, start_block %x, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, inodep->offset);
++                      break;
++              }
++              case SQUASHFS_SYMLINK_TYPE: {
++                      struct squashfs_symlink_inode_header_2 *inodep =
++                                                              &id.symlink;
++                      struct squashfs_symlink_inode_header_2 *sinodep =
++                                                              &sid.symlink;
++      
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
++                                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_size = inodep->symlink_size;
++                      i->i_op = &page_symlink_inode_operations;
++                      i->i_data.a_ops = &squashfs_symlink_aops;
++                      i->i_mode |= S_IFLNK;
++                      SQUASHFS_I(i)->start_block = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++
++                      TRACE("Symbolic link inode %x:%x, start_block %llx, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      next_block, next_offset);
++                      break;
++               }
++               case SQUASHFS_BLKDEV_TYPE:
++               case SQUASHFS_CHRDEV_TYPE: {
++                      struct squashfs_dev_inode_header_2 *inodep = &id.dev;
++                      struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      i->i_mode |= (inodeb->inode_type ==
++                                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
++                                      S_IFBLK;
++                      init_special_inode(i, i->i_mode,
++                                      old_decode_dev(inodep->rdev));
++
++                      TRACE("Device inode %x:%x, rdev %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->rdev);
++                      break;
++               }
++               case SQUASHFS_FIFO_TYPE:
++               case SQUASHFS_SOCKET_TYPE: {
++
++                      i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++                                                      ? S_IFIFO : S_IFSOCK;
++                      init_special_inode(i, i->i_mode, 0);
++                      break;
++               }
++               default:
++                      ERROR("Unknown inode type %d in squashfs_iget!\n",
++                                      inodeb->inode_type);
++                      goto failed_read1;
++      }
++      
++      return 1;
++
++failed_read:
++      ERROR("Unable to read inode [%x:%x]\n", block, offset);
++
++failed_read1:
++      return 0;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long 
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              long long f_pos)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index_2 index;
++
++      TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++                                      i_count, (unsigned int) f_pos);
++
++      if (f_pos == 0)
++              goto finish;
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index_2 sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) &index,
++                                      index_start, index_offset,
++                                      sizeof(index), &index_start,
++                                      &index_offset);
++
++              if (index.index > f_pos)
++                      break;
++
++              squashfs_get_cached_block(s, NULL, index_start, index_offset,
++                                      index.size + 1, &index_start,
++                                      &index_offset);
++
++              length = index.index;
++              *next_block = index.start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++      return length;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              const char *name, int size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index_2 *index;
++      char *str;
++
++      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++      if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
++              (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_index\n");
++              goto failure;
++      }
++
++      index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
++      strncpy(str, name, size);
++      str[size] = '\0';
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index_2 sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) index,
++                                      index_start, index_offset,
++                                      sizeof(struct squashfs_dir_index_2),
++                                      &index_start, &index_offset);
++
++              squashfs_get_cached_block(s, index->name, index_start,
++                                      index_offset, index->size + 1,
++                                      &index_start, &index_offset);
++
++              index->name[index->size + 1] = '\0';
++
++              if (strcmp(index->name, str) > 0)
++                      break;
++
++              length = index->index;
++              *next_block = index->start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++      kfree(str);
++failure:
++      return length;
++}
++
++              
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
++{
++      struct inode *i = file->f_dentry->d_inode;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++              dir_count;
++      struct squashfs_dir_header_2 dirh;
++      struct squashfs_dir_entry_2 *dire;
++
++      TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto finish;
++      }
++
++      length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count,
++                              file->f_pos);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header_2 sdirh;
++                      
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry_2 sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block, next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block, next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                              next_block, next_offset,
++                                              dire->size + 1, &next_block,
++                                              &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (file->f_pos >= length)
++                              continue;
++
++                      dire->name[dire->size + 1] = '\0';
++
++                      TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
++                                      (unsigned int) dirent, dire->name,
++                                      dire->size + 1, (int) file->f_pos,
++                                      dirh.start_block, dire->offset,
++                                      squashfs_filetype_table[dire->type]);
++
++                      if (filldir(dirent, dire->name, dire->size + 1,
++                                      file->f_pos, SQUASHFS_MK_VFS_INODE(
++                                      dirh.start_block, dire->offset),
++                                      squashfs_filetype_table[dire->type])
++                                      < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++                      }
++                      file->f_pos = length;
++              }
++      }
++
++finish:
++      kfree(dire);
++      return 0;
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      kfree(dire);
++      return 0;
++}
++
++
++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
++                              struct nameidata *nd)
++{
++      const unsigned char *name = dentry->d_name.name;
++      int len = dentry->d_name.len;
++      struct inode *inode = NULL;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++                              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++                              dir_count;
++      struct squashfs_dir_header_2 dirh;
++      struct squashfs_dir_entry_2 *dire;
++      int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
++
++      TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto exit_loop;
++      }
++
++      if (len > SQUASHFS_NAME_LEN)
++              goto exit_loop;
++
++      length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count, name,
++                              len);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header_2 sdirh;
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry_2 sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block,next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block,next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                      next_block, next_offset, dire->size + 1,
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (sorted && name[0] < dire->name[0])
++                              goto exit_loop;
++
++                      if ((len == dire->size + 1) && !strncmp(name,
++                                              dire->name, len)) {
++                              squashfs_inode_t ino =
++                                      SQUASHFS_MKINODE(dirh.start_block,
++                                      dire->offset);
++                              unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
++                                      dire->offset);
++
++                              TRACE("calling squashfs_iget for directory "
++                                      "entry %s, inode %x:%x, %lld\n", name,
++                                      dirh.start_block, dire->offset, ino);
++
++                              inode = squashfs_iget(i->i_sb, ino, inode_number);
++
++                              goto exit_loop;
++                      }
++              }
++      }
++
++exit_loop:
++      kfree(dire);
++      d_add(dentry, inode);
++      return ERR_PTR(0);
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      goto exit_loop;
++}
++
++
++int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      msblk->read_inode = squashfs_read_inode_2;
++      msblk->read_fragment_index_table = read_fragment_index_table_2;
++
++      sblk->bytes_used = sblk->bytes_used_2;
++      sblk->uid_start = sblk->uid_start_2;
++      sblk->guid_start = sblk->guid_start_2;
++      sblk->inode_table_start = sblk->inode_table_start_2;
++      sblk->directory_table_start = sblk->directory_table_start_2;
++      sblk->fragment_table_start = sblk->fragment_table_start_2;
++
++      return 1;
++}
+--- /dev/null
++++ linux-2.6.24-rc1/fs/squashfs/squashfs.h
+@@ -0,0 +1,87 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs.h
++ */
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#endif
++
++#ifdef SQUASHFS_TRACE
++#define TRACE(s, args...)     printk(KERN_NOTICE "SQUASHFS: "s, ## args)
++#else
++#define TRACE(s, args...)     {}
++#endif
++
++#define ERROR(s, args...)     printk(KERN_ERR "SQUASHFS error: "s, ## args)
++
++#define SERROR(s, args...)    do { \
++                              if (!silent) \
++                              printk(KERN_ERR "SQUASHFS error: "s, ## args);\
++                              } while(0)
++
++#define WARNING(s, args...)   printk(KERN_WARNING "SQUASHFS: "s, ## args)
++
++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
++{
++      return list_entry(inode, struct squashfs_inode_info, vfs_inode);
++}
++
++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
++#define SQSH_EXTERN
++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++                              long long index, unsigned int length,
++                              long long *next_index, int srclength);
++extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
++                              long long block, unsigned int offset,
++                              int length, long long *next_block,
++                              unsigned int *next_offset);
++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++                                      squashfs_fragment_cache *fragment);
++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++                                      *s, long long start_block,
++                                      int length);
++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
++extern const struct address_space_operations squashfs_symlink_aops;
++extern const struct address_space_operations squashfs_aops;
++extern const struct address_space_operations squashfs_aops_4K;
++extern struct inode_operations squashfs_dir_inode_ops;
++#else
++#define SQSH_EXTERN static
++#endif
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
++{
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++      return 0;
++}
++#endif
+--- /dev/null
++++ linux-2.6.24-rc1/include/linux/squashfs_fs.h
+@@ -0,0 +1,934 @@
++#ifndef SQUASHFS_FS
++#define SQUASHFS_FS
++
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs.h
++ */
++
++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
++
++#ifdef        CONFIG_SQUASHFS_VMALLOC
++#define SQUASHFS_ALLOC(a)             vmalloc(a)
++#define SQUASHFS_FREE(a)              vfree(a)
++#else
++#define SQUASHFS_ALLOC(a)             kmalloc(a, GFP_KERNEL)
++#define SQUASHFS_FREE(a)              kfree(a)
++#endif
++#define SQUASHFS_CACHED_FRAGMENTS     CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE     
++#define SQUASHFS_MAJOR                        3
++#define SQUASHFS_MINOR                        0
++#define SQUASHFS_MAGIC                        0x73717368
++#define SQUASHFS_MAGIC_SWAP           0x68737173
++#define SQUASHFS_START                        0
++
++/* size of metadata (inode and directory) blocks */
++#define SQUASHFS_METADATA_SIZE                8192
++#define SQUASHFS_METADATA_LOG         13
++
++/* default size of data blocks */
++#define SQUASHFS_FILE_SIZE            65536
++#define SQUASHFS_FILE_LOG             16
++
++#define SQUASHFS_FILE_MAX_SIZE                65536
++
++/* Max number of uids and gids */
++#define SQUASHFS_UIDS                 256
++#define SQUASHFS_GUIDS                        255
++
++/* Max length of filename (not 255) */
++#define SQUASHFS_NAME_LEN             256
++
++#define SQUASHFS_INVALID              ((long long) 0xffffffffffff)
++#define SQUASHFS_INVALID_FRAG         ((unsigned int) 0xffffffff)
++#define SQUASHFS_INVALID_BLK          ((long long) -1)
++#define SQUASHFS_USED_BLK             ((long long) -2)
++
++/* Filesystem flags */
++#define SQUASHFS_NOI                  0
++#define SQUASHFS_NOD                  1
++#define SQUASHFS_CHECK                        2
++#define SQUASHFS_NOF                  3
++#define SQUASHFS_NO_FRAG              4
++#define SQUASHFS_ALWAYS_FRAG          5
++#define SQUASHFS_DUPLICATE            6
++#define SQUASHFS_EXPORT                       7
++
++#define SQUASHFS_BIT(flag, bit)               ((flag >> bit) & 1)
++
++#define SQUASHFS_UNCOMPRESSED_INODES(flags)   SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOI)
++
++#define SQUASHFS_UNCOMPRESSED_DATA(flags)     SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOD)
++
++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)        SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOF)
++
++#define SQUASHFS_NO_FRAGMENTS(flags)          SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NO_FRAG)
++
++#define SQUASHFS_ALWAYS_FRAGMENTS(flags)      SQUASHFS_BIT(flags, \
++                                              SQUASHFS_ALWAYS_FRAG)
++
++#define SQUASHFS_DUPLICATES(flags)            SQUASHFS_BIT(flags, \
++                                              SQUASHFS_DUPLICATE)
++
++#define SQUASHFS_EXPORTABLE(flags)            SQUASHFS_BIT(flags, \
++                                              SQUASHFS_EXPORT)
++
++#define SQUASHFS_CHECK_DATA(flags)            SQUASHFS_BIT(flags, \
++                                              SQUASHFS_CHECK)
++
++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
++              duplicate_checking, exortable)  (noi | (nod << 1) | (check_data << 2) \
++              | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
++              (duplicate_checking << 6) | (exportable << 7))
++
++/* Max number of types and file types */
++#define SQUASHFS_DIR_TYPE             1
++#define SQUASHFS_FILE_TYPE            2
++#define SQUASHFS_SYMLINK_TYPE         3
++#define SQUASHFS_BLKDEV_TYPE          4
++#define SQUASHFS_CHRDEV_TYPE          5
++#define SQUASHFS_FIFO_TYPE            6
++#define SQUASHFS_SOCKET_TYPE          7
++#define SQUASHFS_LDIR_TYPE            8
++#define SQUASHFS_LREG_TYPE            9
++
++/* 1.0 filesystem type definitions */
++#define SQUASHFS_TYPES                        5
++#define SQUASHFS_IPC_TYPE             0
++
++/* Flag whether block is compressed or uncompressed, bit is set if block is
++ * uncompressed */
++#define SQUASHFS_COMPRESSED_BIT               (1 << 15)
++
++#define SQUASHFS_COMPRESSED_SIZE(B)   (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
++              (B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
++
++#define SQUASHFS_COMPRESSED(B)                (!((B) & SQUASHFS_COMPRESSED_BIT))
++
++#define SQUASHFS_COMPRESSED_BIT_BLOCK         (1 << 24)
++
++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)     (((B) & \
++      ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
++      ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
++
++#define SQUASHFS_COMPRESSED_BLOCK(B)  (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
++
++/*
++ * Inode number ops.  Inodes consist of a compressed block number, and an
++ * uncompressed  offset within that block
++ */
++#define SQUASHFS_INODE_BLK(a)         ((unsigned int) ((a) >> 16))
++
++#define SQUASHFS_INODE_OFFSET(a)      ((unsigned int) ((a) & 0xffff))
++
++#define SQUASHFS_MKINODE(A, B)                ((squashfs_inode_t)(((squashfs_inode_t) (A)\
++                                      << 16) + (B)))
++
++/* Compute 32 bit VFS inode number from squashfs inode number */
++#define SQUASHFS_MK_VFS_INODE(a, b)   ((unsigned int) (((a) << 8) + \
++                                      ((b) >> 2) + 1))
++/* XXX */
++
++/* Translate between VFS mode and squashfs mode */
++#define SQUASHFS_MODE(a)              ((a) & 0xfff)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES(A)    ((A) * sizeof(struct squashfs_fragment_entry))
++
++#define SQUASHFS_FRAGMENT_INDEX(A)    (SQUASHFS_FRAGMENT_BYTES(A) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)     (SQUASHFS_FRAGMENT_BYTES(A) % \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES(A)  ((SQUASHFS_FRAGMENT_BYTES(A) + \
++                                      SQUASHFS_METADATA_SIZE - 1) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)      (SQUASHFS_FRAGMENT_INDEXES(A) *\
++                                              sizeof(long long))
++
++/* inode lookup table defines */
++#define SQUASHFS_LOOKUP_BYTES(A)      ((A) * sizeof(squashfs_inode_t))
++
++#define SQUASHFS_LOOKUP_BLOCK(A)              (SQUASHFS_LOOKUP_BYTES(A) / \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A)               (SQUASHFS_LOOKUP_BYTES(A) % \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_LOOKUP_BLOCKS(A)     ((SQUASHFS_LOOKUP_BYTES(A) + \
++                                      SQUASHFS_METADATA_SIZE - 1) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A)        (SQUASHFS_LOOKUP_BLOCKS(A) *\
++                                      sizeof(long long))
++
++/* cached data constants for filesystem */
++#define SQUASHFS_CACHED_BLKS          8
++
++#define SQUASHFS_MAX_FILE_SIZE_LOG    64
++
++#define SQUASHFS_MAX_FILE_SIZE                ((long long) 1 << \
++                                      (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
++
++#define SQUASHFS_MARKER_BYTE          0xff
++
++/* meta index cache */
++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
++#define SQUASHFS_META_ENTRIES 31
++#define SQUASHFS_META_NUMBER  8
++#define SQUASHFS_SLOTS                4
++
++struct meta_entry {
++      long long               data_block;
++      unsigned int            index_block;
++      unsigned short          offset;
++      unsigned short          pad;
++};
++
++struct meta_index {
++      unsigned int            inode_number;
++      unsigned int            offset;
++      unsigned short          entries;
++      unsigned short          skip;
++      unsigned short          locked;
++      unsigned short          pad;
++      struct meta_entry       meta_entry[SQUASHFS_META_ENTRIES];
++};
++
++
++/*
++ * definitions for structures on disk
++ */
++
++typedef long long             squashfs_block_t;
++typedef long long             squashfs_inode_t;
++
++struct squashfs_super_block {
++      unsigned int            s_magic;
++      unsigned int            inodes;
++      unsigned int            bytes_used_2;
++      unsigned int            uid_start_2;
++      unsigned int            guid_start_2;
++      unsigned int            inode_table_start_2;
++      unsigned int            directory_table_start_2;
++      unsigned int            s_major:16;
++      unsigned int            s_minor:16;
++      unsigned int            block_size_1:16;
++      unsigned int            block_log:16;
++      unsigned int            flags:8;
++      unsigned int            no_uids:8;
++      unsigned int            no_guids:8;
++      unsigned int            mkfs_time /* time of filesystem creation */;
++      squashfs_inode_t        root_inode;
++      unsigned int            block_size;
++      unsigned int            fragments;
++      unsigned int            fragment_table_start_2;
++      long long               bytes_used;
++      long long               uid_start;
++      long long               guid_start;
++      long long               inode_table_start;
++      long long               directory_table_start;
++      long long               fragment_table_start;
++      long long               lookup_table_start;
++} __attribute__ ((packed));
++
++struct squashfs_dir_index {
++      unsigned int            index;
++      unsigned int            start_block;
++      unsigned char           size;
++      unsigned char           name[0];
++} __attribute__ ((packed));
++
++#define SQUASHFS_BASE_INODE_HEADER            \
++      unsigned int            inode_type:4;   \
++      unsigned int            mode:12;        \
++      unsigned int            uid:8;          \
++      unsigned int            guid:8;         \
++      unsigned int            mtime;          \
++      unsigned int            inode_number;
++
++struct squashfs_base_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      squashfs_block_t        start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      unsigned int            file_size;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_lreg_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      squashfs_block_t        start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      long long               file_size;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            start_block;
++      unsigned int            parent_inode;
++} __attribute__  ((packed));
++
++struct squashfs_ldir_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned int            file_size:27;
++      unsigned int            offset:13;
++      unsigned int            start_block;
++      unsigned int            i_count:16;
++      unsigned int            parent_inode;
++      struct squashfs_dir_index       index[0];
++} __attribute__  ((packed));
++
++union squashfs_inode_header {
++      struct squashfs_base_inode_header       base;
++      struct squashfs_dev_inode_header        dev;
++      struct squashfs_symlink_inode_header    symlink;
++      struct squashfs_reg_inode_header        reg;
++      struct squashfs_lreg_inode_header       lreg;
++      struct squashfs_dir_inode_header        dir;
++      struct squashfs_ldir_inode_header       ldir;
++      struct squashfs_ipc_inode_header        ipc;
++};
++      
++struct squashfs_dir_entry {
++      unsigned int            offset:13;
++      unsigned int            type:3;
++      unsigned int            size:8;
++      int                     inode_number:16;
++      char                    name[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_header {
++      unsigned int            count:8;
++      unsigned int            start_block;
++      unsigned int            inode_number;
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry {
++      long long               start_block;
++      unsigned int            size;
++      unsigned int            pending;
++} __attribute__ ((packed));
++
++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
++extern int squashfs_uncompress_init(void);
++extern int squashfs_uncompress_exit(void);
++
++/*
++ * macros to convert each packed bitfield structure from little endian to big
++ * endian and vice versa.  These are needed when creating or using a filesystem
++ * on a machine with different byte ordering to the target architecture.
++ *
++ */
++
++#define SQUASHFS_SWAP_START \
++      int bits;\
++      int b_pos;\
++      unsigned long long val;\
++      unsigned char *s;\
++      unsigned char *d;
++
++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
++      SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
++      SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
++      SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
++      SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
++      SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
++      SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
++      SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
++      SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
++      SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
++      SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
++      SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
++      SQUASHFS_SWAP((s)->flags, d, 288, 8);\
++      SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
++      SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
++      SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
++      SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
++      SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
++      SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
++      SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
++      SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
++      SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
++      SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
++      SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
++      SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
++      SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
++      SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
++}
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++      SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++      SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++      SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_ipc_inode_header))\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_dev_inode_header)); \
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_reg_inode_header));\
++      SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
++      SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 192, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
++}
++
++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_lreg_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
++      SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 224, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_dir_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 147, 13);\
++      SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
++      SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_ldir_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
++      SQUASHFS_SWAP((s)->offset, d, 155, 13);\
++      SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
++      SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
++      SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
++      SQUASHFS_SWAP((s)->index, d, 0, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
++      SQUASHFS_SWAP((s)->size, d, 64, 8);\
++}
++
++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
++      SQUASHFS_SWAP((s)->count, d, 0, 8);\
++      SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
++      SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
++      SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++      SQUASHFS_SWAP((s)->type, d, 13, 3);\
++      SQUASHFS_SWAP((s)->size, d, 16, 8);\
++      SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
++      SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
++      SQUASHFS_SWAP((s)->size, d, 64, 32);\
++}
++
++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
++
++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 2);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      16)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
++}
++
++#define SQUASHFS_SWAP_INTS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 4);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      32)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
++}
++
++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 8);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      64)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
++}
++
++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * bits / 8);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      bits)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++
++struct squashfs_base_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            type:4;
++      unsigned int            offset:4;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            mtime;
++      unsigned int            start_block;
++      unsigned int            file_size:32;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++} __attribute__  ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 4);\
++      SQUASHFS_SWAP((s)->guid, d, 20, 4);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_ipc_inode_header_1));\
++      SQUASHFS_SWAP((s)->type, d, 24, 4);\
++      SQUASHFS_SWAP((s)->offset, d, 28, 4);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_dev_inode_header_1));\
++      SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header_1));\
++      SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_reg_inode_header_1));\
++      SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_dir_inode_header_1));\
++      SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 43, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
++}
++
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++
++struct squashfs_dir_index_2 {
++      unsigned int            index:27;
++      unsigned int            start_block:29;
++      unsigned char           size;
++      unsigned char           name[0];
++} __attribute__ ((packed));
++
++struct squashfs_base_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            mtime;
++      unsigned int            start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      unsigned int            file_size:32;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++} __attribute__  ((packed));
++
++struct squashfs_ldir_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            file_size:27;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++      unsigned int            i_count:16;
++      struct squashfs_dir_index_2     index[0];
++} __attribute__  ((packed));
++
++union squashfs_inode_header_2 {
++      struct squashfs_base_inode_header_2     base;
++      struct squashfs_dev_inode_header_2      dev;
++      struct squashfs_symlink_inode_header_2  symlink;
++      struct squashfs_reg_inode_header_2      reg;
++      struct squashfs_dir_inode_header_2      dir;
++      struct squashfs_ldir_inode_header_2     ldir;
++      struct squashfs_ipc_inode_header_2      ipc;
++};
++      
++struct squashfs_dir_header_2 {
++      unsigned int            count:8;
++      unsigned int            start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_dir_entry_2 {
++      unsigned int            offset:13;
++      unsigned int            type:3;
++      unsigned int            size:8;
++      char                    name[0];
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry_2 {
++      unsigned int            start_block;
++      unsigned int            size;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++      SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
++      SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_dev_inode_header_2)); \
++      SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header_2));\
++      SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_reg_inode_header_2));\
++      SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
++      SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 128, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_dir_inode_header_2));\
++      SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 51, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_ldir_inode_header_2));\
++      SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
++      SQUASHFS_SWAP((s)->offset, d, 59, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
++      SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
++      SQUASHFS_SWAP((s)->index, d, 0, 27);\
++      SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
++      SQUASHFS_SWAP((s)->size, d, 56, 8);\
++}
++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
++      SQUASHFS_SWAP((s)->count, d, 0, 8);\
++      SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
++      SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++      SQUASHFS_SWAP((s)->type, d, 13, 3);\
++      SQUASHFS_SWAP((s)->size, d, 16, 8);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
++      SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
++      SQUASHFS_SWAP((s)->size, d, 32, 32);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES_2(A)  (A * sizeof(struct squashfs_fragment_entry_2))
++
++#define SQUASHFS_FRAGMENT_INDEX_2(A)  (SQUASHFS_FRAGMENT_BYTES_2(A) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)   (SQUASHFS_FRAGMENT_BYTES_2(A) % \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES_2(A)        ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
++                                      SQUASHFS_METADATA_SIZE - 1) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)    (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
++                                              sizeof(int))
++
++#endif
++
++#ifdef __KERNEL__
++
++/*
++ * macros used to swap each structure entry, taking into account
++ * bitfields and different bitfield placing conventions on differing
++ * architectures
++ */
++
++#include <asm/byteorder.h>
++
++#ifdef __BIG_ENDIAN
++      /* convert from little endian to big endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++              tbits, b_pos)
++#else
++      /* convert from big endian to little endian */ 
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++              tbits, 64 - tbits - b_pos)
++#endif
++
++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
++      b_pos = pos % 8;\
++      val = 0;\
++      s = (unsigned char *)p + (pos / 8);\
++      d = ((unsigned char *) &val) + 7;\
++      for(bits = 0; bits < (tbits + b_pos); bits += 8) \
++              *d-- = *s++;\
++      value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
++}
++
++#define SQUASHFS_MEMSET(s, d, n)      memset(s, 0, n);
++
++#endif
++#endif
+--- /dev/null
++++ linux-2.6.24-rc1/include/linux/squashfs_fs_i.h
+@@ -0,0 +1,45 @@
++#ifndef SQUASHFS_FS_I
++#define SQUASHFS_FS_I
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_i.h
++ */
++
++struct squashfs_inode_info {
++      long long       start_block;
++      unsigned int    offset;
++      union {
++              struct {
++                      long long       fragment_start_block;
++                      unsigned int    fragment_size;
++                      unsigned int    fragment_offset;
++                      long long       block_list_start;
++              } s1;
++              struct {
++                      long long       directory_index_start;
++                      unsigned int    directory_index_offset;
++                      unsigned int    directory_index_count;
++                      unsigned int    parent_inode;
++              } s2;
++      } u;
++      struct inode    vfs_inode;
++};
++#endif
+--- /dev/null
++++ linux-2.6.24-rc1/include/linux/squashfs_fs_sb.h
+@@ -0,0 +1,74 @@
++#ifndef SQUASHFS_FS_SB
++#define SQUASHFS_FS_SB
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_sb.h
++ */
++
++#include <linux/squashfs_fs.h>
++
++struct squashfs_cache {
++      long long       block;
++      int             length;
++      long long       next_index;
++      char            *data;
++};
++
++struct squashfs_fragment_cache {
++      long long       block;
++      int             length;
++      unsigned int    locked;
++      char            *data;
++};
++
++struct squashfs_sb_info {
++      struct squashfs_super_block     sblk;
++      int                     devblksize;
++      int                     devblksize_log2;
++      int                     swap;
++      struct squashfs_cache   *block_cache;
++      struct squashfs_fragment_cache  *fragment;
++      int                     next_cache;
++      int                     next_fragment;
++      int                     next_meta_index;
++      unsigned int            *uid;
++      unsigned int            *guid;
++      long long               *fragment_index;
++      unsigned int            *fragment_index_2;
++      char                    *read_page;
++      struct mutex            read_data_mutex;
++      struct mutex            read_page_mutex;
++      struct mutex            block_cache_mutex;
++      struct mutex            fragment_mutex;
++      struct mutex            meta_index_mutex;
++      wait_queue_head_t       waitq;
++      wait_queue_head_t       fragment_wait_queue;
++      struct meta_index       *meta_index;
++      z_stream                stream;
++      long long               *inode_lookup_table;
++      int                     (*read_inode)(struct inode *i,  squashfs_inode_t \
++                              inode);
++      long long               (*read_blocklist)(struct inode *inode, int \
++                              index, int readahead_blks, char *block_list, \
++                              unsigned short **block_p, unsigned int *bsize);
++      int                     (*read_fragment_index_table)(struct super_block *s);
++};
++#endif
+--- linux-2.6.24-rc1.orig/init/do_mounts_rd.c
++++ linux-2.6.24-rc1/init/do_mounts_rd.c
+@@ -5,6 +5,7 @@
+ #include <linux/ext2_fs.h>
+ #include <linux/romfs_fs.h>
+ #include <linux/cramfs_fs.h>
++#include <linux/squashfs_fs.h>
+ #include <linux/initrd.h>
+ #include <linux/string.h>
+@@ -39,6 +40,7 @@
+  * numbers could not be found.
+  *
+  * We currently check for the following magic numbers:
++ *      squashfs
+  *    minix
+  *    ext2
+  *    romfs
+@@ -53,6 +55,7 @@
+       struct ext2_super_block *ext2sb;
+       struct romfs_super_block *romfsb;
+       struct cramfs_super *cramfsb;
++      struct squashfs_super_block *squashfsb;
+       int nblocks = -1;
+       unsigned char *buf;
+@@ -64,6 +67,7 @@
+       ext2sb = (struct ext2_super_block *) buf;
+       romfsb = (struct romfs_super_block *) buf;
+       cramfsb = (struct cramfs_super *) buf;
++      squashfsb = (struct squashfs_super_block *) buf;
+       memset(buf, 0xe5, size);
+       /*
+@@ -101,6 +105,18 @@
+               goto done;
+       }
++      /* squashfs is at block zero too */
++      if (squashfsb->s_magic == SQUASHFS_MAGIC) {
++              printk(KERN_NOTICE
++                     "RAMDISK: squashfs filesystem found at block %d\n",
++                     start_block);
++              if (squashfsb->s_major < 3)
++                      nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++              else
++                      nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++              goto done;
++      }
++
+       /*
+        * Read block 1 to test for minix and ext2 superblock
+        */
similarity index 90%
rename from meta/packages/linux/linux-rp_2.6.23+2.6.24-rc0+git.bb
rename to meta/packages/linux/linux-rp_2.6.23+2.6.24-rc1.bb
index 93ffe19b6e9cc7655f9c4c1f2298aa035848a1f8..d73f528892c8d6321bcc6c658c89520d406370ff 100644 (file)
@@ -1,7 +1,5 @@
 require linux-rp.inc
 
-PR = "r1"
-
 DEFAULT_PREFERENCE = "-1"
 
 # Handy URLs
@@ -16,16 +14,16 @@ DEFAULT_PREFERENCE = "-1"
 # Patches submitted upstream are towards top of this list 
 # Hacks should clearly named and at the bottom
 SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
-           http://www.kernel.org/pub/linux/kernel/v2.6/snapshots/patch-2.6.23-git9.bz2;patch=1 \
+           http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.24-rc1.bz2;patch=1 \
            ${RPSRC}/lzo_crypto-r2.patch;patch=1 \
            ${RPSRC}/lzo_jffs2_sysfs-r1.patch;patch=1 \
-           ${RPSRC}/hx2750_base-r30.patch;patch=1 \
+           file://hx2750_base-r31.patch;patch=1 \
            ${RPSRC}/hx2750_bl-r9.patch;patch=1 \
            ${RPSRC}/hx2750_pcmcia-r3.patch;patch=1 \
            ${RPSRC}/pxa_keys-r8.patch;patch=1 \
-           ${RPSRC}/tsc2101-r16.patch;patch=1 \
+#          ${RPSRC}/tsc2101-r16.patch;patch=1 \
            ${RPSRC}/hx2750_test1-r7.patch;patch=1 \
-           ${RPSRC}/input_power-r9.patch;patch=1 \
+#          ${RPSRC}/input_power-r9.patch;patch=1 \
            ${RPSRC}/pxa25x_cpufreq-r2.patch;patch=1 \
            ${RPSRC}/sharpsl_pm_fixes1-r0.patch;patch=1 \
            ${RPSRC}/pm_changes-r1.patch;patch=1 \
@@ -33,14 +31,13 @@ SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
            ${RPSRC}/usb_pxa27x_udc-r7.patch;patch=1 \
            ${RPSRC}/locomo_kbd_tweak-r1.patch;patch=1 \
            ${RPSRC}/poodle_pm-r5.patch;patch=1 \
-           ${RPSRC}/pxa27x_overlay-r7.patch;patch=1 \
+           file://pxa27x_overlay-r8.patch;patch=1 \
            ${RPSRC}/w100_extaccel-r1.patch;patch=1 \
            ${RPSRC}/w100_extmem-r1.patch;patch=1 \
            file://w100fb-unused-var.patch;patch=1 \
            file://hostap-monitor-mode.patch;patch=1 \
            file://serial-add-support-for-non-standard-xtals-to-16c950-driver.patch;patch=1 \
            ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \
-           ${RPSRC}/logo_oz-r2.patch.bz2;patch=1;status=unmergable \
            ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \
            ${RPSRC}/mmcsd_large_cards-r1.patch;patch=1;status=hack \
            file://mmcsd_no_scr_check-r2.patch;patch=1 \
@@ -49,9 +46,8 @@ SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
            ${RPSRC}/corgi_rearrange_lcd-r0.patch;patch=1 \
            file://pxa-serial-hack.patch;patch=1;status=hack \
            file://connectplus-remove-ide-HACK.patch;patch=1;status=hack \
-           file://squashfs3.0-2.6.15.patch;patch=1;status=external \
-           file://uvesafb-0.1-rc3-2.6.22.patch;patch=1;status=external \
-#           file://htcuni.patch;patch=1 \
+#          file://squashfs3.2-2.6.20-r0.patch;patch=1;status=external \
+#          file://htcuni.patch;patch=1 \
            file://binutils-buildid-arm.patch;patch=1 \
            file://defconfig-c7x0 \
            file://defconfig-hx2000 \